MediaProcessors
comm.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017, 2018 Rafael Antoniello
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of copyright holders nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
35 #include "comm.h"
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <ctype.h>
44 
45 #include "log.h"
46 #include "stat_codes.h"
47 #include "check_utils.h"
48 #include "llist.h"
49 #include "uri_parser.h"
50 
51 /* **** Definitions **** */
52 
56 #define TAG_IS(TAG) (strcmp(tag, TAG)== 0)
57 
62 typedef struct comm_module_ctx_s {
70  pthread_mutex_t module_api_mutex;
79 
80 /* **** Prototypes **** */
81 
82 static int register_comm_if(const comm_if_t *comm_if, log_ctx_t *log_ctx);
83 static int unregister_comm_if(const char *scheme, log_ctx_t *log_ctx);
84 static const comm_if_t* get_comm_if_by_scheme(const char *scheme,
85  log_ctx_t *log_ctx);
86 
87 static comm_if_t* comm_if_allocate();
88 static comm_if_t* comm_if_dup(const comm_if_t *comm_if_arg);
89 //static int comm_if_cmp(const comm_if_t* comm_if1, const comm_if_t* comm_if2);
90 static void comm_if_release(comm_if_t **ref_comm_if);
91 
92 static int comm_module_url_probe(const char *url);
93 
94 /* **** Implementations **** */
95 
100 
102 {
103  int ret_code, end_code= STAT_ERROR;
104  LOG_CTX_INIT(log_ctx);
105 
106  /* Check module initialization */
107  if(comm_module_ctx!= NULL) {
108  LOGE("'COMM' module already initialized\n");
109  return STAT_ERROR;
110  }
111 
112  comm_module_ctx= (comm_module_ctx_t*)calloc(1, sizeof(comm_module_ctx_t));
113  CHECK_DO(comm_module_ctx!= NULL, goto end);
114 
115  /* **** Initialize context **** */
116 
117  ret_code= pthread_mutex_init(&comm_module_ctx->module_api_mutex, NULL);
118  CHECK_DO(ret_code== 0, goto end);
119 
120  comm_module_ctx->comm_if_llist= NULL;
121 
122  end_code= STAT_SUCCESS;
123 end:
124  if(end_code!= STAT_SUCCESS)
126  return STAT_SUCCESS;
127 }
128 
130 {
131  LOG_CTX_INIT(NULL);
132 
133  /* Check module initialization */
134  if(comm_module_ctx== NULL) {
135  LOGE("'COMM' module must be initialized previously\n");
136  return;
137  }
138 
139  /* Module's API mutual exclusion lock */
140  ASSERT(pthread_mutex_destroy(&comm_module_ctx->module_api_mutex)== 0);
141 
142  /* List of supported/registered communication protocols */
143  LLIST_RELEASE(&comm_module_ctx->comm_if_llist, comm_if_release, comm_if_t);
144 
145  /* Release module's context structure */
146  free(comm_module_ctx);
147  comm_module_ctx= NULL;
148 }
149 
150 int comm_module_opt(const char *tag, ...)
151 {
152  va_list arg;
153  int end_code= STAT_ERROR;
154  LOG_CTX_INIT(NULL);
155 
156  /* Check arguments */
157  if(comm_module_ctx== NULL) {
158  LOGE("'COMM' module should be initialized previously\n");
159  return STAT_ERROR;
160  }
161  CHECK_DO(tag!= NULL, return STAT_ERROR);
162 
163  va_start(arg, tag);
164 
165  /* Lock module API critical section */
166  ASSERT(pthread_mutex_lock(&comm_module_ctx->module_api_mutex)== 0);
167 
168  if(TAG_IS("COMM_REGISTER_PROTO")) {
169  end_code= register_comm_if(va_arg(arg, comm_if_t*), LOG_CTX_GET());
170  } else if (TAG_IS("COMM_UNREGISTER_PROTO")) {
171  end_code= unregister_comm_if(va_arg(arg, const char*), LOG_CTX_GET());
172  } else {
173  LOGE("Unknown option\n");
174  end_code= STAT_ENOTFOUND;
175  }
176 
177  ASSERT(pthread_mutex_unlock(&comm_module_ctx->module_api_mutex)== 0);
178  va_end(arg);
179  return end_code;
180 }
181 
182 comm_ctx_t* comm_open(const char *url, const char *local_url,
183  comm_mode_t comm_mode, log_ctx_t *log_ctx, ...)
184 {
185  va_list arg;
186  const comm_if_t *comm_if;
187  int ret_code, end_code= STAT_ERROR;
188  char *uri_scheme= NULL;
189  size_t uri_scheme_size= 0;
190  comm_ctx_t* (*open)(const char*, const char*, comm_mode_t, log_ctx_t*,
191  va_list)= NULL;
192  comm_ctx_t *comm_ctx= NULL;
193  LOG_CTX_INIT(NULL);
194 
195  /* Check arguments */
196  CHECK_DO(comm_module_ctx!= NULL, return NULL); // module!
197  CHECK_DO(url!= NULL && strlen(url)> 0, return NULL);
198  // argument 'local_url' is allowed to be NULL in certain implementations
199  // (e.g. as "binding" is not needed in certain protocol-stacks)
200  CHECK_DO(comm_mode< COMM_MODE_MAX, return NULL);
201  // argument 'log_ctx' is allowed to be NULL
202 
203  va_start(arg, log_ctx);
204 
205  /* Set LOG module context */
206  LOG_CTX_SET(log_ctx);
207 
208  /* Get protocol interface by scheme */
209  uri_scheme= uri_parser_get_uri_part(url, SCHEME);
210  if(uri_scheme== NULL || (uri_scheme_size= strlen(uri_scheme))<= 0) {
211  end_code= STAT_ENOPROTOOPT;
212  goto end;
213  }
214  ASSERT(pthread_mutex_lock(&comm_module_ctx->module_api_mutex)== 0);
215  comm_if= get_comm_if_by_scheme(uri_scheme, LOG_CTX_GET());
216  ASSERT(pthread_mutex_unlock(&comm_module_ctx->module_api_mutex)== 0);
217  CHECK_DO(comm_if!= NULL, goto end);
218 
219  /* Check mandatory call-backs existence */
220  CHECK_DO((open= comm_if->open)!= NULL, goto end);
221  CHECK_DO(comm_if->close!= NULL, goto end);
222 
223  /* Open (allocate) the specific communication protocol instance */
224  comm_ctx= open(url, local_url, comm_mode, LOG_CTX_GET(), arg);
225  CHECK_DO(comm_ctx!= NULL, goto end);
226 
227  /* **** Initialize context structure **** */
228 
229  /* Communication interface structure prototype */
230  comm_ctx->comm_if= comm_if;
231 
232  /* Module instance API mutual exclusion lock */
233  ret_code= pthread_mutex_init(&comm_ctx->api_mutex, NULL);
234  CHECK_DO(ret_code== 0, goto end);
235 
236  /* External LOG module context structure instance */
237  comm_ctx->log_ctx= LOG_CTX_GET();
238 
239  /* Module instance mode */
240  comm_ctx->comm_mode= comm_mode;
241 
242  /* Local URL */
243  if(local_url!= NULL) {
244  comm_ctx->local_url= strdup(local_url);
245  CHECK_DO(comm_ctx->local_url!= NULL, goto end);
246  }
247 
248  /* Input/output URL */
249  comm_ctx->url= strdup(url);
250  CHECK_DO(comm_ctx->url!= NULL, goto end);
251 
252  end_code= STAT_SUCCESS;
253 end:
254  va_end(arg);
255  if(uri_scheme!= NULL) {
256  free(uri_scheme);
257  uri_scheme= NULL;
258  }
259  if(end_code!= STAT_SUCCESS)
260  comm_close(&comm_ctx);
261  return comm_ctx;
262 }
263 
264 void comm_close(comm_ctx_t **ref_comm_ctx)
265 {
266  comm_ctx_t *comm_ctx;
267  const comm_if_t *comm_if;
268  LOG_CTX_INIT(NULL);
269 
270  if(ref_comm_ctx== NULL || (comm_ctx= *ref_comm_ctx)== NULL)
271  return;
272 
273  comm_if= comm_ctx->comm_if;
274  ASSERT(comm_if!= NULL && comm_if->close!= NULL);
275 
276  ASSERT(pthread_mutex_destroy(&comm_ctx->api_mutex)== 0);
277 
278  if(comm_ctx->local_url!= NULL) {
279  free(comm_ctx->local_url);
280  comm_ctx->local_url= NULL;
281  }
282 
283  if(comm_ctx->url!= NULL){
284  free(comm_ctx->url);
285  comm_ctx->url= NULL;
286  }
287 
288  /* Close the specific module instance */
289  if(comm_if!= NULL && comm_if->close!= NULL)
290  comm_if->close(ref_comm_ctx);
291 }
292 
293 int comm_send(comm_ctx_t *comm_ctx, const void *buf, size_t count,
294  struct timeval *timeout)
295 {
296  int ret_code;
297  LOG_CTX_INIT(NULL);
298 
299  /* Check arguments */
300  CHECK_DO(comm_ctx!= NULL, return STAT_ERROR);
301  CHECK_DO(buf!= NULL, return STAT_ERROR);
302  CHECK_DO(count> 0, return STAT_ERROR);
303  // timeout NULL means indefinitely wait
304 
305  LOG_CTX_SET(comm_ctx->log_ctx);
306 
307  CHECK_DO(comm_ctx->comm_if!= NULL, return STAT_ERROR);
308 
309  if(comm_ctx->comm_mode!= COMM_MODE_OPUT || comm_ctx->comm_if->send== NULL) {
310  LOGE("Communication interface does not implement 'send()' function.");
311  return STAT_ERROR;
312  }
313  pthread_mutex_lock(&comm_ctx->api_mutex);
314  ret_code= comm_ctx->comm_if->send(comm_ctx, buf, count, timeout);
315  pthread_mutex_unlock(&comm_ctx->api_mutex);
316  return ret_code;
317 }
318 
319 int comm_recv(comm_ctx_t *comm_ctx, void** ref_buf, size_t *ref_count,
320  char **ref_from, struct timeval* timeout)
321 {
322  int ret_code;
323  LOG_CTX_INIT(NULL);
324 
325  /* Check arguments */
326  CHECK_DO(comm_ctx!= NULL, return STAT_ERROR);
327  CHECK_DO(ref_buf!= NULL, return STAT_ERROR);
328  CHECK_DO(ref_count!= NULL, return STAT_ERROR);
329  // argument 'ref_from' is allowed to be NULL
330  // timeout NULL means indefinitely wait
331 
332  LOG_CTX_SET(comm_ctx->log_ctx);
333 
334  *ref_buf= NULL;
335  *ref_count= 0;
336  if(ref_from!= NULL)
337  *ref_from= NULL;
338 
339  CHECK_DO(comm_ctx->comm_if!= NULL, return STAT_ERROR);
340 
341  if(comm_ctx->comm_mode!= COMM_MODE_IPUT || comm_ctx->comm_if->recv== NULL) {
342  LOGE("Communication interface does not implement 'recv()' function.");
343  return STAT_ERROR;
344  }
345  pthread_mutex_lock(&comm_ctx->api_mutex);
346  ret_code= comm_ctx->comm_if->recv(comm_ctx, ref_buf, ref_count, ref_from,
347  timeout);
348  pthread_mutex_unlock(&comm_ctx->api_mutex);
349  return ret_code;
350 }
351 
352 int comm_unblock(comm_ctx_t* comm_ctx)
353 {
354  LOG_CTX_INIT(NULL);
355 
356  /* Check arguments */
357  CHECK_DO(comm_ctx!= NULL, return STAT_ERROR);
358 
359  LOG_CTX_SET(comm_ctx->log_ctx);
360 
361  CHECK_DO(comm_ctx->comm_if!= NULL, return STAT_ERROR);
362 
363  if(comm_ctx->comm_if->unblock) {
364  /* NEVER do the following (as we are unblocking and another thread may
365  * have the MUTEX):
366  */
367  //pthread_mutex_lock(&comm_ctx->api_mutex);
368  comm_ctx->comm_if->unblock(comm_ctx);
369  //pthread_mutex_unlock(&comm_ctx->api_mutex);
370  }
371  return STAT_SUCCESS;
372 }
373 
374 int comm_open_external(pthread_mutex_t *comm_ctx_mutex_external,
375  const char *url, const char *local_url, comm_mode_t comm_mode,
376  log_ctx_t *log_ctx, comm_ctx_t **ref_comm_ctx, ...)
377 {
378  int ret_code, end_code= STAT_ENOPROTOOPT;
379  comm_ctx_t *comm_ctx= NULL;
380  LOG_CTX_INIT(log_ctx);
381 
382  /* Check arguments */
383  CHECK_DO(comm_module_ctx!= NULL, return STAT_ERROR);
384  CHECK_DO(comm_ctx_mutex_external!= NULL, return STAT_ERROR);
385  CHECK_DO(url!= NULL && strlen(url)> 0, return STAT_ERROR);
386  // argument 'local_url' is allowed to be NULL in certain implementations
387  // (e.g. as "binding" is not needed in certain protocol-stacks)
388  CHECK_DO(comm_mode< COMM_MODE_MAX, return STAT_ERROR);
389  // argument 'log_ctx' is allowed to be NULL
390  CHECK_DO(ref_comm_ctx!= NULL, return STAT_ERROR);
391 
392  /* Test if new URL is supported */
393  if((ret_code= comm_module_url_probe(url))!= STAT_SUCCESS) {
394  end_code= ret_code;
395  goto end;
396  }
397 
398  /* Open module instance */
399  comm_ctx= comm_open(url, local_url, comm_mode, LOG_CTX_GET());
400  if(comm_ctx== NULL)
401  goto end;
402 
403  /* Open succeed, update external COMM module reference.
404  * Always treat external reference within given critical section.
405  */
406  ASSERT(pthread_mutex_lock(comm_ctx_mutex_external)== 0);
407  if(*ref_comm_ctx!= NULL) {
408  LOGE("Trying to open an already opened communication interface\n");
409  end_code= STAT_ECONFLICT;
410  } else {
411  *ref_comm_ctx= comm_ctx;
412  comm_ctx= NULL; // Avoid double referencing
413  end_code= STAT_SUCCESS;
414  }
415  ASSERT(pthread_mutex_unlock(comm_ctx_mutex_external)== 0);
416 end:
417  if(comm_ctx!= NULL)
418  comm_close_external(comm_ctx_mutex_external, &comm_ctx, LOG_CTX_GET());
419  return end_code;
420 }
421 
422 void comm_close_external(pthread_mutex_t *comm_ctx_mutex_external,
423  comm_ctx_t **ref_comm_ctx, log_ctx_t *log_ctx)
424 {
425  LOG_CTX_INIT(log_ctx);
426 
427  /* Check arguments */
428  CHECK_DO(comm_module_ctx!= NULL, return);
429  CHECK_DO(comm_ctx_mutex_external!= NULL, return);
430  CHECK_DO(ref_comm_ctx!= NULL, return);
431 
432  /* Firstly, unlock module outside critical section to avoid deadlocks */
433  if(*ref_comm_ctx!= NULL)
434  comm_unblock(*ref_comm_ctx);
435 
436  /* Close module instance */
437  ASSERT(pthread_mutex_lock(comm_ctx_mutex_external)== 0);
438  comm_close(ref_comm_ctx);
439  *ref_comm_ctx= NULL; // redundant; for the sake of clarification
440  ASSERT(pthread_mutex_unlock(comm_ctx_mutex_external)== 0);
441  return;
442 }
443 
444 int comm_reset_external(pthread_mutex_t *comm_ctx_mutex_external,
445  const char *new_url, const char *local_url, comm_mode_t comm_mode,
446  log_ctx_t *log_ctx, comm_ctx_t **ref_comm_ctx_curr, ...)
447 {
448  char *p_curr_url= NULL; // Do not release
449  LOG_CTX_INIT(log_ctx);
450 
451  /* Check arguments */
452  CHECK_DO(comm_module_ctx!= NULL, return STAT_ERROR);
453  CHECK_DO(comm_ctx_mutex_external!= NULL, return STAT_ERROR);
454  // argument 'new_url' is allowed to be NULL
455  // argument 'local_url' is allowed to be NULL in certain implementations
456  // (e.g. as "binding" is not needed in certain protocol-stacks)
457  CHECK_DO(comm_mode< COMM_MODE_MAX, return STAT_ERROR);
458  // argument 'log_ctx' is allowed to be NULL
459  CHECK_DO(ref_comm_ctx_curr!= NULL, return STAT_ERROR);
460 
461  /* Check if URL has changed */
462  p_curr_url= (*ref_comm_ctx_curr)!= NULL? (*ref_comm_ctx_curr)->url: NULL;
463  if(new_url!= NULL && p_curr_url!= NULL && strcmp(new_url, p_curr_url)== 0)
464  return STAT_NOTMODIFIED;
465 
466  /* Special case: requesting to close interface */
467  if(new_url== NULL || (new_url!= NULL && strcmp(new_url, "")== 0)) {
468  comm_close_external(comm_ctx_mutex_external, ref_comm_ctx_curr,
469  LOG_CTX_GET());
470  return STAT_SUCCESS;
471  }
472 
473  /* **** At this point we assume we have a new valid URL **** */
474 
475  /* Close previous COMM module instance and open new one */
476  comm_close_external(comm_ctx_mutex_external, ref_comm_ctx_curr,
477  LOG_CTX_GET());
478  return comm_open_external(comm_ctx_mutex_external, new_url, local_url,
479  comm_mode, LOG_CTX_GET(), ref_comm_ctx_curr);
480 }
481 
482 int comm_recv_external(pthread_mutex_t *comm_ctx_mutex_external,
483  comm_ctx_t **ref_comm_ctx, void** ref_buf, size_t *ref_count,
484  char **ref_from, struct timeval* timeout, log_ctx_t *log_ctx)
485 {
486  int end_code= STAT_ENODATA;
487  LOG_CTX_INIT(log_ctx);
488 
489  /* Check arguments */
490  CHECK_DO(comm_module_ctx!= NULL, return STAT_ERROR);
491  CHECK_DO(comm_ctx_mutex_external!= NULL, return STAT_ERROR);
492  CHECK_DO(ref_comm_ctx!= NULL, return STAT_ERROR);
493  CHECK_DO(ref_buf!= NULL, return STAT_ERROR);
494  CHECK_DO(ref_count!= NULL, return STAT_ERROR);
495  // argument 'ref_from' is allowed to be NULL
496  // timeout NULL means indefinitely wait
497 
498  ASSERT(pthread_mutex_lock(comm_ctx_mutex_external)== 0);
499  if(*ref_comm_ctx!= NULL) {
500  end_code= comm_recv(*ref_comm_ctx, ref_buf, ref_count, ref_from,
501  timeout);
502  }
503  ASSERT(pthread_mutex_unlock(comm_ctx_mutex_external)== 0);
504  return end_code;
505 }
506 
507 static int register_comm_if(const comm_if_t *comm_if, log_ctx_t *log_ctx)
508 {
509  llist_t *n;
510  int ret_code, end_code= STAT_ERROR;
511  comm_if_t *comm_if_cpy= NULL;
512  LOG_CTX_INIT(log_ctx);
513 
514  /* Check arguments */
515  CHECK_DO(comm_module_ctx!= NULL, return STAT_ERROR);
516  CHECK_DO(comm_if!= NULL, return STAT_ERROR);
517 
518  /* Check that module API critical section is locked */
519  ret_code= pthread_mutex_trylock(&comm_module_ctx->module_api_mutex);
520  CHECK_DO(ret_code== EBUSY, return STAT_ERROR);
521 
522  /* Check if protocol is already register with given "scheme" */
523  for(n= comm_module_ctx->comm_if_llist; n!= NULL; n= n->next) {
524  comm_if_t *comm_if_nth= (comm_if_t*)n->data;
525  CHECK_DO(comm_if_nth!= NULL, continue);
526  if(strcmp(comm_if_nth->scheme, comm_if->scheme)== 0) {
527  end_code= STAT_ECONFLICT;
528  goto end;
529  }
530  }
531 
532  /* Allocate a copy of the protocol interface in the list */
533  comm_if_cpy= comm_if_dup(comm_if);
534  //LOGV("Registering communication protocol with scheme: '%s'\n",
535  // comm_if_cpy->scheme); //comment-me
536  CHECK_DO(comm_if_cpy!= NULL, goto end);
537  ret_code= llist_push(&comm_module_ctx->comm_if_llist, comm_if_cpy);
538  CHECK_DO(ret_code== STAT_SUCCESS, goto end);
539 
540  end_code= STAT_SUCCESS;
541 end:
542  if(end_code!= STAT_SUCCESS)
543  comm_if_release(&comm_if_cpy);
544  return end_code;
545 }
546 
547 static int unregister_comm_if(const char *scheme, log_ctx_t *log_ctx)
548 {
549  llist_t **ref_n;
550  int ret_code;
551  LOG_CTX_INIT(log_ctx);
552 
553  /* Check arguments */
554  CHECK_DO(comm_module_ctx!= NULL, return STAT_ERROR);
555  CHECK_DO(scheme!= NULL, return STAT_ERROR);
556 
557  /* Check that module instance critical section is locked */
558  ret_code= pthread_mutex_trylock(&comm_module_ctx->module_api_mutex);
559  CHECK_DO(ret_code== EBUSY, return STAT_ERROR);
560 
561  for(ref_n= &comm_module_ctx->comm_if_llist; (*ref_n)!= NULL;
562  ref_n= &((*ref_n)->next)) {
563  comm_if_t *comm_if_nth= (comm_if_t*)(*ref_n)->data;
564  CHECK_DO(comm_if_nth!= NULL, continue);
565 
566  if(strcmp(comm_if_nth->scheme, scheme)== 0) { // Node found
567  void *node;
568 
569  node= llist_pop(ref_n);
570  ASSERT(node!= NULL && node== (void*)comm_if_nth);
571 
572  /* Once that node register was popped (and thus not accessible
573  * by any concurrent thread), release corresponding context
574  * structure.
575  */
576  //LOGD("Unregistering communication protocol '%s' succeed\n",
577  // comm_if_nth->scheme); // comment-me
578  comm_if_release(&comm_if_nth);
579  ASSERT(comm_if_nth== NULL);
580  return STAT_SUCCESS;
581  }
582  }
583  return STAT_ENOTFOUND;
584 }
585 
586 static const comm_if_t* get_comm_if_by_scheme(const char *scheme,
587  log_ctx_t *log_ctx)
588 {
589  llist_t *n;
590  int ret_code;
591  LOG_CTX_INIT(log_ctx);
592 
593  /* Check arguments */
594  CHECK_DO(comm_module_ctx!= NULL, return NULL);
595  CHECK_DO(scheme!= NULL && strlen(scheme)> 0, return NULL);
596 
597  /* Check that module instance critical section is locked */
598  ret_code= pthread_mutex_trylock(&comm_module_ctx->module_api_mutex);
599  CHECK_DO(ret_code== EBUSY, return NULL);
600 
601  /* Check if protocol is already register with given "scheme" */
602  for(n= comm_module_ctx->comm_if_llist; n!= NULL; n= n->next) {
603  comm_if_t *comm_if_nth= (comm_if_t*)n->data;
604  CHECK_DO(comm_if_nth!= NULL, continue);
605  if(strcmp(comm_if_nth->scheme, scheme)== 0)
606  return comm_if_nth;
607  }
608  return NULL;
609 }
610 
611 static comm_if_t* comm_if_allocate()
612 {
613  return (comm_if_t*)calloc(1, sizeof(comm_if_t));
614 }
615 
616 static comm_if_t* comm_if_dup(const comm_if_t *comm_if_arg)
617 {
618  int end_code= STAT_ERROR;
619  comm_if_t *comm_if= NULL;
620  LOG_CTX_INIT(NULL);
621 
622  /* Check arguments */
623  CHECK_DO(comm_if_arg!= NULL, return NULL);
624 
625  /* Allocate context structure */
626  comm_if= comm_if_allocate();
627  CHECK_DO(comm_if!= NULL, goto end);
628 
629  /* Copy simple-type members values.
630  * Note that pointers to callback are all supposed to be static values,
631  * for this reason we just copy (not duplicate) the pointer values.
632  */
633  memcpy(comm_if, comm_if_arg, sizeof(comm_if_t));
634 
635  /* **** Duplicate members that use dynamic memory allocations **** */
636 
637  CHECK_DO(comm_if_arg->scheme!= NULL, goto end);
638  comm_if->scheme= strdup(comm_if_arg->scheme);
639  CHECK_DO(comm_if->scheme!= NULL, goto end);
640 
641  end_code= STAT_SUCCESS;
642 end:
643  if(end_code!= STAT_SUCCESS)
644  comm_if_release(&comm_if);
645  return comm_if;
646 }
647 
648 #if 0 // Not used
649 static int comm_if_cmp(const comm_if_t* comm_if1, const comm_if_t* comm_if2)
650 {
651  int ret_value= 1; // means "non-equal"
652  LOG_CTX_INIT(NULL);
653 
654  /* Check arguments */
655  CHECK_DO(comm_if1!= NULL, return 1);
656  CHECK_DO(comm_if2!= NULL, return 1);
657 
658  /* Compare contexts fields */
659  if(strcmp(comm_if1->scheme, comm_if2->scheme)!= 0)
660  goto end;
661  if(comm_if1->open!= comm_if2->open)
662  goto end;
663  if(comm_if1->close!= comm_if2->close)
664  goto end;
665  if(comm_if1->send!= comm_if2->send)
666  goto end;
667  if(comm_if1->recv!= comm_if2->recv)
668  goto end;
669  if(comm_if1->unblock!= comm_if2->unblock)
670  goto end;
671 
672  // Reserved for future use: compare new fields here...
673 
674  ret_value= 0; // contexts are equal
675 end:
676  return ret_value;
677 }
678 #endif
679 
680 static void comm_if_release(comm_if_t **ref_comm_if)
681 {
682  comm_if_t *comm_if;
683 
684  if(ref_comm_if== NULL || (comm_if= *ref_comm_if)== NULL)
685  return;
686 
687  if(comm_if->scheme!= NULL) {
688  free((void*)comm_if->scheme);
689  comm_if->scheme= NULL;
690  }
691 
692  free(comm_if);
693  *ref_comm_if= NULL;
694 }
695 
696 static int comm_module_url_probe(const char *url)
697 {
698  llist_t *n;
699  int end_code= STAT_ENOPROTOOPT;
700  size_t uri_part_size= 0;
701  char *uri_part= NULL;
702  LOG_CTX_INIT(NULL);
703 
704  /* Check arguments */
705  CHECK_DO(url!= NULL, return end_code);
706 
707  if(strlen(url)== 0)
708  goto end;
709 
710  /* Check protocol scheme */
711  uri_part= uri_parser_get_uri_part(url, SCHEME);
712  if(!(uri_part!= NULL && (uri_part_size= strlen(uri_part))> 0))
713  goto end;
714  for(n= comm_module_ctx->comm_if_llist;; n= n->next) {
715  comm_if_t *comm_if_nth;
716  if(n== NULL) {
717  LOGE("Unknown protocol\n");
718  goto end; // end of list; protocol not supported
719  }
720  comm_if_nth= (comm_if_t*)n->data;
721  CHECK_DO(comm_if_nth!= NULL, continue);
722  if(strcmp(comm_if_nth->scheme, uri_part)== 0)
723  break; // scheme found; protocol is supported
724  }
725  free(uri_part);
726  uri_part= NULL;
727 
728  /* Check host-text existence */
729  uri_part= uri_parser_get_uri_part(url, HOSTTEXT);
730  if(!(uri_part!= NULL && (uri_part_size= strlen(uri_part))> 0)) {
731  end_code= STAT_EAFNOSUPPORT_HOSTNAME;
732  goto end;
733  }
734  free(uri_part);
735  uri_part= NULL;
736 
737  /* Check port-text existence */
738  uri_part= uri_parser_get_uri_part(url, PORTTEXT);
739  if(!(uri_part!= NULL && (uri_part_size= strlen(uri_part))> 0)) {
740  end_code= STAT_EAFNOSUPPORT_PORT;
741  goto end;
742  }
743  free(uri_part);
744  uri_part= NULL;
745 
746  end_code= STAT_SUCCESS;
747 end:
748  if(uri_part!= NULL)
749  free(uri_part);
750  return end_code;
751 }
URI parser wrapper.
comm_mode_t comm_mode
Definition: comm.h:95
int comm_module_open(log_ctx_t *log_ctx)
Definition: comm.c:101
Generic communication module.
pthread_mutex_t api_mutex
Definition: comm.h:87
char * url
Definition: comm.h:103
pthread_mutex_t module_api_mutex
Definition: comm.c:70
Definition: llist.h:49
char * local_url
Definition: comm.h:99
struct comm_module_ctx_s comm_module_ctx_t
#define TAG_IS(TAG)
Definition: comm.c:56
General status codes enumeration.
#define CHECK_DO(COND, ACTION)
Definition: check_utils.h:57
#define LLIST_RELEASE(ref_llist_head, node_release_fxn, node_type)
Definition: llist.h:165
llist_t * comm_if_llist
Definition: comm.c:77
log_ctx_t * log_ctx
Definition: comm.h:91
int llist_push(llist_t **ref_llist_head, void *data)
Definition: llist.c:57
Simple linked-list utility implementation.
#define ASSERT(COND)
Definition: check_utils.h:51
void * llist_pop(llist_t **ref_llist_head)
Definition: llist.c:75
static comm_module_ctx_t * comm_module_ctx
Definition: comm.c:99
Definition: log.c:102
enum comm_mode_enum comm_mode_t
int comm_module_opt(const char *tag,...)
Definition: comm.c:150
void comm_module_close()
Definition: comm.c:129
const comm_if_t * comm_if
Definition: comm.h:83
Definition: comm.h:64