UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
messaging.cpp
Go to the documentation of this file.
1
8/*
9 * Copyright (c) 2013-2021 CESNET, z. s. p. o.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, is permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * 3. Neither the name of CESNET nor the names of its contributors may be
24 * used to endorse or promote products derived from this software without
25 * specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
29 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
30 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
31 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#include "config_unix.h"
43#include "config_win32.h"
44#endif
45
46#include "messaging.h"
47
48#include <condition_variable>
49#include <iostream>
50#include <memory>
51#include <mutex>
52#include <unordered_map>
53
54#include "debug.h"
55#include "module.h"
56#include "utils/list.h"
57#include "utils/lock_guard.h"
58
59#define MAX_MESSAGES 100
60#define MAX_MESSAGES_FOR_NOT_EXISTING_RECV 10
61#define MOD_NAME "[messaging] "
62
63using namespace std;
64using namespace ultragrid;
65
66struct response {
67 int status;
68 char text[];
69};
70
71
72namespace {
73struct responder {
74 responder() : received_response(nullptr) {}
75 ~responder() {
76 free_response(received_response);
77 }
78 static void receive_response(void *s, struct response *r) {
79 (*((shared_ptr<responder> *) s))->receive_response_real(r);
80 }
81 void receive_response_real(struct response *r) {
82 unique_lock<mutex> lk(lock);
83 received_response = r;
84 lk.unlock();
85 cv.notify_one();
86 }
87
88 struct response *received_response;
89 condition_variable cv;
90 mutex lock;
91};
92
93struct pair_msg_path {
94 struct message *msg;
95 char path[];
96};
97}
98
99void free_message_for_child(void *m, struct response *r) {
100 struct pair_msg_path *mp = (struct pair_msg_path *) m;
101 free_message(mp->msg, r);
102 free(mp);
103
104}
105
121static struct response *send_message_common(struct module *root, const char *const_path, struct message *msg, bool sync, int timeout_ms, int flags)
122{
127 char *path, *tmp;
128 char *item, *save_ptr;
129 tmp = path = strdup(const_path);
130 struct module *receiver = root;
131 shared_ptr<struct responder> responder;
132
133 if (sync) {
134 msg->send_response = responder::receive_response;
135 responder = shared_ptr<struct responder>(new struct responder());
136 msg->priv_data = new shared_ptr<struct responder>(responder);
137 }
138
139 pthread_mutex_lock(&receiver->lock);
140
141 while ((item = strtok_r(path, ".", &save_ptr))) {
142 path = NULL;
143 struct module *old_receiver = receiver;
144
145 if (strcmp(item, "root") == 0)
146 continue;
147
148 receiver = get_matching_child(receiver, item);
149
150 if (!receiver) {
153 printf("Receiver %s does not exist.\n", const_path);
154 //dump_tree(root, 0);
157 printf("Dropping some old messages for %s (queue full).\n", const_path);
159 new_response(RESPONSE_NOT_FOUND, "Receiver not found"));
160 }
161
162 struct pair_msg_path *saved_message = (struct pair_msg_path *)
163 malloc(sizeof(struct pair_msg_path) + strlen(const_path + (item - tmp)) + 1);
164 saved_message->msg = msg;
165 strcpy(saved_message->path, const_path + (item - tmp));
166
167 simple_linked_list_append(old_receiver->msg_queue_children, saved_message);
168 pthread_mutex_unlock(&old_receiver->lock);
169
170 free(tmp);
171 if (!sync) {
172 return new_response(RESPONSE_ACCEPTED, "(receiver not yet exists)");
173 } else {
174 unique_lock<mutex> lk(responder->lock);
175 if (timeout_ms == -1) {
176 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: infinite wait for "
177 "non-existent recv. Please report!\n");
178 responder->cv.wait(lk, [responder]{return responder->received_response != NULL;});
179 } else {
180 responder->cv.wait_for(lk, std::chrono::milliseconds(timeout_ms), [responder]{return responder->received_response != NULL;});
181 }
182 if (responder->received_response) {
183 struct response *resp = responder->received_response;
184 responder->received_response = NULL;
185 return resp;
186 } else {
187 return new_response(RESPONSE_ACCEPTED, NULL);
188 }
189 }
190 } else {
191 pthread_mutex_unlock(&old_receiver->lock);
192 free_message(msg, NULL);
193 free(tmp);
194 return new_response(RESPONSE_NOT_FOUND, NULL);
195 }
196 }
197 pthread_mutex_lock(&receiver->lock);
198 pthread_mutex_unlock(&old_receiver->lock);
199 }
200
201 free(tmp);
202
203 //pthread_mutex_guard guard(receiver->lock, lock_guard_retain_ownership_t());
204
205 pthread_mutex_lock(&receiver->msg_queue_lock);
206 int size = simple_linked_list_size(receiver->msg_queue);
207 pthread_mutex_unlock(&receiver->msg_queue_lock);
208 if (size >= MAX_MESSAGES) {
209 struct message *m = (struct message *) simple_linked_list_pop(receiver->msg_queue);
210 free_message(m, new_response(RESPONSE_INT_SERV_ERR, "Too many unprocessed messages"));
211 printf("Dropping some messages for %s - queue full.\n", const_path);
212 }
213 pthread_mutex_lock(&receiver->msg_queue_lock);
215 pthread_mutex_unlock(&receiver->msg_queue_lock);
216
217 if (receiver->new_message) {
218 receiver->new_message(receiver);
219 }
220
221 pthread_mutex_unlock(&receiver->lock);
222
223 if (!sync) {
224 return new_response(RESPONSE_ACCEPTED, NULL);
225 } else {
226 unique_lock<mutex> lk(responder->lock);
227 if (timeout_ms == -1) {
228 if (receiver->new_message == NULL) {
229 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: infinite wait for "
230 "module without msg notifier. Please report!\n");
231 }
232 responder->cv.wait(lk, [responder]{return responder->received_response != NULL;});
233 } else {
234 responder->cv.wait_for(lk, std::chrono::milliseconds(timeout_ms), [responder]{return responder->received_response != NULL;});
235 }
236 if (responder->received_response) {
237 struct response *resp = responder->received_response;
238 responder->received_response = NULL;
239 return resp;
240 } else {
241 return new_response(RESPONSE_ACCEPTED, NULL);
242 }
243 }
244}
245
249struct response *send_message(struct module *root, const char *const_path, struct message *msg)
250{
251 return send_message_common(root, const_path, msg, false, 0, 0);
252}
253
257struct response *send_message_sync(struct module *root, const char *const_path, struct message *msg, int timeout_ms, int flags)
258{
259 return send_message_common(root, const_path, msg, true, timeout_ms, flags);
260}
261
266{
267 pthread_mutex_guard guard(node->lock);
268
269 for(void *it = simple_linked_list_it_init(node->msg_queue_children); it != NULL; ) {
270 struct pair_msg_path *msg = (struct pair_msg_path *) simple_linked_list_it_next(&it);
271 struct module *receiver = get_matching_child(node, msg->path);
272 if (receiver) {
273 struct response *resp = send_message_to_receiver(receiver, msg->msg);
274 free_response(resp);
276 free(msg);
277 // reinit iterator
279 }
280 }
281}
282
283void module_store_message(struct module *node, struct message *m)
284{
287}
288
289struct response *send_message_to_receiver(struct module *receiver, struct message *msg)
290{
291 pthread_mutex_lock(&receiver->msg_queue_lock);
293 pthread_mutex_unlock(&receiver->msg_queue_lock);
294
295 pthread_mutex_guard guard(receiver->lock);
296 if (receiver->new_message) {
297 receiver->new_message(receiver);
298 }
299
300 return new_response(RESPONSE_ACCEPTED, NULL);
301}
302
303struct message *new_message(size_t len)
304{
305 assert(len >= sizeof(struct message));
306
307 struct message *ret = (struct message *)
308 calloc(1, len);
309
310 return ret;
311}
312
318void free_message(struct message *msg, struct response *r)
319{
320 if (!msg) {
321 return;
322 }
323
324 if (r) {
325 if (msg->send_response) {
326 msg->send_response(msg->priv_data, r);
327 } else {
328 free_response(r);
329 }
330 }
331
332 if (msg->data_deleter) {
333 msg->data_deleter(msg);
334 }
335
336 if (msg->priv_data) {
337 delete (shared_ptr<struct responder> *) msg->priv_data;
338 }
339
340 free(msg);
341}
342
349struct response *new_response(int status, const char *text)
350{
351 struct response *resp = (struct response *) malloc(sizeof(struct response) + (text ? strlen(text) : 0) + 1);
352 resp->status = status;
353 if (text) {
354 strcpy(resp->text, text);
355 } else {
356 resp->text[0] = '\0';
357 }
358 return resp;
359}
360
361void free_response(struct response *r) {
362 free(r);
363}
364
366 return r->status;
367}
368
369const char *response_get_text(struct response *r) {
370 return r->text;
371}
372
374{
375 const static unordered_map<int, const char *> mapping = {
376 { RESPONSE_OK, "OK" },
377 { RESPONSE_ACCEPTED, "Accepted" },
378 { RESPONSE_NO_CONTENT, "No Content" },
379 { RESPONSE_BAD_REQUEST, "Bad Request" },
380 { RESPONSE_NOT_FOUND, "Not Found" },
381 { RESPONSE_REQ_TIMEOUT, "Request Timeout" },
382 { RESPONSE_INT_SERV_ERR, "Internal Server Error" },
383 { RESPONSE_NOT_IMPL, "Not Implemented" },
384 };
385
386 auto it = mapping.find(status);
387 if (it != mapping.end()) {
388 return it->second;
389 }
390
391 return NULL;
392}
393
394struct message *check_message(struct module *mod)
395{
397
398 if(simple_linked_list_size(mod->msg_queue) > 0) {
399 return (struct message *) simple_linked_list_pop(mod->msg_queue);
400 } else {
401 return NULL;
402 }
403}
404
int void size_t * len
const char unsigned int flags
static const struct codec_param mapping[AC_COUNT]
Definition libavcodec.c:87
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
struct module * get_matching_child(struct module *node, const char *const_path)
Definition module.c:300
void simple_linked_list_append(struct simple_linked_list *l, void *data)
Definition list.cpp:68
void * simple_linked_list_it_next(void **i)
Definition list.cpp:119
bool simple_linked_list_remove(struct simple_linked_list *l, void *item)
Definition list.cpp:144
int simple_linked_list_size(struct simple_linked_list *l)
Definition list.cpp:93
void * simple_linked_list_pop(struct simple_linked_list *l)
Definition list.cpp:82
void * simple_linked_list_it_init(struct simple_linked_list *l)
Definition list.cpp:108
void free_message(struct message *msg, struct response *r)
#define MAX_MESSAGES
Definition messaging.cpp:59
struct response * new_response(int status, const char *text)
struct response * send_message_sync(struct module *root, const char *const_path, struct message *msg, int timeout_ms, int flags)
Sends message without waiting for response.
void module_store_message(struct module *node, struct message *m)
void free_message_for_child(void *m, struct response *r)
Definition messaging.cpp:99
int response_get_status(struct response *r)
struct response * send_message_to_receiver(struct module *receiver, struct message *msg)
struct response * send_message(struct module *root, const char *const_path, struct message *msg)
Sends message without waiting for response.
struct message * new_message(size_t len)
static struct response * send_message_common(struct module *root, const char *const_path, struct message *msg, bool sync, int timeout_ms, int flags)
struct message * check_message(struct module *mod)
void free_response(struct response *r)
#define MOD_NAME
Definition messaging.cpp:61
const char * response_status_to_text(int status)
const char * response_get_text(struct response *r)
void module_check_undelivered_messages(struct module *node)
Sends message with waiting for response.
#define MAX_MESSAGES_FOR_NOT_EXISTING_RECV
Definition messaging.cpp:60
#define SEND_MESSAGE_FLAG_QUIET
do not print error messages on console (recv not found/queue full)
Definition messaging.h:171
#define RESPONSE_NO_CONTENT
Definition messaging.h:59
#define RESPONSE_NOT_IMPL
Definition messaging.h:64
#define RESPONSE_REQ_TIMEOUT
Definition messaging.h:62
#define RESPONSE_OK
Definition messaging.h:57
#define SEND_MESSAGE_FLAG_NO_STORE
if receiver doesn't exist, doesn't store it and retur 404 instead
Definition messaging.h:172
#define RESPONSE_BAD_REQUEST
Definition messaging.h:60
#define RESPONSE_INT_SERV_ERR
Definition messaging.h:63
#define RESPONSE_ACCEPTED
Definition messaging.h:58
#define RESPONSE_NOT_FOUND
Definition messaging.h:61
class generic_lock_guard< pthread_mutex_t, pthread_mutex_lock, pthread_mutex_unlock > pthread_mutex_guard
Definition lock_guard.h:43
struct msghdr msg
Definition hd-rum.c:27
struct simple_linked_list * msg_queue
Definition module.h:122
notify_t new_message
if set, notifies module that new message is in queue, receiver lock is hold during the call
Definition module.h:119
pthread_mutex_t msg_queue_lock
Definition module.h:121
pthread_mutex_t lock
Definition module.h:114
struct simple_linked_list * msg_queue_children
messages for childern that were not delivered
Definition module.h:124
char text[]
Definition messaging.cpp:68