Libtrap: Internal development docs  1.16.1
trap.c
Go to the documentation of this file.
1 /**
2  * \file trap.c
3  * \brief TRAP library base.
4  * \author Vaclav Bartos <ibartosv@fit.vutbr.cz>
5  * \author Tomas Cejka <cejkat@cesnet.cz>
6  * \author Jan Neuzil <neuzija1@fit.cvut.cz>
7  * \author Marek Svepes <svepemar@fit.cvut.cz>
8  * \author Tomas Jansky <janskto1@fit.cvut.cz>
9  * \author Jaroslav Hlavac <hlavaj20@fit.cvut.cz>
10  * \date 2013 - 2017
11  */
12 /*
13  * Copyright (C) 2013-2017 CESNET
14  *
15  * LICENSE TERMS
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  * notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in
24  * the documentation and/or other materials provided with the
25  * distribution.
26  * 3. Neither the name of the Company nor the names of its contributors
27  * may be used to endorse or promote products derived from this
28  * software without specific prior written permission.
29  *
30  * ALTERNATIVELY, provided that this notice is retained in full, this
31  * product may be distributed under the terms of the GNU General Public
32  * License (GPL) version 2 or later, in which case the provisions
33  * of the GPL apply INSTEAD OF those given above.
34  *
35  * This software is provided ``as is'', and any express or implied
36  * warranties, including, but not limited to, the implied warranties of
37  * merchantability and fitness for a particular purpose are disclaimed.
38  * In no event shall the company or contributors be liable for any
39  * direct, indirect, incidental, special, exemplary, or consequential
40  * damages (including, but not limited to, procurement of substitute
41  * goods or services; loss of use, data, or profits; or business
42  * interruption) however caused and on any theory of liability, whether
43  * in contract, strict liability, or tort (including negligence or
44  * otherwise) arising in any way out of the use of this software, even
45  * if advised of the possibility of such damage.
46  *
47  */
48 #define _GNU_SOURCE
49 #include <config.h>
50 #include <ctype.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <getopt.h>
56 #include <pthread.h>
57 #include <signal.h>
58 #include <semaphore.h>
59 #include <unistd.h>
60 #include <errno.h>
61 #include <sys/socket.h>
62 #include <arpa/inet.h>
63 #include <sys/ioctl.h>
64 #include <stdint.h>
65 #include <inttypes.h>
66 #include <assert.h>
67 #include <poll.h>
68 
69 #include "../include/libtrap/trap.h"
70 #include "trap_internal.h"
71 #include "trap_error.h"
72 #include "trap_ifc.h"
73 #include "ifc_dummy.h"
74 #include "ifc_tcpip.h"
75 #include "ifc_tcpip_internal.h"
76 #include "ifc_file.h"
77 
78 #if HAVE_OPENSSL
79 # include "ifc_tls.h"
80 # include "ifc_tls_internal.h"
81 # include <openssl/ssl.h>
82 # include <openssl/err.h>
83 #endif
84 
85 /**
86  * Version of libtrap
87  *
88  * Used from config.h that is generated by the configure script.
89  */
90 const char trap_version[] __attribute__((used)) = PACKAGE_VERSION;
91 
92 /**
93  * Git revision of libtrap
94  *
95  * Used from config.h that is generated by the configure script.
96  */
97 const char trap_git_version[] __attribute__((used)) = GIT_VERSION;
98 
99 /**
100  * Print Trap IFC help in trap_print_help() if non-zero.
101  */
102 char trap_help_spec = 0;
103 
104 /**
105  * NULL terminated array of supported IFC types.
106  */
111 #if HAVE_OPENSSL
113 #endif
117  0
118 };
119 
121 
122 /* for backwards compatibility */
124 /* for backwards compatibility */
125 const char *trap_last_error_msg = NULL;
126 
128 
129 /** String representation of interface direction (Input/Output) */
130 #define ifcdir2str(type) (((type) == TRAPIFC_OUTPUT) ? "Output" : "Input")
131 
132 static inline char *get_param_by_delimiter(const char *source, char **dest, const char delimiter);
133 void *service_thread_routine(void *arg);
134 
135 /**
136  * Look for environment variables and change the change the related global variables.
137  */
139 {
140  int size;
141  /* According to man, getenv is not secured in some cases.
142  * 1) effective ID does not match real ID */
143  if ((getuid() != geteuid()) || (getgid() != getegid())) {
144  return;
145  }
146  /* 2) effective capability bit was set on the executable file.
147  * TODO
148  */
149 
150  /* 3) process has a nonempty permitted capability set.
151  * TODO
152  */
153 
154  /*
155  * TRAP_SOCKET_DIR env.var. to redefine path to sockets,
156  * trap_default_socket_path_format is set.
157  */
158  const char *e = getenv("TRAP_SOCKET_DIR");
159  if (e != NULL) {
160  size = snprintf(NULL, 0, "%s%s", e, DEFAULT_SOCKET_FORMAT);
161  trap_default_socket_path_format = malloc(size + 1);
163  }
164 
165 #if HAVE_OPENSSL
166  SSL_load_error_strings();
167  OpenSSL_add_ssl_algorithms();
168 #endif
169 }
170 
172 {
176  }
177 
178 #if HAVE_OPENSSL
179  EVP_cleanup();
180  ERR_free_strings();
181 #endif
182 }
183 
184 trap_module_info_t *trap_create_module_info(const char *mname, const char *mdesc, int8_t i_ifcs, int8_t o_ifcs, uint16_t param_count)
185 {
186  trap_module_info_t *m = NULL;
187 
188  m = calloc(1, sizeof(trap_module_info_t));
189  if (m != NULL) {
190  m->params = calloc(param_count + 1, sizeof(trap_module_info_parameter_t *));
191  if (m->params == NULL) {
192  free(m);
193  return NULL;
194  }
195  }
196 
197  ALLOCATE_BASIC_INFO_2(m, mname, mdesc, i_ifcs, o_ifcs);
198 
199  /* allocated module_info on success, NULL on error */
200  return m;
201 }
202 
203 int trap_update_module_param(trap_module_info_t *m, uint16_t param_id, char shortopt, const char *longopt, const char *desc, int req_arg, const char *arg_type)
204 {
205  ALLOCATE_PARAM_ITEMS_2(m, param_id, shortopt, longopt, desc, req_arg, arg_type)
206  return 0;
207 }
208 
209 ///////////////////////////////////////////////////////////////////////////////
210 
211 /**
212  * \defgroup buffering Buffering sublayer
213  * @{
214  */
215 
216 /**
217  * \brief Check content of buffer, iterate over message headers
218  * \param [in] buffer start of buffer
219  * \param [in] buffer_size size of buffer
220  * \return 0 on success, number of errors otherwise
221  */
222 int trap_check_buffer_content(void *buffer, uint32_t buffer_size)
223 {
224  uint32_t offset, check_mess_counter = 0;
225  uint16_t *check_mess_header;
226  int errors = 0;
227  void *check_mess_pointer;
228  for (offset = 0, check_mess_header = check_mess_pointer = buffer;
229  ((offset < buffer_size) && (offset < TRAP_IFC_MESSAGEQ_SIZE));) {
230  check_mess_counter++;
231  /* go to next size, skip header + payload */
232  offset += sizeof(*check_mess_header) + (*check_mess_header);
233  check_mess_pointer += sizeof(*check_mess_header) + (*check_mess_header);
234  check_mess_header = (uint16_t *) check_mess_pointer;
235  }
236  if (offset != buffer_size) {
237  VERBOSE(CL_ERROR, "Not enough data or some headers are malformed.");
238  errors++;
239  return errors;
240  }
241  return errors;
242 }
243 
244 /**
245  * Read data from buffer or receive data into buffer if buffer is empty
246  *
247  * \param[in,out] ctx pointer to the private libtrap context data (trap_ctx_init())
248  * \param[in] ifc_idx index of input interface
249  * \param[out] data pointer to received message
250  * \param[out] size size of message
251  * \param[in] timeout TRAP_WAIT | TRAP_NO_WAIT | timeout
252  */
253 static inline int trap_read_from_buffer(trap_ctx_priv_t *ctx, uint32_t ifc_idx, const void **data, uint16_t *size, int timeout)
254 {
255  int result = TRAP_E_TIMEOUT;
256  trap_input_ifc_t *ifc = &ctx->in_ifc_list[ifc_idx];
257 
258  pthread_mutex_lock(&ifc->ifc_mtx);
259  /* Receive new buffer from the input interface if the buffer is empty. */
260  if (ifc->buffer_unread_bytes == 0) {
261  uint32_t buffer_size_tmp = 0;
262 
263  ifc->buffer_pointer = ifc->buffer;
264  result = ifc->recv(ifc->priv, ifc->buffer, &buffer_size_tmp, timeout);
265  DEBUG_BUF(VERBOSE(CL_VERBOSE_LIBRARY, "Received new buffer with size: %" PRIu32 ".", buffer_size_tmp));
266  if (result == TRAP_E_OK) {
267  ifc->buffer_unread_bytes = buffer_size_tmp;
268  __sync_fetch_and_add(&ctx->counter_recv_buffer[ifc_idx], 1);
269 
270 #ifdef BUFFERING_CHECK_HEADERS
271  if (trap_check_buffer_content(ifc->buffer, buffer_size_tmp) != 0) {
272  VERBOSE(CL_ERROR, "Buffer is not valid.");
273  }
274 #endif
275  } else {
276  goto exit;
277  }
278  }
279 
280  if (ifc->buffer_unread_bytes > 0) {
281  /* Get message from buffer. */
282  (*size) = ntohs(*((uint16_t *) ifc->buffer_pointer));
283  (*data) = (ifc->buffer_pointer + sizeof(*size));
284 
285  uint32_t msg_size = (*size) + sizeof(*size);
286  DEBUG_BUF(VERBOSE(CL_VERBOSE_LIBRARY, "Read: %" PRIu64 " header bytes, %" PRIu16 " data bytes. Remaining bytes: %" PRIu32 "", sizeof(*size), *size, ifc->buffer_unread_bytes - msg_size));
287 
288  /* Check whether the buffer data were not malformed. */
289  if (ifc->buffer_unread_bytes < msg_size) {
290  ifc->buffer_unread_bytes = 0;
291  ifc->buffer_pointer = ifc->buffer;
292  VERBOSE(CL_WARNING, "Attempt to read: %" PRIu64 " header bytes, %" PRIu16 " data bytes. However, only %" PRIu32 " bytes remain.", sizeof(*size), *size, ifc->buffer_unread_bytes);
293  } else {
294  /* Move to the next message. */
295  ifc->buffer_unread_bytes -= msg_size;
296  ifc->buffer_pointer += msg_size;
297  }
298 
299  result = TRAP_E_OK;
300  } else {
301  (*size) = 0;
302  }
303 exit:
304  if (result == TRAP_E_OK) {
305  __sync_fetch_and_add(&ctx->counter_recv_message[ifc_idx], 1);
306  if (ifc->client_state == FMT_CHANGED) {
307  ifc->client_state = FMT_OK;
308  result = TRAP_E_FORMAT_CHANGED;
309  }
310  }
311  pthread_mutex_unlock(&ifc->ifc_mtx);
312 
313  return result;
314 }
315 
316 /**
317  * @}
318  */
319 
320 /** Set section for trap_print_help()
321  *
322  * \param [in] level 0 for default info about module, 1 for info about IFC specifier
323  */
324 void trap_set_help_section(int level)
325 {
326  trap_help_spec = level;
327 }
328 
329 /** Initialization function.
330  * Create and initialize all interfaces. This function parses command-line
331  * arguments; it extracts arguments it needs to set up interfaces and returns
332  * the rest (argc and argv are modified).
333  * @param[in,out] argc Pointer to number of command-line arguments.
334  * @param[in,out] argv Command-line arguments.
335  * @param[out] ifc_spec Structure with specification of interface types and
336  * their parameters.
337  * @return Error code (0 on success)
338  */
339 int trap_parse_params(int *argc, char **argv, trap_ifc_spec_t *ifc_spec)
340 {
341  uint32_t i, j, ifc_count = 0;
342  char *ifc_spec_str = NULL;
343  char *ifc_type = NULL;
344  char *p;
345  int rv = TRAP_E_OK;
346 
347  if (ifc_spec == NULL) {
348  VERBOSE(CL_ERROR, "Bad pointer 'ifc_spec' passed to trap_parse_params().");
349  return TRAP_E_BAD_FPARAMS;
350  }
351 
352  /* initialization of ifc_spec */
353  memset(ifc_spec, 0, sizeof(trap_ifc_spec_t));
354 
355  // Look for -h (or --help) parameter
356  for (i = 0; i < *argc; i++) {
357  if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
358  if (i + 1 < *argc && ((strcmp(argv[i + 1], "trap") == 0) || (strcmp(argv[i + 1], "1") == 0))) {
359  trap_help_spec = 1;
360  }
361  // Remove parameter from argv and break
362  for (j = i; j + 1 < *argc; j++) {
363  argv[j] = argv[j + 1];
364  }
365  *argc -= 1;
366  return TRAP_E_HELP;
367  }
368  }
369 
370  // Extract -i parameter (interface specifier)
371  for (i = 0; i < *argc-1; i++) {
372  if (argv[i] && strcmp(argv[i], "-i") == 0) {
373  ifc_spec_str = argv[i+1];
374  // Remove parameters from argv
375  for (j = i; j + 2 < *argc; j++) {
376  argv[j] = argv[j + 2];
377  }
378  *argc -= 2;
379  break;
380  }
381  }
382  if (ifc_spec_str == NULL) {
383  //return trap_errorf(ctx, TRAP_E_BADPARAMS, "Interface specifier (option -i) not found.");
385  trap_last_error_msg = "Interface specifier (option -i) not found.";
386  return TRAP_E_BADPARAMS;
387  }
388 
389  // Extract verbose level parameter (-v, -vv, -vvv)
390  for (i = 0; i < *argc; i++) {
391  // If param matches -v, -vv or -vvv, set verbosity level
392  if (strcmp(argv[i], "-v") == 0) {
394  } else if (strcmp(argv[i], "-vv") == 0) {
396  } else if (strcmp(argv[i], "-vvv") == 0) {
398  } else {
399  continue;
400  }
401  // Remove parameter from argv and break
402  for (j = i; j + 1 < *argc; j++) {
403  argv[j] = argv[j + 1];
404  }
405  *argc -= 1;
406  break;
407  }
408 
409  /* count the number of IFC parameters, the format is:
410  * type1:param1:param1_2,type2:,type3:param3 */
411  p = ifc_spec_str;
412  while (p && *p != '\0') {
413  p = strchr(p, TRAP_IFC_DELIMITER);
414  if (p != NULL && *p == TRAP_IFC_DELIMITER) {
415  p++;
416  }
417  ifc_count++;
418  }
419 
420  ifc_spec->types = calloc(ifc_count + 1, sizeof(*ifc_spec->types));
421  if (ifc_spec->types == NULL) {
422  return TRAP_E_MEMORY;
423  }
424  ifc_spec->params = calloc(ifc_count, sizeof(char *));
425  if (ifc_spec->params == NULL) {
426  free(ifc_spec->types);
427  ifc_spec->types = NULL;
428  return TRAP_E_MEMORY;
429  }
430 
431  p = ifc_spec_str;
432  for (i = 0; i < ifc_count; i++) {
433  /* set IFC type and skip to params */
434  if (p != NULL) {
435  ifc_spec->types[i] = p[0];
436  if (strlen(p) >= 2 && p[1] == TRAP_IFC_PARAM_DELIMITER) {
437  /* there is a param string to parse */
438  p += 2;
439  p = get_param_by_delimiter(p, &ifc_spec->params[i], TRAP_IFC_DELIMITER);
440  } else {
441  /* param was not passed, set an empty one */
442  ifc_spec->params[i] = strdup("");
443  }
444  } else {
445  /* unexpected error, p shouldn't be NULL */
446  VERBOSE(CL_ERROR, "Bad IFC_SPEC '%s'. See -h trap for help.", ifc_spec_str);
447  ifc_spec->params[i] = strdup("");
448  }
449  if (ifc_spec->params[i] == NULL) {
450  VERBOSE(CL_ERROR, "Allocation failed.");
451  rv = TRAP_E_MEMORY;
452  goto clean_on_fail;
453  }
454  }
455 
456  /* check for unsupported IFCs */
457  for (i = 0; ifc_spec->types[i] != 0; ++i) {
458  for (ifc_type = trap_ifc_type_supported; *ifc_type != 0; ++ifc_type) {
459  if (*ifc_type == ifc_spec->types[i]) {
460  break;
461  }
462  }
463  if (*ifc_type == 0) {
464  /* not found */
465  VERBOSE(CL_ERROR, "Unsupported IFC type '%c'.", ifc_spec->types[i]);
466  rv = TRAP_E_BADPARAMS;
467  goto clean_on_fail;
468  }
469  }
470 
473  return TRAP_E_OK;
474 
475 clean_on_fail:
476  for (i = 0; i < ifc_count; i++) {
477  /* set IFC type and skip to params */
478  if (ifc_spec->params[i] != NULL) {
479  free(ifc_spec->params[i]);
480  ifc_spec->params[i] = NULL;
481  }
482  }
483  if (ifc_spec->types != NULL) {
484  free(ifc_spec->types);
485  }
486  if (ifc_spec->params) {
487  free(ifc_spec->params);
488  }
489  memset(ifc_spec, 0, sizeof(trap_ifc_spec_t));
490  return rv;
491 }
492 
493 /** Destructor of trap_ifc_spec_t structure.
494  * @param[in] ifc_spec trap_ifc_spec_t structure to clear.
495  * @return Error code (0 on success)
496  */
498 {
499  int i;
500  if (ifc_spec.types == NULL) {
502  }
503  if (ifc_spec.params != NULL) {
504  for (i = 0; i < strlen(ifc_spec.types); i++) {
505  if (ifc_spec.params[i] != NULL) {
506  free(ifc_spec.params[i]);
507  ifc_spec.params[i] = NULL;
508  }
509  }
510  free(ifc_spec.params);
511  ifc_spec.params = NULL;
512  }
513  free(ifc_spec.types);
515 }
516 
517 void trap_free_ctx_t(trap_ctx_priv_t **ctx);
518 
519 /** Initialization function.
520  * Create and initialize all interfaces.
521  * @param[in] module_info Pointer to struct containing info about the module.
522  * @param[in] ifc_spec Structure with specification of interface types and
523  * their parameters.
524  * @return Error code (0 on success)
525  */
526 int trap_init(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec)
527 {
528  int le;
529  if ((trap_glob_ctx != NULL) && (trap_glob_ctx->initialized != 0)) {
531  }
532  trap_glob_ctx = trap_ctx_init(module_info, ifc_spec);
533  if (trap_glob_ctx == NULL) {
534  return TRAP_E_MEMORY;
535  }
539 
540  trap_finalize();
542 
543  /* restore error message that was lost by finalize&free */
545  trap_last_error = le;
546  return trap_last_error;
547  }
549 }
550 
551 
552 /** Function to terminate module's operation.
553  * This function stops all read/write operations on all interfaces.
554  * Any waiting in trap_recv() and trap_send()_data is interrupted and these
555  * functions return immediately with TRAP_E_TERMINATED.
556  * Any call of trap_recv() or trap_send() after call of this function
557  * returns TRAP_E_TERMINATED.
558  *
559  * This function is used to terminate module's operation (asynchronously), e.g.
560  * in SIGTERM handler.
561  * @return Always TRAP_E_OK (0).
562  */
564 {
566  if (trap_glob_ctx != NULL) {
569  } else {
570  trap_last_error_msg = "No allocated global context.";
571  trap_last_error = ret;
572  }
573  return ret;
574 }
575 
576 
577 
579 {
580  int ret;
582  if (ret != TRAP_E_OK) {
583  if (trap_glob_ctx != NULL) {
586  } else {
587  trap_last_error_msg = "No allocated global context.";
588  trap_last_error = ret;
589  }
590  }
591  return ret;
592 }
593 
594 
595 /**
596  * \brief Get pointer to data stored in buffer (with headers) and mark buffer as clean.
597  *
598  */
599 void trap_get_internal_buffer(trap_ctx_priv_t *ctx, uint16_t ifc_idx, const void **data, uint32_t *size)
600 {
601  (*data) = ctx->in_ifc_list[ifc_idx].buffer;
602  (*size) = ctx->in_ifc_list[ifc_idx].buffer_unread_bytes;
603 
604  /* mark internal buffer as free for next reading */
605  ctx->in_ifc_list[ifc_idx].buffer_pointer = ctx->in_ifc_list[ifc_idx].buffer;
606  ctx->in_ifc_list[ifc_idx].buffer_unread_bytes = 0;
607 }
608 
609 #define SEND_DATA() do { \
610  int res = trap_ctx_send((trap_ctx_t *) trap_glob_ctx, ifcidx, data, size); \
611  if (res != TRAP_E_NOT_INITIALIZED) { \
612  trap_last_error_msg = trap_glob_ctx->trap_last_error_msg; \
613  trap_last_error = trap_glob_ctx->trap_last_error; \
614  } \
615  return res; \
616 } while (0);
617 
618 int trap_send_data(unsigned int ifcidx, const void *data, uint16_t size, int timeout)
619 {
620  trap_glob_ctx->out_ifc_list[ifcidx].datatimeout = timeout;
621  SEND_DATA()
622 }
623 
624 int trap_send(uint32_t ifcidx, const void *data, uint16_t size)
625 {
626  SEND_DATA()
627 }
628 
629 #undef SEND_DATA
630 
631 int trap_recv(uint32_t ifcidx, const void **data, uint16_t *size)
632 {
633  int res;
634  res = trap_ctx_recv((trap_ctx_t *) trap_glob_ctx, ifcidx, data, size);
635  if (res != TRAP_E_NOT_INITIALIZED) {
638  }
639  return res;
640 }
641 
642 
643 /** Set verbosity level.
644  * Verbosity levels are:
645  * - -3 - errors
646  * - -2 - warnings
647  * - -1 - notices (default)
648  * - 0 - verbose
649  * - 1 - more verbose
650  * - 2 - even more verbose
651  *
652  * @param[in] level Desired level of verbosity.
653  */
654 void trap_set_verbose_level(int level)
655 {
656  trap_verbose = level;
657 }
658 
659 /** Get verbosity level.
660  * See trap_set_verbose_level for list of levels.
661  * @return Verbosity level currently set in the library.
662  */
664 {
665  return trap_verbose;
666 }
667 
668 extern char **environ;
669 
670 void trap_json_print_string(char *str)
671 {
672  printf("\"");
673  if (str != NULL) {
674  while (*str != 0) {
675  if (*str == '\n') {
676  printf("\\n");
677  } else if (*str == '\t') {
678  printf(" ");
679  } else {
680  printf("%c", *str);
681  }
682  str++;
683  }
684  }
685  printf("\"");
686 }
687 
688 void trap_convert_module_info_to_json(const trap_module_info_t *info)
689 {
690  int i = 0;
691 
692  printf("{\"name\":");
693  trap_json_print_string(info->name);
694  printf(",\"description\":");
695  trap_json_print_string(info->description);
696  printf(",\"num_ifc_in\":%u,\"num_ifc_out\":%u,\"params\":[",
697  info->num_ifc_in, info->num_ifc_out);
698 
699  while (info->params[i] != NULL) {
700  if (i != 0) {
701  printf(",");
702  }
703  printf("{\"short_opt\":\"%c\",\"long_opt\":", info->params[i]->short_opt);
704  trap_json_print_string(info->params[i]->long_opt);
705  printf(",\"description\":");
706  trap_json_print_string(info->params[i]->description);
707  printf(",\"argument_type\":");
708  trap_json_print_string(info->params[i]->argument_type);
709  printf(",\"mandatory_argument\": %d}", info->params[i]->param_required_argument);
710  i++;
711  }
712  printf("]}\n");
713 }
714 
715 /**
716  * Print helper for formatting text of help.
717  *
718  * \param[in] s String to print (e.g. description).
719  * \param[in] align The number of spaces that should be add after line-break.
720  * \param[in] cut Approximate (minimal) length of string that is printed on the line.
721  * Line-break is added if needed, after the current word.
722  */
723 static void print_aligned(const char *s, uint16_t align, uint16_t cut)
724 {
725  int32_t tmp = 0, rest, written;
726  const char *p = s;
727 
728  rest = strlen(s);
729  if (rest < cut) {
730  printf("%s\n", s);
731  } else {
732  written = 0;
733  while (rest > 0) {
734  /* print alignment spaces */
735  if (p != s) {
736  printf("%*s", align, " ");
737  }
738  /* skip leading spaces of text */
739  while ((*p == ' ' || *p == '\t') && *p != 0) {
740  p++;
741  rest--;
742  }
743  /* find word boundary */
744  if (rest > cut) {
745  for (tmp = cut; tmp > 0; tmp--) {
746  switch (p[tmp]) {
747  case '.':
748  case ',':
749  case ';':
750  /* let this character on the end of line */
751  tmp += 1;
752  goto write;
753  case ' ':
754  case '\t':
755  case '\n':
756  goto write;
757  default:
758  break;
759  }
760  }
761  } else {
762  tmp = cut;
763  }
764 write:
765  if (tmp == 0) {
766  /* failed to find word separator and it is useless
767  * to write 0 chars -> write the whole line */
768  tmp = cut;
769  }
770  written = printf("%.*s\n", tmp, p);
771  rest -= written;
772  p += written - 1;
773  }
774  }
775 }
776 
777 /**
778  * Print helper for formatting multiline text of help.
779  *
780  * Multiline text means that the string contains '\n'.
781  * print_aligned() is used for line breaking.
782  *
783  * \param[in] s String to print (e.g. description).
784  * \param[in] align The number of spaces that should be add after line-break.
785  * \param[in] cut Approximate (minimal) length of string that is printed on the line.
786  * Line-break is added if needed, after the current word.
787  */
788 static void print_aligned_multiline(const char *s, uint16_t align, uint16_t cut)
789 {
790  const char *eol = NULL, *sol = s;
791  int bufsize = 512, linewidth;
792  char *buffer = calloc(1, bufsize);
793  if (buffer == NULL) {
794  VERBOSE(CL_ERROR, "Failed to allocate buffer for printing.");
795  goto failed;
796  }
797  do {
798  eol = strchr(sol, '\n');
799  if (eol == NULL) {
800  /* end of text */
801  linewidth = strlen(sol);
802  } else {
803  linewidth = eol - sol;
804  }
805 
806  if (linewidth >= bufsize) {
807  buffer = realloc(buffer, linewidth + 1);
808  bufsize = linewidth + 1;
809  if (buffer == NULL) {
810  VERBOSE(CL_ERROR, "Failed to allocate buffer for printing.");
811  goto failed;
812  }
813  }
814  strncpy(buffer, sol, linewidth);
815  if (buffer[linewidth - 1] == '\n') {
816  buffer[linewidth - 1] = 0;
817  } else {
818  buffer[linewidth] = 0;
819  }
820  print_aligned(buffer, 0, cut);
821  sol = eol + 1;
822  } while (eol != NULL);
823 
824 failed:
825  free(buffer);
826 }
827 
828 /**
829  * Get size of terminal.
830  *
831  * \return Returns columns of terminal.
832  */
833 static uint16_t get_terminal_width()
834 {
835  struct winsize ws;
836  if (ioctl(1, TIOCGWINSZ, &ws) == 0) {
837  if (ws.ws_col > 0) {
838  return ws.ws_col - 1;
839  } else {
840  return 0;
841  }
842  }
843  return 0;
844 }
845 
846 /**
847  * Get name of this process/module.
848  *
849  * \return Allocated string. If it is not possible to get the name,
850  * "module" is returned.
851  */
852 char *get_module_name(void)
853 {
854  size_t bufsize = 1024, rv;
855  char buffer[bufsize], *p, *ret;
856  FILE *f = fopen("/proc/self/cmdline", "r");
857  if (f == NULL) {
858  /* unknown name */
859  return strdup("module");
860  }
861  rv = fread(buffer, 1, bufsize - 1, f);
862  buffer[rv] = 0;
863  if (rv > 0) {
864  p = buffer;
865  /* skip to the next argument if this one matches regex /^python[23]?/ */
866  ret = strstr(p, "python");
867  if (ret != NULL && ((ret[6] == 0) || (ret[6] == '2') || (ret[6] == '3'))) {
868  p = strchr(p, 0);
869  p += 1;
870  }
871  ret = strrchr(p, '/');
872  if (ret == NULL) {
873  /* '/' was not found, module_name does not contain path */
874  ret = strdup(p);
875  } else {
876  /* skip found '/' */
877  p = ret + 1;
878  /* skip "lt-" prefix of libtool */
879  if (p[0] == 'l' && p[1] == 't' && p[2] == '-') {
880  p += 3;
881  }
882  /* return the result */
883  ret = strdup(p);
884  }
885  } else {
886  /* unknown name */
887  ret = strdup("module");
888  }
889  fclose(f);
890  return ret;
891 }
892 
893 /** Print common TRAP help message.
894  * The help message contains information from module_info and describes common
895  * TRAP command-line parameters.
896  * @param[in] module_info Pointer to struct containing info about the module.
897  */
898 void trap_print_help(const trap_module_info_t *module_info)
899 {
900  char *pager = NULL, *output_format = NULL;
901  const char *temp_env;
902  int pager_fds[2];
903  uint32_t i, written = 0, tmp = 0, cols;
904  pid_t p;
905  uint8_t adit_param = 0, opt_param = 0;
906  uint16_t align_def = 0, align_opt = 0;
907 
908  /* Decide which format of output will be used according to the environment variable */
909  temp_env = getenv("LIBTRAP_OUTPUT_FORMAT");
910  if (temp_env != NULL) {
911  output_format = strdup(temp_env);
912  }
913  if (output_format != NULL) {
914  if (strcmp(output_format, "json") == 0) {
916  free(output_format);
917  return;
918  }
919  }
920  /* output format is useless by now */
921  free(output_format);
922 
923  cols = get_terminal_width();
924  if (cols == 0) {
926  }
927 
928  temp_env = getenv("PAGER");
929  if (temp_env != NULL) {
930  pager = strdup(temp_env);
931  }
932 
933  if ((pager == NULL) || (strcmp(pager, "") == 0)) {
934  goto output;
935  }
936 
937  if (pipe(pager_fds) < 0) {
938  fprintf(stderr, "pipe() failed.");
939  goto output;
940  }
941 
942  p = fork();
943  if (p < 0) {
944  fprintf(stderr, "fork() failed.");
945  goto output;
946  } else if (p == 0) {
947  /* child - pager */
948  close(pager_fds[0]); /* close unused read end!!! important */
949  /* set write end of pipe as stdout for this child process */
950  dup2(pager_fds[1], STDOUT_FILENO);
951  close(pager_fds[1]); /* important */
952  goto output;
953  } else {
954  /* parent */
955  char *args[] = {pager, NULL};
956  close(pager_fds[1]); /* close unused write end!!! important */
957  /* set read end of pipe as stdin for this process */
958  dup2(pager_fds[0], STDIN_FILENO);
959  close(pager_fds[0]); /* already redirected to stdin */
960  execvp(args[0], args);
961  free(pager);
962  perror("exec failed");
963  exit(EXIT_FAILURE);
964  }
965  return;
966 output:
967  /* pager is useless by now */
968  free(pager);
969  printf("TRAP module, libtrap version: %s %s\n", trap_version, trap_git_version);
970  puts("===========================================");
971  if (trap_help_spec == 0) {
972  printf("Name: %s\n", module_info->name);
973  if (module_info->num_ifc_in == -1) {
974  printf("Inputs: variable\n");
975  } else {
976  printf("Inputs: %u\n", (module_info->num_ifc_in));
977  }
978  if (module_info->num_ifc_out == -1) {
979  printf("Outputs: variable\n");
980  } else {
981  printf("Outputs: %u\n", module_info->num_ifc_out);
982  }
983  printf("Description:\n ");
984  print_aligned(module_info->description, 2, cols - 2);
985 
986 
987  /* print basic usage with module name */
988  char *module_name = get_module_name();
989  printf("\nUsage: %s [COMMON]... ", module_name);
990  free(module_name);
991 
992  if (module_info->params != NULL) {
993  i = 0;
994  while (module_info->params[i] != NULL) {
995  if (module_info->params[i]->short_opt == '-') {
996  adit_param = 1;
997  } else if ((module_info->params[i]->short_opt >= 'a' && module_info->params[i]->short_opt <= 'z')
998  || (module_info->params[i]->short_opt >= 'A' && module_info->params[i]->short_opt <= 'Z')) {
999  opt_param = 1;
1000  }
1001  i++;
1002  }
1003  }
1004 
1005  if (opt_param == 1) {
1006  printf("[OPTIONS]... ");
1007  }
1008  if (adit_param == 1) {
1009  printf("[ADDITIONAL]... ");
1010  }
1011  printf("\n");
1012 
1013  align_def = strlen("LIBTRAP_OUTPUT_FORMAT") + 4;
1014  align_opt = 0;
1015 
1016  if (opt_param == 1) {
1017  for (i = 0; module_info->params[i] != NULL; i++) {
1018  if (module_info->params[i]->argument_type == NULL) {
1019  continue;
1020  }
1021  if (HAVE_GETOPT_LONG && module_info->params[i]->long_opt != NULL) {
1022  tmp = strlen(module_info->params[i]->long_opt) + strlen(module_info->params[i]->argument_type);
1023  } else {
1024  tmp = strlen(module_info->params[i]->argument_type);
1025  }
1026  if (tmp > align_opt) {
1027  align_opt = tmp;
1028  }
1029  }
1030  /* add additional chars as a space: */
1031  align_opt += 14;
1032 
1033  if (align_opt > align_def) {
1034  align_def = align_opt;
1035  }
1036 
1037  printf("\nParameters of module [OPTIONS]:\n-------------------------------\n");
1038 
1039  i = 0;
1040  while (module_info->params[i] != NULL) {
1041  /* Position parameters (params without option, instead of "-o arg" it is only "arg") are specified with '-' in short-opt */
1042  if (module_info->params[i]->short_opt == '-') {
1043  i++;
1044  continue;
1045  } else if (HAVE_GETOPT_LONG) {
1046  if (isprint(module_info->params[i]->short_opt)) {
1047  written = printf(" -%c --%s ", module_info->params[i]->short_opt,
1048  module_info->params[i]->long_opt);
1049  } else {
1050  written = printf(" --%s ", module_info->params[i]->long_opt);
1051  }
1052  } else {
1053  written = printf(" -%c ", module_info->params[i]->short_opt);
1054  }
1055  switch (module_info->params[i]->param_required_argument) {
1056  case required_argument:
1057  written += printf("<%s>", module_info->params[i]->argument_type);
1058  break;
1059  case optional_argument:
1060  written += printf("[%s]", module_info->params[i]->argument_type);
1061  break;
1062  case no_argument:
1063  written += printf(" ");
1064  break;
1065  }
1066  if (written < align_def) {
1067  printf("%*s", align_def - written, " ");
1068  }
1069 
1070  print_aligned(module_info->params[i]->description, align_def, cols - align_def);
1071  /* empty line after param */
1072  puts("");
1073 
1074  i++;
1075  }
1076  }
1077 
1078  /* If the module has some position parameters, their section is printed */
1079  if (adit_param == 1) {
1080  printf("\nAdditional parameters of module [ADDITIONAL]:\n---------------------------------------------\n");
1081 
1082  i = 0;
1083  while (module_info->params[i] != NULL) {
1084  if (module_info->params[i]->short_opt == '-') {
1085  printf(" %s", module_info->params[i]->description);
1086  if (module_info->params[i]->param_required_argument == required_argument) {
1087  printf(" (data type: <%s>)", module_info->params[i]->argument_type);
1088  }
1089  printf("\n\n");
1090  }
1091  i++;
1092  }
1093  }
1094 
1095  printf("\nCommon TRAP parameters [COMMON]:\n--------------------------------\n");
1096 
1097 #define X(param, text, align, cut) do { \
1098  written = printf(param); \
1099  if (written < align_def) { \
1100  printf("%*s", align - written, " "); \
1101  } \
1102  print_aligned(text, align, cut); \
1103  puts(""); \
1104 } while (0)
1105 
1106  X(" -h [trap,1]",
1107  "If no argument, print this message. If \"trap\" or 1 is given, print "
1108  "TRAP help.",
1109  align_def, cols - align_def);
1110 
1111  X(" -i IFC_SPEC",
1112  "Specification of interface types and their parameters, "
1113  "see \"-h trap\" (mandatory parameter).",
1114  align_def, cols - align_def);
1115 
1116  X(" -v", "Be verbose.", align_def, cols - align_def);
1117  X(" -vv", "Be more verbose.", align_def, cols - align_def);
1118  X(" -vvv", "Be even more verbose.", align_def, cols - align_def);
1119 
1120  puts("\nEnvironment variables that affects output:\n------------------------------------------");
1121  X(" LIBTRAP_OUTPUT_FORMAT", "If set to \"json\", information about module is printed in JSON format.",
1122  align_def, cols - align_def);
1123  X(" PAGER", "Show the help output in the set PAGER.",
1124  align_def, cols - align_def);
1125  X(" TRAP_SOCKET_DIR", "Change path to socket directory (default: " DEFAULTSOCKETDIR ").",
1126  align_def, cols - align_def);
1127 
1128 #undef X
1129  } else if (trap_help_spec != 0) {
1131  }
1132 }
1133 
1134 /** Print help about interface specifier.
1135  * Prints help message about format of interface specifier and description of
1136  * all available interface types.
1137  */
1139 {
1140  extern const char *trap_help_ifcspec;
1141  uint32_t cols = get_terminal_width();
1142  if (cols == 0) {
1144  }
1145 
1147 }
1148 
1149 ////////////////////////////
1150 
1151 /**
1152  * \brief Splitter of *params* string.
1153  * Cut the first param, copy it into *dest* and returns pointer to the start of following
1154  * parameter.
1155  * \param[in] source source string, typically *params*
1156  * \param[out] dest destination string, target of first parameter copying
1157  * \param[in] delimiter separator of values in *params*
1158  * \return Pointer to the start of following parameter (char after delimiter). \note If NULL, no other parameter is present or error during allocation occured.
1159  */
1160 char *trap_get_param_by_delimiter(const char *source, char **dest, const char delimiter)
1161 {
1162  char *param_end = NULL;
1163  unsigned int param_size = 0;
1164 
1165  if (source == NULL) {
1166  return NULL;
1167  }
1168 
1169  param_end = strchr(source, delimiter);
1170  if (param_end == NULL) {
1171  /* no delimiter found, copy the whole source */
1172  *dest = strdup(source);
1173  return NULL;
1174  }
1175 
1176  param_size = param_end - source;
1177  *dest = (char *) calloc(1, param_size + 1);
1178  if (*dest == NULL) {
1179  return (NULL);
1180  }
1181  strncpy(*dest, source, param_size);
1182  return param_end + 1;
1183 }
1184 
1185 inline char *get_param_by_delimiter(const char *source, char **dest, const char delimiter)
1186 {
1187  return trap_get_param_by_delimiter(source, dest, delimiter);
1188 }
1189 
1190 void trap_set_abs_timespec(struct timeval *tm, struct timespec *tmnblk)
1191 {
1192  if (tmnblk == NULL) {
1193  /* we do not need tmnblk */
1194  return;
1195  }
1196  /* tmnblk is used for timed wait on semaphore, this needs absolute time... */
1197  if (clock_gettime(CLOCK_REALTIME, tmnblk) == -1) {
1198  /* handle error */
1199  tmnblk->tv_sec = 0;
1200  tmnblk->tv_nsec = 0;
1201  }
1202 
1203  if (tm->tv_usec != 0) {
1204  tmnblk->tv_nsec = (long) tm->tv_usec * 1000;
1205  } else {
1206  tmnblk->tv_nsec = 0;
1207  }
1208  tmnblk->tv_sec += (time_t) (tm->tv_sec + (tm->tv_usec / 1000000));
1209 }
1210 
1211 void trap_set_timeouts(int timeout, struct timeval *tm, struct timespec *tmnblk)
1212 {
1213  if ((timeout == TRAP_NO_WAIT) || (timeout == TRAP_HALFWAIT)) {
1214  tm->tv_sec = 0;
1215  tm->tv_usec = 0;
1216  } else if (timeout > TRAP_HALFWAIT) {
1217  if (timeout == TRAP_WAIT) {
1218  tm->tv_sec = 0;
1219  tm->tv_usec = 0;
1220  } else {
1221  tm->tv_sec = timeout / 1000000;
1222  tm->tv_usec = timeout % 1000000;
1223  }
1224  } else {
1225  VERBOSE(CL_ERROR, "Setting timeout to %d failed", timeout);
1226  return;
1227  }
1228  trap_set_abs_timespec(tm, tmnblk);
1229 }
1230 
1231 int trap_ifcctl(int8_t type, uint32_t ifcidx, int32_t request, ... /* arg */)
1232 {
1233  va_list ap;
1234  int res;
1235  va_start(ap, request);
1236  res = trap_ctx_vifcctl(trap_glob_ctx, type, ifcidx, request, ap);
1237  va_end(ap);
1238  return res;
1239 }
1240 
1241 void trap_send_flush(uint32_t ifc)
1242 {
1244 }
1245 
1246 /**
1247  * \addtogroup contextapi Context API
1248  * @{
1249  */
1250 
1252 {
1253  trap_ctx_priv_t *ctx = calloc(1, sizeof(trap_ctx_priv_t));
1254  /* space for vars init with non-zero values */
1255  return ctx;
1256 }
1257 
1259 {
1260  int i;
1261  trap_ctx_priv_t *c;
1262 
1263  if (ctx == NULL) {
1264  return;
1265  }
1266  c = (*ctx);
1267  if (c == NULL) {
1268  return;
1269  }
1270 
1271  /* free allocated counters */
1272  free(c->counter_autoflush);
1273  c->counter_autoflush = NULL;
1274  free(c->counter_send_buffer);
1275  c->counter_send_buffer = NULL;
1276  free(c->counter_recv_message);
1277  c->counter_recv_message = NULL;
1278  free(c->counter_send_message);
1279  c->counter_send_message = NULL;
1280  free(c->counter_recv_buffer);
1281  c->counter_recv_buffer = NULL;
1282  free(c->counter_dropped_message);
1283  c->counter_dropped_message = NULL;
1284  free(c->counter_recv_delay_last);
1285  c->counter_recv_delay_last = NULL;
1286  free(c->counter_recv_delay_total);
1287  c->counter_recv_delay_total = NULL;
1288  free(c->recv_delay_timestamp);
1289  c->recv_delay_timestamp = NULL;
1290 
1291  pthread_mutex_destroy(&c->error_mtx);
1292 
1293  // Destroy all interfaces
1294  if ((c->num_ifc_in > 0) && (c->in_ifc_list != NULL)) {
1295  for (i = 0; i < c->num_ifc_in; i++) {
1296  if (c->in_ifc_list[i].buffer != NULL) {
1297  free(c->in_ifc_list[i].buffer);
1298  c->in_ifc_list[i].buffer = NULL;
1299  }
1300  if (c->in_ifc_list[i].data_fmt_spec != NULL) {
1301  free(c->in_ifc_list[i].data_fmt_spec);
1302  c->in_ifc_list[i].data_fmt_spec = NULL;
1303  }
1304  if (c->in_ifc_list[i].req_data_fmt_spec != NULL) {
1305  free(c->in_ifc_list[i].req_data_fmt_spec);
1306  c->in_ifc_list[i].req_data_fmt_spec = NULL;
1307  }
1308  if (c->in_ifc_list[i].destroy != NULL) {
1309  c->in_ifc_list[i].destroy(c->in_ifc_list[i].priv);
1310  }
1311  pthread_mutex_destroy(&c->in_ifc_list[i].ifc_mtx);
1312  }
1313  free(c->in_ifc_list);
1314  }
1315 
1316  if ((c->num_ifc_out > 0) && (c->out_ifc_list != NULL)) {
1317  for (i = 0; i < c->num_ifc_out; i++) {
1318  if (c->out_ifc_list[i].destroy != NULL) {
1319  c->out_ifc_list[i].destroy(c->out_ifc_list[i].priv);
1320  }
1321  if (c->out_ifc_list[i].data_fmt_spec != NULL) {
1322  free(c->out_ifc_list[i].data_fmt_spec);
1323  c->out_ifc_list[i].data_fmt_spec = NULL;
1324  }
1325  pthread_mutex_destroy(&c->out_ifc_list[i].ifc_mtx);
1326  }
1327  free(c->out_ifc_list);
1328  c->out_ifc_list = NULL;
1329  free(c->ifc_autoflush_timeout);
1330  c->ifc_autoflush_timeout = NULL;
1331  }
1332 
1333  if (c->service_ifc_name != NULL) {
1334  free(c->service_ifc_name);
1335  c->service_ifc_name = NULL;
1336  }
1337 
1338  free(c);
1339  (*ctx) = NULL;
1340 }
1341 
1343 {
1344  int i;
1345  trap_ctx_priv_t *c = (trap_ctx_priv_t *) ctx;
1346  if (c == NULL || c->terminated) {
1347  return TRAP_E_OK;
1348  }
1349 
1350  c->terminated = 1;
1351 
1352  for (i = 0; i < c->num_ifc_in; i++) {
1353  if (c->in_ifc_list[i].terminate != NULL) {
1354  c->in_ifc_list[i].terminate(c->in_ifc_list[i].priv);
1355  } else {
1356  return trap_errorf(c, TRAP_E_MEMORY, "IFC was not initialized.");
1357  }
1358  }
1359  for (i = 0; i < c->num_ifc_out; i++) {
1360  if (c->out_ifc_list[i].terminate != NULL) {
1361  c->out_ifc_list[i].terminate(c->out_ifc_list[i].priv);
1362  } else {
1363  return trap_errorf(c, TRAP_E_MEMORY, "IFC was not initialized.");
1364  }
1365  }
1366 
1367  return trap_error(ctx, TRAP_E_OK);
1368 }
1369 
1370 static inline uint64_t get_cur_timestamp()
1371 {
1372  struct timespec spec_time;
1373 
1374  clock_gettime(CLOCK_MONOTONIC, &spec_time);
1375  /* time in microseconds seconds -> secs * microsends + nanoseconds */
1376  return spec_time.tv_sec * 1000000 + (spec_time.tv_nsec / 1000);
1377 }
1378 
1379 int trap_ctx_recv(trap_ctx_t *ctx, uint32_t ifcidx, const void **data, uint16_t *size)
1380 {
1381  int ret_val = 0;
1382  trap_ctx_priv_t *c = (trap_ctx_priv_t *) ctx;
1383  if (c == NULL || c->initialized == 0) {
1384  return TRAP_E_NOT_INITIALIZED;
1385  }
1386 
1387  uint64_t delay = get_cur_timestamp() - c->recv_delay_timestamp[ifcidx];
1388  c->counter_recv_delay_last[ifcidx] = delay;
1389  c->counter_recv_delay_total[ifcidx] += delay;
1390 
1391  if (c->terminated) {
1392  return trap_error(c, TRAP_E_TERMINATED);
1393  }
1394 
1395  if (ifcidx >= c->num_ifc_in) {
1396  return trap_errorf(c, TRAP_E_NOT_SELECTED, "No input ifc to get data from...");
1397  }
1398 
1399  ret_val = trap_read_from_buffer(c, ifcidx, data, size, c->in_ifc_list[ifcidx].datatimeout);
1400 
1401  c->recv_delay_timestamp[ifcidx] = get_cur_timestamp();
1402  return trap_error(ctx, ret_val);
1403 }
1404 
1405 /** Cleanup function.
1406  * Disconnect all interfaces and do all necessary cleanup.
1407  * @return Error code
1408  */
1410 {
1411  int i;
1412  if ((ctx == NULL) || (*ctx == NULL)) {
1413  return TRAP_E_NOT_INITIALIZED;
1414  }
1415  trap_ctx_priv_t *c = *((trap_ctx_priv_t **)ctx);
1416  if (c == NULL) {
1417  return TRAP_E_NOT_INITIALIZED;
1418  }
1419  if (c->initialized == 0) {
1420  free(c);
1421  (*ctx) = NULL;
1422  return TRAP_E_NOT_INITIALIZED;
1423  }
1424 
1425  /* force flush of buffer for every output ifc */
1426  for (i = 0; i < c->num_ifc_out; i++) {
1429  trap_ctx_send_flush((trap_ctx_t *) c, i);
1430  }
1431 
1432  /* check if libtrap is terminated and terminate if not */
1433  if (c->terminated == 0) {
1434  trap_ctx_terminate(c);
1435  }
1436 
1437  if (c->service_thread_initialized == 1) {
1438  pthread_join(c->service_thread, NULL);
1439  }
1440  trap_free_ctx_t(&c);
1441  (*ctx) = NULL;
1442 
1444 
1445  return TRAP_E_OK;
1446 }
1447 
1448 int trap_ctx_send(trap_ctx_t *ctx, unsigned int ifc, const void *data, uint16_t size)
1449 {
1450  int ret_val = TRAP_E_OK;
1451  trap_ctx_priv_t *c = (trap_ctx_priv_t *) ctx;
1452  if (c == NULL || c->initialized == 0) {
1453  return TRAP_E_NOT_INITIALIZED;
1454  }
1455  trap_output_ifc_t* ifc_ptr = &c->out_ifc_list[ifc];
1456 
1457  if (c->terminated) {
1458  return trap_error(c, TRAP_E_TERMINATED);
1459  }
1460 
1461  if (ifc >= c->num_ifc_out) {
1462  return trap_error(c, TRAP_E_BAD_IFC_INDEX);
1463  }
1464 
1465  ret_val = ifc_ptr->send(ifc_ptr->priv, data, size, ifc_ptr->datatimeout);
1466 
1467  if (ret_val == TRAP_E_OK) {
1468  __sync_add_and_fetch(&c->counter_send_message[ifc], 1);
1469  } else {
1470  __sync_add_and_fetch(&c->counter_dropped_message[ifc], 1);
1471  }
1472  return trap_error(ctx, ret_val);
1473 }
1474 
1475 /**
1476  * Remove setter starting from params string.
1477  *
1478  * \param[in,out] params String with parameters of IFC.
1479  * \param[in] setter Pointer to the start of setter that should be removed.
1480  * It ends by TRAP_IFC_PARAM_DELIMITER or zero-byte in the string.
1481  */
1482 static inline void remove_setter_from_param(char *params, char *setter)
1483 {
1484  char *strval = strchr(setter, TRAP_IFC_PARAM_DELIMITER);
1485  if (strval == NULL) {
1486  if (params < setter) {
1487  *(setter - 1) = 0;
1488  } else {
1489  *setter = 0;
1490  }
1491  } else {
1492  for (strval++; *strval != 0; setter++, strval++) {
1493  *setter = *strval;
1494  }
1495  *setter = 0;
1496  }
1497 }
1498 
1499 /**
1500  * Find setters in IFC parameters and set values if needed.
1501  *
1502  * \param[in,out] ifc Pointer to IFC structure from the array in context.
1503  * \param[in,out] params String passed as argument of -i, found setters are
1504  * removed after their processing.
1505  */
1506 static inline void handle_inifc_setters(trap_input_ifc_t *ifc, char *params)
1507 {
1508  char *strval, *p;
1509 
1510  /* look for timeout setter and set the datatimeout if found */
1511  p = strstr(params, "timeout=");
1512  if (p != NULL) {
1513 
1514 #define X(val) do { \
1515  ifc->datatimeout = val; \
1516  ifc->datatimeout_fixed = 1; \
1517 } while (0)
1518  strval = p + sizeof("timeout=") - 1;
1519  if (strncmp(strval, "WAIT", 4) == 0) {
1520  X(TRAP_WAIT);
1521  } else if (strncmp(strval, "NO_WAIT", 7) == 0) {
1522  X(TRAP_NO_WAIT);
1523  } else {
1524  if (sscanf(strval, "%"SCNi32, &ifc->datatimeout) == 1) {
1525  ifc->datatimeout_fixed = 1;
1526  }
1527  }
1528 #undef X
1529  /* clean the parameter because it was processed */
1530  remove_setter_from_param(params, p);
1531  }
1532 }
1533 
1534 /**
1535  * Switch of supported IFC types, place to call input IFC constructor.
1536  *
1537  * \param[in,out] ctx pointer to context
1538  * \param[in] ifc_spec IFC specifiers
1539  * \param[in] idx index into IFC array
1540  * \return EXIT_SUCCESS on success, EXIT_FAILURE on error.
1541  */
1542 static inline int trapifc_in_construct(trap_ctx_priv_t *ctx, trap_ifc_spec_t *ifc_spec, int idx)
1543 {
1544  int ret = TRAP_E_OK;
1545  /* Common setters - this should be done before the constructor */
1546  handle_inifc_setters(&ctx->in_ifc_list[idx], ifc_spec->params[idx]);
1547 
1548  switch (ifc_spec->types[idx]) {
1550  /* if (create_generator_ifc("\x10||==::test::==||", &ctx->in_ifc_list[idx]) != TRAP_E_OK) */
1551  if ((ret = create_generator_ifc(ctx, ifc_spec->params[idx], &ctx->in_ifc_list[idx])) != TRAP_E_OK) {
1552  VERBOSE(CL_ERROR, "Initialization of GENERATOR input interface no. %i failed.", idx);
1553  goto error;
1554  }
1555  break;
1556  case TRAP_IFC_TYPE_TCPIP:
1557  if ((ret = create_tcpip_receiver_ifc(ctx, ifc_spec->params[idx], &ctx->in_ifc_list[idx], idx, TRAP_IFC_TCPIP)) != TRAP_E_OK) {
1558  VERBOSE(CL_ERROR, "Initialization of TCPIP input interface no. %i failed.", idx);
1559  goto error;
1560  }
1561  break;
1562 #if HAVE_OPENSSL
1563  case TRAP_IFC_TYPE_TLS:
1564  if ((ret = create_tls_receiver_ifc(ctx, ifc_spec->params[idx], &ctx->in_ifc_list[idx], idx)) != TRAP_E_OK) {
1565  VERBOSE(CL_ERROR, "Initialization of TLS input interface no. %i failed.", idx);
1566  goto error;
1567  }
1568  break;
1569 #endif
1570  case TRAP_IFC_TYPE_UNIX:
1571  if ((ret = create_tcpip_receiver_ifc(ctx, ifc_spec->params[idx], &ctx->in_ifc_list[idx], idx, TRAP_IFC_TCPIP_UNIX)) != TRAP_E_OK) {
1572  VERBOSE(CL_ERROR, "Initialization of UNIX input interface no. %i failed.", idx);
1573  goto error;
1574  }
1575  break;
1576  case TRAP_IFC_TYPE_FILE:
1577  if ((ret = create_file_recv_ifc(ctx, ifc_spec->params[idx], &ctx->in_ifc_list[idx], idx)) != TRAP_E_OK) {
1578  VERBOSE(CL_ERROR, "Initialization of FILE input interface no. %i failed.", idx);
1579  goto error;
1580  }
1581  break;
1582  default:
1583  VERBOSE(CL_ERROR, "Unknown input interface type '%c'.", ifc_spec->types[idx]);
1584  ret = TRAP_E_BADPARAMS;
1585  goto error;
1586  }
1587  return EXIT_SUCCESS;
1588 error:
1589  trap_error(ctx, ret);
1590  return EXIT_FAILURE;
1591 }
1592 
1593 /**
1594  * Find setters in IFC parameters and set values if needed.
1595  *
1596  * \param[in,out] ifc Pointer to IFC structure from the array in context.
1597  * \param[in,out] params String passed as argument of -i, found setters are
1598  * removed after their processing.
1599  */
1600 static inline void handle_outifc_setters(trap_output_ifc_t *ifc, char *params)
1601 {
1602  char *strval, *p;
1603 
1604  /* look for timeout setter and set the datatimeout if found */
1605  p = strstr(params, "timeout=");
1606  if (p != NULL) {
1607 
1608 #define X(val) do { \
1609  ifc->datatimeout = val; \
1610  ifc->datatimeout_fixed = 1; \
1611 } while (0)
1612  strval = p + sizeof("timeout=") - 1;
1613  if (strncmp(strval, "WAIT", 4) == 0) {
1614  X(TRAP_WAIT);
1615  } else if (strncmp(strval, "NO_WAIT", 7) == 0) {
1616  X(TRAP_NO_WAIT);
1617  } else if (strncmp(strval, "HALF_WAIT", 9) == 0) {
1618  X(TRAP_HALFWAIT);
1619  } else {
1620  if (sscanf(strval, "%"SCNi32, &ifc->datatimeout) == 1) {
1621  ifc->datatimeout_fixed = 1;
1622  }
1623  }
1624 #undef X
1625  /* clean the parameter because it was processed */
1626  remove_setter_from_param(params, p);
1627  }
1628 
1629  /* look for bufferswitch setter and set it if found */
1630  p = strstr(params, "buffer=");
1631  if (p != NULL) {
1632 
1633 #define X(val) do { \
1634  ifc->bufferswitch = val; \
1635  ifc->bufferswitch_fixed = 1; \
1636 } while (0)
1637  char *strval = p + sizeof("buffer=") - 1;
1638  if (strncmp(strval, "on", 2) == 0) {
1639  X(1);
1640  } else if (strncmp(strval, "off", 3) == 0) {
1641  X(0);
1642  } else {
1643  VERBOSE(CL_ERROR, "Unknown value for setter \"buffer\".");
1644  }
1645 #undef X
1646  /* clean the parameter because it was processed */
1647  remove_setter_from_param(params, p);
1648  }
1649 
1650  /* look for autoflush setter and set the it if found */
1651  p = strstr(params, "autoflush=");
1652  if (p != NULL) {
1653  strval = p + sizeof("autoflush=") - 1;
1654  if (strncmp(strval, "off", 3) == 0) {
1655  ifc->timeout = TRAP_NO_AUTO_FLUSH;
1656  ifc->timeout_fixed = 1;
1657  } else {
1658  if (sscanf(strval, "%"SCNi64, &ifc->timeout) == 1) {
1659  ifc->timeout_fixed = 1;
1660  }
1661  }
1662  /* clean the parameter because it was processed */
1663  remove_setter_from_param(params, p);
1664  }
1665 }
1666 
1667 /**
1668  * Switch of supported IFC types, place to call output IFC constructor.
1669  *
1670  * \param[in,out] ctx pointer to context
1671  * \param[in] ifc_spec IFC specifiers
1672  * \param[in] idx index into IFC array
1673  * \return EXIT_SUCCESS on success, EXIT_FAILURE on error.
1674  */
1675 static inline int trapifc_out_construct(trap_ctx_priv_t *ctx, trap_ifc_spec_t *ifc_spec, int idx)
1676 {
1677  int ret = TRAP_E_OK;
1678  /* Common setters - this should be done before the constructor */
1680  ifc_spec->params[ctx->num_ifc_in + idx]);
1681 
1682  /* call correct constructor of interface */
1683  switch (ifc_spec->types[ctx->num_ifc_in + idx]) {
1685  if ((ret = create_blackhole_ifc(ctx, NULL, &ctx->out_ifc_list[idx])) != TRAP_E_OK) {
1686  VERBOSE(CL_ERROR, "Initialization of BLACKHOLE output interface no. %i failed.", idx);
1687  goto error;
1688  }
1689  break;
1690  case TRAP_IFC_TYPE_TCPIP:
1691  if ((ret = create_tcpip_sender_ifc(ctx, ifc_spec->params[ctx->num_ifc_in + idx],
1692  &ctx->out_ifc_list[idx], idx, TRAP_IFC_TCPIP)) != TRAP_E_OK) {
1693  VERBOSE(CL_ERROR, "Initialization of TCPIP output interface no. %i failed.", idx);
1694  goto error;
1695  }
1696  break;
1697 #if HAVE_OPENSSL
1698  case TRAP_IFC_TYPE_TLS:
1699  if ((ret = create_tls_sender_ifc(ctx, ifc_spec->params[ctx->num_ifc_in + idx], &ctx->out_ifc_list[idx], idx)) != TRAP_E_OK) {
1700  VERBOSE(CL_ERROR, "Initialization of TLS output interface no. %i failed.", idx);
1702  goto error;
1703  }
1704  break;
1705 #endif
1706  case TRAP_IFC_TYPE_UNIX:
1707  if ((ret = create_tcpip_sender_ifc(ctx, ifc_spec->params[ctx->num_ifc_in + idx],
1708  &ctx->out_ifc_list[idx], idx, TRAP_IFC_TCPIP_UNIX)) != TRAP_E_OK) {
1709  VERBOSE(CL_ERROR, "Initialization of UNIX output interface no. %i failed.", idx);
1710  goto error;
1711  }
1712  break;
1713  case TRAP_IFC_TYPE_FILE:
1714  if ((ret = create_file_send_ifc(ctx, ifc_spec->params[ctx->num_ifc_in + idx], &ctx->out_ifc_list[idx], idx)) != TRAP_E_OK) {
1715  VERBOSE(CL_ERROR, "Initialization of FILE output interface no. %i failed.", idx);
1716  goto error;
1717  }
1718  break;
1719  default:
1720  VERBOSE(CL_ERROR, "Unknown output interface type '%c'.", ifc_spec->types[ctx->num_ifc_in + idx]);
1721  ret = TRAP_E_BADPARAMS;
1722  goto error;
1723  }
1724 
1725  return EXIT_SUCCESS;
1726 error:
1727  trap_error(ctx, ret);
1728  return EXIT_FAILURE;
1729 }
1730 
1731 trap_ctx_t *trap_ctx_init3(const char *name, const char *description, int8_t i_ifcs, int8_t o_ifcs, const char *ifc_spec, const char *service_ifc_name)
1732 {
1733  trap_ctx_t *res = NULL;
1734  trap_module_info_t module_info;
1735  trap_ifc_spec_t ifcs;
1736  int argc = 2;
1737 
1738  char *argv[2] = {"-i", (char *) ifc_spec};
1739 
1740  /* Prepare module info */
1741  if (name != NULL) {
1742  module_info.name = strdup(name);
1743  } else {
1744  module_info.name = strdup("nemea-module");
1745  }
1746  if (description != NULL) {
1747  module_info.description = strdup(description);
1748  } else {
1749  module_info.description = strdup("");
1750  }
1751  module_info.num_ifc_in = i_ifcs;
1752  module_info.num_ifc_out = o_ifcs;
1753 
1754  if (module_info.name == NULL || module_info.description == NULL) {
1755  VERBOSE(CL_ERROR, "Not enough memory.");
1756  if (module_info.name != NULL) {
1757  free(module_info.name);
1758  }
1759  if (module_info.description != NULL) {
1760  free(module_info.description);
1761  }
1762 
1763  return NULL;
1764  }
1765 
1766  /* Prepare ifcs (trap_ifc_spec_t) */
1767  int rv = trap_parse_params(&argc, argv, &ifcs);
1768  if (rv != TRAP_E_OK) {
1769  fprintf(stderr, "ERROR in parsing of parameters for TRAP: %s\n", trap_last_error_msg);
1770  return NULL;
1771  }
1772 
1773  res = trap_ctx_init2(&module_info, ifcs, service_ifc_name);
1774 
1775  free(module_info.name);
1776  free(module_info.description);
1777  trap_free_ifc_spec(ifcs);
1778 
1779  return res;
1780 }
1781 
1782 /**
1783  *
1784  * \return context, NULL when allocation failed.
1785  */
1786 trap_ctx_t *trap_ctx_init(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec)
1787 {
1788  // service_sock_spec size is length of "service_PID" where PID is max 10 chars (8 + 10 + 1 zero terminating)
1789  char service_sock_spec[19];
1790  trap_ctx_t *res = NULL;
1791 
1792  if (snprintf(service_sock_spec, 19, "service_%d", getpid()) < 1) {
1793  VERBOSE(CL_ERROR, "Could not create service socket specifier in service routine.");
1794  return NULL;
1795  }
1796 
1797  res = trap_ctx_init2(module_info, ifc_spec, service_sock_spec);
1798 
1799  return res;
1800 }
1801 
1802 trap_ctx_t *trap_ctx_init2(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec, const char *service_ifc_name)
1803 {
1804  int i;
1805  if ((ifc_spec.types == NULL) || (ifc_spec.params == NULL)) {
1806  return NULL;
1807  }
1809  if (ctx == NULL) {
1810  return NULL;
1811  }
1812  /* count number of interfaces */
1813  if (module_info->num_ifc_in < 0 && module_info->num_ifc_out < 0) {
1814  trap_free_ctx_t(&ctx);
1815  return NULL;
1816  } else if (module_info->num_ifc_in < 0) {
1817  module_info->num_ifc_in = strlen(ifc_spec.types) - module_info->num_ifc_out;
1818  } else if (module_info->num_ifc_out < 0) {
1819  module_info->num_ifc_out = strlen(ifc_spec.types) - module_info->num_ifc_in;
1820  }
1821 
1823  if (pthread_mutex_init(&ctx->error_mtx, NULL) != 0) {
1824  free(ctx);
1825  return NULL;
1826  }
1827 
1828  trap_error(ctx, TRAP_E_OK); // set "no error"
1829 
1830  // Check whether parameters matches module's numbers of interfaces
1831  ctx->num_ifc_in = module_info->num_ifc_in;
1832  ctx->num_ifc_out = module_info->num_ifc_out;
1833 
1834  int strlen_ifc_types = strlen(ifc_spec.types);
1835 
1836  if (strlen_ifc_types != (ctx->num_ifc_in + ctx->num_ifc_out)) {
1837  trap_errorf(ctx, TRAP_E_BADPARAMS, "Bad number of IFCs in IFC_SPEC.");
1838  VERBOSE(CL_ERROR, "Got %d IFCs via -i, expected %d input and %d output IFCs.",
1839  strlen_ifc_types, ctx->num_ifc_in, ctx->num_ifc_out);
1840  return ctx;
1841  }
1842 
1843  ctx->counter_send_message = (uint64_t *) calloc(ctx->num_ifc_out, sizeof(uint64_t));
1844  ctx->counter_recv_message = (uint64_t *) calloc(ctx->num_ifc_in, sizeof(uint64_t));
1845  ctx->counter_send_buffer = (uint64_t *) calloc(ctx->num_ifc_out, sizeof(uint64_t));
1846  ctx->counter_autoflush = (uint64_t *) calloc(ctx->num_ifc_out, sizeof(uint64_t));
1847  ctx->counter_recv_buffer = (uint64_t *) calloc(ctx->num_ifc_in, sizeof(uint64_t));
1848  ctx->counter_dropped_message = (uint64_t *) calloc(ctx->num_ifc_out, sizeof(uint64_t));
1849  ctx->counter_recv_delay_last = (uint64_t *) calloc(ctx->num_ifc_in, sizeof(uint64_t));
1850  ctx->counter_recv_delay_total = (uint64_t *) calloc(ctx->num_ifc_in, sizeof(uint64_t));
1851  ctx->recv_delay_timestamp = (uint64_t *) calloc(ctx->num_ifc_in, sizeof(uint64_t));
1852 
1853  ctx->terminated = 0;
1854 
1855  // Create input interfaces
1856  if (ctx->num_ifc_in > 0) {
1857  ctx->in_ifc_list = (trap_input_ifc_t *) calloc(ctx->num_ifc_in, sizeof(trap_input_ifc_t));
1858  if (!ctx->in_ifc_list) {
1859  trap_error(ctx, TRAP_E_MEMORY);
1860  goto alloc_counter_failed;
1861  }
1862 
1863  /* set default value of datatimeout */
1864  for (i=0; i<ctx->num_ifc_in; ++i) {
1865  ctx->in_ifc_list[i].datatimeout = TRAP_WAIT;
1867 
1869  ctx->in_ifc_list[i].data_fmt_spec = NULL;
1871  ctx->in_ifc_list[i].req_data_fmt_spec = NULL;
1872 
1873  /* allocate extra bytes for TCPIP IFC checksum */
1874  ctx->in_ifc_list[i].buffer = (void *) calloc(1, TRAP_IFC_MESSAGEQ_SIZE + 1);
1875  if (ctx->in_ifc_list[i].buffer == NULL) {
1876  trap_errorf(ctx, TRAP_E_MEMORY, "Not enough memory for input ifc buffer.");
1877  goto freein_on_failed;
1878  }
1879  ctx->in_ifc_list[i].buffer_unread_bytes = 0;
1880  ctx->in_ifc_list[i].buffer_pointer = ctx->in_ifc_list[i].buffer;
1881  ctx->in_ifc_list[i].ifc_type = ifc_spec.types[i];
1883 
1884  /* call input IFC constructor */
1885  if (trapifc_in_construct(ctx, &ifc_spec, i) == EXIT_FAILURE) {
1886  goto freein_on_failed;
1887  }
1888  }
1889 
1890  }
1891 
1892  // Create output interfaces
1893  if (ctx->num_ifc_out > 0) {
1894  ctx->out_ifc_list = (trap_output_ifc_t *) calloc(ctx->num_ifc_out, sizeof(trap_output_ifc_t));
1895  if (ctx->out_ifc_list == NULL) {
1896  trap_error(ctx, TRAP_E_MEMORY);
1897  goto freeall_on_failed;
1898  }
1899  /* set default value of datatimeout */
1900  for (i=0; i<ctx->num_ifc_out; ++i) {
1902  }
1903  }
1904 
1905  for (i = 0; i < ctx->num_ifc_out; i++) {
1907  ctx->out_ifc_list[i].data_fmt_spec = NULL;
1908 
1909  if (pthread_mutex_init(&ctx->out_ifc_list[i].ifc_mtx, NULL) != 0) {
1910  goto freein_on_failed;
1911  }
1913  ctx->out_ifc_list[i].bufferswitch = 1;
1914  ctx->out_ifc_list[i].ifc_type = ifc_spec.types[ctx->num_ifc_in + i];
1915 
1916  /* call output IFC constructor */
1917  if (trapifc_out_construct(ctx, &ifc_spec, i) == EXIT_FAILURE) {
1918  goto freeall_on_failed;
1919  }
1920 
1921  }
1922 
1923  /*
1924  * Set the name of service IFC, which is passed in context to service thread.
1925  * Service thread creates service IFC (UNIX IFC) with the given name and handles client
1926  * requests in the loop.
1927  */
1928  if (service_ifc_name != NULL) {
1929  ctx->service_ifc_name = strdup(service_ifc_name);
1930  } else {
1931  ctx->service_ifc_name = NULL;
1932  }
1933 
1934  if (pthread_create(&ctx->service_thread, NULL, service_thread_routine, (void *) ctx) == 0) {
1935  ctx->service_thread_initialized = 1;
1936  } else {
1937  ctx->service_thread_initialized = 0;
1938  VERBOSE(CL_VERBOSE_LIBRARY, "pthread_create() error: could not create service thread.");
1939  }
1940 
1941  ctx->initialized = 1;
1942  return ctx;
1943 
1944 freeall_on_failed:
1945  if (ctx->out_ifc_list != NULL) {
1946  for (i=0; i<ctx->num_ifc_out; ++i) {
1947  pthread_mutex_destroy(&ctx->out_ifc_list[i].ifc_mtx);
1948  if (ctx->out_ifc_list[i].destroy != NULL && ctx->out_ifc_list[i].priv != NULL) {
1949  ctx->out_ifc_list[i].destroy(ctx->out_ifc_list[i].priv);
1950  }
1951  }
1952 
1953  free(ctx->out_ifc_list);
1954  ctx->out_ifc_list = NULL;
1955  }
1956 freein_on_failed:
1957  if (ctx->in_ifc_list != NULL) {
1958  for (i=0; i<ctx->num_ifc_in; ++i) {
1959  pthread_mutex_destroy(&ctx->in_ifc_list[i].ifc_mtx);
1960  if (ctx->in_ifc_list[i].destroy != NULL && ctx->in_ifc_list[i].priv != NULL) {
1961  ctx->in_ifc_list[i].destroy(ctx->in_ifc_list[i].priv);
1962  }
1963 
1964  if (ctx->in_ifc_list[i].buffer != NULL) {
1965  free(ctx->in_ifc_list[i].buffer);
1966  ctx->in_ifc_list[i].buffer = NULL;
1967  }
1968  }
1969  }
1970  ctx->terminated = 1;
1971 
1972  if (ctx->in_ifc_list) {
1973  free(ctx->in_ifc_list);
1974  ctx->in_ifc_list = NULL;
1975  }
1976 alloc_counter_failed:
1977  if (ctx->counter_send_message) {
1978  free(ctx->counter_send_message);
1979  ctx->counter_send_message = NULL;
1980  }
1981  if (ctx->counter_recv_message) {
1982  free(ctx->counter_recv_message);
1983  ctx->counter_recv_message = NULL;
1984  }
1985  if (ctx->counter_send_buffer) {
1986  free(ctx->counter_send_buffer);
1987  ctx->counter_send_buffer = NULL;
1988  }
1989  if (ctx->counter_autoflush) {
1990  free(ctx->counter_autoflush);
1991  ctx->counter_autoflush = NULL;
1992  }
1993  if (ctx->counter_recv_buffer) {
1994  free(ctx->counter_recv_buffer);
1995  ctx->counter_recv_buffer = NULL;
1996  }
1997  if (ctx->counter_dropped_message) {
1998  free(ctx->counter_dropped_message);
1999  ctx->counter_dropped_message = NULL;
2000  }
2001  if (ctx->counter_recv_delay_last) {
2002  free(ctx->counter_recv_delay_last);
2003  ctx->counter_recv_delay_last = NULL;
2004  }
2005  if (ctx->counter_recv_delay_total) {
2006  free(ctx->counter_recv_delay_total);
2007  ctx->counter_recv_delay_total = NULL;
2008  }
2009  if (ctx->recv_delay_timestamp) {
2010  free(ctx->recv_delay_timestamp);
2011  ctx->recv_delay_timestamp = NULL;
2012  }
2013 
2015 
2016  return ctx;
2017 }
2018 
2019 int trap_ctx_ifcctl(trap_ctx_t *ctx, int8_t type, uint32_t ifcidx, int32_t request, ... /* arg */)
2020 {
2021  va_list ap;
2022  int res;
2023  if (ctx == NULL) {
2024  return TRAP_E_NOT_INITIALIZED;
2025  }
2026  va_start(ap, request);
2027  res = trap_ctx_vifcctl(ctx, type, ifcidx, request, ap);
2028  va_end(ap);
2029  return trap_error(ctx, res);
2030 }
2031 
2032 int trap_ctx_vifcctl(trap_ctx_t *ctx, int8_t type, uint32_t ifcidx, int32_t request, va_list ap)
2033 {
2034  char en_dis_switch = 0;
2035  uint64_t timeout = 0;
2036  int32_t datatimeout;
2037  trap_ctx_priv_t *c = ctx;
2038 
2039  if ((ifcidx >= c->num_ifc_out) && (ifcidx >= c->num_ifc_in)) {
2040  /* error - wrong interface index, because it should be less than number of input or output interfaces */
2041  VERBOSE(CL_ERROR, "Index of non-existing interface.");
2042  return trap_error(ctx, TRAP_E_BADPARAMS);
2043  }
2044 
2045  if (c->terminated) {
2046  return trap_error(ctx, TRAP_E_TERMINATED);
2047  }
2048 
2049  switch (request) {
2051  timeout = va_arg(ap, uint64_t);
2052  VERBOSE(CL_VERBOSE_BASIC, "%s ifc %d: Setting autoflush timeout to %lu.",
2053  ifcdir2str(type), (int)ifcidx, timeout);
2054  if (type == TRAPIFC_OUTPUT) {
2055  if (c->out_ifc_list[ifcidx].timeout_fixed == 0) {
2056  __sync_bool_compare_and_swap(&c->out_ifc_list[ifcidx].timeout, c->out_ifc_list[ifcidx].timeout, timeout);
2057  __sync_fetch_and_add(&c->ifc_change, 1);
2058  }
2059  }
2060  break;
2061  case TRAPCTL_BUFFERSWITCH:
2062  en_dis_switch = (char) va_arg(ap, int);
2063  VERBOSE(CL_VERBOSE_BASIC, "%s ifc %d: Set buffer switch to %s.",
2064  ifcdir2str(type), (int)ifcidx, ((int) en_dis_switch ? "ON" : "OFF"));
2065  if (type == TRAPIFC_OUTPUT) {
2066  if (c->out_ifc_list[ifcidx].bufferswitch_fixed == 0) {
2067  __sync_bool_compare_and_swap(&c->out_ifc_list[ifcidx].bufferswitch, c->out_ifc_list[ifcidx].bufferswitch, en_dis_switch);
2068  __sync_fetch_and_add(&c->ifc_change, 1);
2069  }
2070  }
2071  break;
2072  case TRAPCTL_SETTIMEOUT:
2073  datatimeout = (int32_t) va_arg(ap, int32_t);
2074  VERBOSE(CL_VERBOSE_BASIC, "%s ifc %d: Setting timeout to %d.",
2075  ifcdir2str(type), (int)ifcidx, datatimeout);
2076  if (type == TRAPIFC_OUTPUT) {
2077  if (ifcidx < c->num_ifc_out) {
2078  if (c->out_ifc_list[ifcidx].datatimeout_fixed == 0) {
2079  __sync_bool_compare_and_swap(&c->out_ifc_list[ifcidx].datatimeout, c->out_ifc_list[ifcidx].datatimeout, datatimeout);
2080  }
2081  } else {
2082  VERBOSE(CL_ERROR, "There is no output IFC with this index. Bad index passed.");
2083  }
2084  } else if (type == TRAPIFC_INPUT) {
2085  if (ifcidx < c->num_ifc_in) {
2086  if (c->in_ifc_list[ifcidx].datatimeout_fixed == 0) {
2087  __sync_bool_compare_and_swap(&c->in_ifc_list[ifcidx].datatimeout, c->in_ifc_list[ifcidx].datatimeout, datatimeout);
2088  }
2089  } else {
2090  VERBOSE(CL_ERROR, "There is no input IFC with this index. Bad index passed.");
2091  }
2092  }
2093  break;
2094 
2095  default:
2096  VERBOSE(CL_ERROR, "Unknown type of request.");
2097  }
2098 
2099  return trap_error(ctx, TRAP_E_OK);;
2100 }
2101 
2103 {
2104  trap_ctx_priv_t *c = ctx;
2105  return c->trap_last_error;
2106 }
2107 
2109 {
2110  /* TODO: this is dangerous... the value in buffer can be changing constantly. */
2111  trap_ctx_priv_t *c = ctx;
2112  return c->trap_last_error_msg;
2113 }
2114 
2115 void trap_ctx_send_flush(trap_ctx_t *ctx, uint32_t ifc)
2116 {
2117  trap_ctx_priv_t *c = ctx;
2118 
2119  if (c == NULL || c->initialized == 0) {
2120  return;
2121  }
2122 
2123  c->out_ifc_list[ifc].flush(c->out_ifc_list[ifc].priv);
2124 }
2125 
2126 /**
2127  * @}
2128  */
2129 
2130 /**
2131  * \addtogroup supervisor Supervisor monitoring feature
2132  * @{
2133  */
2134 
2135 /* Structure used as a header sent before data in json format in service interface */
2136 typedef struct msg_header_s {
2137  uint8_t com;
2138  uint32_t data_size;
2139 } msg_header_t;
2140 
2141 int service_get_data(int sock_d, uint32_t size, void **data)
2142 {
2143  int num_of_timeouts = 0;
2144  int total_receved = 0;
2145  int last_receved = 0;
2146 
2147  while (total_receved < size) {
2148  last_receved = recv(sock_d, (*data) + total_receved, size - total_receved, MSG_DONTWAIT);
2149  if (last_receved == 0) {
2150  return -1;
2151  } else if (last_receved == -1) {
2152  if (errno == EAGAIN || errno == EWOULDBLOCK) {
2153  num_of_timeouts++;
2154  if (num_of_timeouts >= 3) {
2155  return -1;
2156  } else {
2157  usleep(25000);
2158  continue;
2159  }
2160  }
2161  return -1;
2162  }
2163  total_receved += last_receved;
2164  }
2165  return TRAP_E_OK;
2166 }
2167 
2168 int service_send_data(int sock_d, uint32_t size, void **data)
2169 {
2170  int num_of_timeouts = 0, total_sent = 0, last_sent = 0;
2171 
2172  while (total_sent < size) {
2173  last_sent = send(sock_d, (*data) + total_sent, size - total_sent, MSG_DONTWAIT);
2174  if (last_sent == -1) {
2175  if (errno == EAGAIN || errno == EWOULDBLOCK) {
2176  num_of_timeouts++;
2177  if (num_of_timeouts >= 3) {
2178  return -1;
2179  } else {
2180  usleep(25000);
2181  continue;
2182  }
2183  }
2184  return -1;
2185  }
2186  total_sent += last_sent;
2187  }
2188  return TRAP_E_OK;
2189 }
2190 
2191 
2193 {
2194  uint32_t x = 0;
2195  char *ifc_id = NULL;
2196  char none_ifc_id[] = "none";
2197 
2198  json_t *in_ifc_cnts = NULL;
2199  json_t *out_ifc_cnts = NULL;
2200  json_t *client_stats_arr;
2201 
2202  uint32_t in_cnt = (ctx->num_ifc_in > 0) ? ctx->num_ifc_in : 0;
2203  uint32_t out_cnt = (ctx->num_ifc_out > 0) ? ctx->num_ifc_out : 0;
2204 
2205  json_t *in_ifces_arr = json_array();
2206  if (in_ifces_arr == NULL) {
2207  VERBOSE(CL_ERROR, "Service thread - could not create json array while creating json string with counters.");
2208  goto clean_up;
2209  }
2210  json_t *out_ifces_arr = json_array();
2211  if (out_ifces_arr == NULL) {
2212  VERBOSE(CL_ERROR, "Service thread - could not create json array while creating json string with counters.");
2213  goto clean_up;
2214  }
2215 
2216  json_t *result_json = NULL;
2217 
2218  for (x = 0; x < in_cnt; x++) {
2219  ifc_id = ctx->in_ifc_list[x].get_id(ctx->in_ifc_list[x].priv);
2220  if (ifc_id == NULL) {
2221  ifc_id = none_ifc_id;
2222  }
2223  in_ifc_cnts = json_pack("{sisssisIsIsIsI}",
2224  "ifc_state", ctx->in_ifc_list[x].is_conn(ctx->in_ifc_list[x].priv),
2225  "ifc_id", ifc_id, "ifc_type", (int) (ctx->in_ifc_list[x].ifc_type),
2226  "messages", __sync_fetch_and_add(&ctx->counter_recv_message[x], 0),
2227  "buffers", __sync_fetch_and_add(&ctx->counter_recv_buffer[x], 0),
2228  "delay_last", __sync_fetch_and_add(&ctx->counter_recv_delay_last[x], 0),
2229  "delay_total", (long)(__sync_fetch_and_add(&ctx->counter_recv_delay_total[x], 0)) / 1000000); // round to whole seconds
2230  if (json_array_append_new(in_ifces_arr, in_ifc_cnts) == -1) {
2231  VERBOSE(CL_ERROR, "Service thread - could not append new item to out_ifces_arr while creating json string with counters..\n");
2232  goto clean_up;
2233  }
2234  }
2235 
2236  for (x = 0; x < out_cnt; x++) {
2237  ifc_id = ctx->out_ifc_list[x].get_id(ctx->out_ifc_list[x].priv);
2238  if (ifc_id == NULL) {
2239  ifc_id = none_ifc_id;
2240  }
2241 
2242  client_stats_arr = json_array();
2243  if (client_stats_arr == NULL) {
2244  VERBOSE(CL_ERROR, "Service thread - could not create json array with client statistics\n");
2245  goto clean_up;
2246  }
2247 
2248  if (ctx->out_ifc_list[x].get_client_stats_json(ctx->out_ifc_list[x].priv, client_stats_arr) == 0) {
2249  VERBOSE(CL_ERROR, "Service thread - could not create json array with client statistics\n");
2250  goto clean_up;
2251  }
2252 
2253  out_ifc_cnts = json_pack("{sosisssisIsIsIsI}",
2254  "client_stats_arr", client_stats_arr,
2255  "num_clients", ctx->out_ifc_list[x].get_client_count(ctx->out_ifc_list[x].priv),
2256  "ifc_id", ifc_id, "ifc_type", (int) (ctx->out_ifc_list[x].ifc_type),
2257  "sent-messages", __sync_fetch_and_add(&ctx->counter_send_message[x], 0),
2258  "dropped-messages", __sync_fetch_and_add(&ctx->counter_dropped_message[x], 0),
2259  "buffers", __sync_fetch_and_add(&ctx->counter_send_buffer[x], 0),
2260  "autoflushes", __sync_fetch_and_add(&ctx->counter_autoflush[x],0));
2261  if (json_array_append_new(out_ifces_arr, out_ifc_cnts) == -1) {
2262  VERBOSE(CL_ERROR, "Service thread - could not append new item to out_ifces_arr while creating json string with counters..\n");
2263  goto clean_up;
2264  }
2265  }
2266 
2267  result_json = json_pack("{sisisoso}", "in_cnt", in_cnt, "out_cnt", out_cnt, "in", in_ifces_arr, "out", out_ifces_arr);
2268  if (result_json == NULL) {
2269  VERBOSE(CL_ERROR, "Service thread - could not create final json object while creating json string with counters.");
2270  goto clean_up;
2271  }
2272 
2273  *data = json_dumps(result_json, 0);
2274  json_decref(result_json);
2275  if (*data == NULL) {
2276  return -1;
2277  }
2278  return 0;
2279 
2280 
2281 clean_up:
2282  *data = NULL;
2283  return -1;
2284 }
2285 
2286 /**
2287  * Service IFC thread function.
2288  *
2289  * This function is run in separate thread. It waits for incoming
2290  * connections e.g. from supervisor. Service IFC can send IFC counters
2291  * declared in #trap_ctx_priv_s
2292  * \param[in] arg Pointer to the private libtrap context data (#trap_ctx_init()).
2293  */
2294 void *service_thread_routine(void *arg)
2295 {
2296  struct timespec ts = {.tv_sec = 0, .tv_nsec = 100000000};
2297  msg_header_t *header = (msg_header_t *) calloc(1, sizeof(msg_header_t));
2298  char *json_data = NULL;
2299  int ret_val, supervisor_sd;
2300  trap_output_ifc_t *service_ifc = NULL;
2301  tcpip_sender_private_t *priv;
2302  int i, j; /* loop vars */
2303  struct client_s *cl;
2304  struct pollfd *pfds = NULL;
2305  int pfds_size;
2306 
2307  trap_ctx_priv_t *g_ctx = (trap_ctx_priv_t *) arg;
2308 
2309  if (g_ctx->service_ifc_name == NULL) {
2310  VERBOSE(CL_VERBOSE_OFF, "Service socket will not be created, its name is not specified.");
2311  goto exit_service_thread;
2312  }
2313 
2314  service_ifc = (trap_output_ifc_t *) calloc(1, sizeof(trap_output_ifc_t));
2315  if (service_ifc == NULL) {
2316  VERBOSE(CL_ERROR, "Error: allocation of service IFC failed.");
2317  goto exit_service_thread;
2318  }
2319 
2320  /* service port does not create thread for accepting clients */
2321  if (create_tcpip_sender_ifc(NULL, g_ctx->service_ifc_name, service_ifc, 0, TRAP_IFC_TCPIP_SERVICE) != TRAP_E_OK) {
2322  VERBOSE(CL_ERROR,"Error while creating service IFC.");
2323  free(service_ifc);
2324  service_ifc = NULL;
2325  goto exit_service_thread;
2326  }
2327 
2328  priv = (tcpip_sender_private_t *) service_ifc->priv;
2329  pfds = calloc(priv->clients_arr_size + 1, sizeof(*pfds));
2330  if (pfds == NULL) {
2331  VERBOSE(CL_ERROR, "Error: allocation of pfds failed.");
2332  goto exit_service_thread;
2333  }
2334  while (1) {
2335  if (g_ctx->terminated) {
2336  break;
2337  }
2338 
2339  /* prepare file descriptor set */
2340  pfds_size = 0;
2341  pfds[pfds_size++] = (struct pollfd) {.fd = priv->server_sd, .events = POLLIN};
2342  for (i=0; i<priv->clients_arr_size; ++i) {
2343  cl = &priv->clients[i];
2344  if (cl->sd > 0) {
2345  pfds[pfds_size++] = (struct pollfd) {.fd = cl->sd, .events = POLLIN};
2346  }
2347  }
2348  fflush(stdout);
2349 
2350  ret_val = ppoll(pfds, pfds_size, &ts, NULL);
2351  if (ret_val == -1) {
2352  if (errno == EINTR) {
2353  /* received interrupt, go to next terminated condition */
2354  continue;
2355  }
2356  VERBOSE(CL_ERROR, "Select() failed in service thread.");
2357  break;
2358  } else if (ret_val == 0) {
2359  // timeout
2360  continue;
2361  } else {
2362  /* handle all read events - requests / new client */
2363  for (i = j = 0; i < priv->clients_arr_size; ++i) {
2364  cl = &priv->clients[i];
2365  if (cl->sd > -1 && pfds[++j].revents & POLLIN) {
2366  supervisor_sd = cl->sd;
2367  ret_val = service_get_data(supervisor_sd, sizeof(msg_header_t), (void **) &header);
2368 
2369  if (ret_val == -1) {
2370  /* disconnected client */
2371  close(cl->sd);
2372  cl->sd = -1;
2373  continue;
2374  } else if (ret_val == 0) {
2375  if (header->com == SERVICE_GET_COM) {
2376  if (encode_cnts_to_json(&json_data, g_ctx) != 0) {
2377  VERBOSE(CL_VERBOSE_LIBRARY, "[ERROR] Service could not encode counters to json.")
2378  close(cl->sd);
2379  cl->sd = -1;
2380  continue;
2381  } else {
2382  // Set reply header before send
2383  header->com = SERVICE_OK_REPLY;
2384  header->data_size = strlen(json_data) + 1;
2385  if (service_send_data(supervisor_sd, sizeof(msg_header_t), (void **) &header) != TRAP_E_OK) {
2386  VERBOSE(CL_VERBOSE_LIBRARY, "[ERROR] Service could not send data header.")
2387  close(cl->sd);
2388  cl->sd = -1;
2389  free(json_data);
2390  json_data = NULL;
2391  continue;
2392  }
2393  if (service_send_data(supervisor_sd, header->data_size, (void **) &json_data) != TRAP_E_OK) {
2394  VERBOSE(CL_VERBOSE_LIBRARY, "[ERROR] Service could not send data.")
2395  close(cl->sd);
2396  cl->sd = -1;
2397  free(json_data);
2398  json_data = NULL;
2399  continue;
2400  }
2401 
2402  free(json_data);
2403  json_data = NULL;
2404  }
2405  } else {
2406  // Received unknown request -> disconnect client
2407  VERBOSE(CL_VERBOSE_LIBRARY, "[ERROR] Service thread received unknown request.")
2408  close(cl->sd);
2409  cl->sd = -1;
2410  continue;
2411  }
2412  }
2413  }
2414  }
2415  if (pfds[0].revents & POLL_IN) {
2416  /* accept new client */
2417  for (i=0; i<priv->clients_arr_size; ++i) {
2418  cl = &priv->clients[i];
2419  if (cl->sd == -1) {
2420  cl->sd = accept(priv->server_sd, NULL, NULL);
2421  goto accept_success;
2422  }
2423  }
2424  /* not enough space, go away */
2425  int accept_retval = accept(priv->server_sd, NULL, NULL);
2426  if (accept_retval >= 0) {
2427  close(accept_retval);
2428  }
2429 accept_success:
2430  continue;
2431  }
2432  }
2433  }
2434 
2435  /* disconnect rest clients */
2436  for (i=0; i<priv->clients_arr_size; ++i) {
2437  cl = &priv->clients[i];
2438  if (cl->sd > -1) {
2439  close(cl->sd);
2440  cl->sd = -1;
2441  }
2442  }
2443 
2444 exit_service_thread:
2445  if (json_data != NULL) {
2446  free(json_data);
2447  json_data = NULL;
2448  }
2449  free(header);
2450  if (service_ifc != NULL) {
2451  service_ifc->terminate(service_ifc->priv);
2452  service_ifc->destroy(service_ifc->priv);
2453  free(service_ifc);
2454  }
2455  if (pfds != NULL) {
2456  free(pfds);
2457  }
2458  pthread_exit(NULL);
2459 }
2460 
2461 /**
2462  * \brief Create dump files.
2463  *
2464  * Create dump files for debug as follows:
2465  * trap-i[number]-config.txt Output interface configuration.
2466  * trap-i[number]-buffer.dat Output interface buffer
2467  * trap-o[number]-config.txt Input interface configuration.
2468  * trap-o[number]-buffer.dat Input interface buffer
2469  *
2470  * \param[in] ctx Pointer to the private libtrap context data (#trap_ctx_init()).
2471  * \param[in] path Output directory, if NULL use current working directory.
2472  */
2473 void trap_ctx_create_ifc_dump(trap_ctx_t *ctx, const char *path)
2474 {
2475  const char *td = "./";
2476  uint32_t i;
2477 
2478  if (path != NULL) {
2479  td = path;
2480  }
2481 
2482  trap_ctx_priv_t *c = ctx;
2483  if (c == NULL || c->initialized == 0) {
2484  VERBOSE(CL_ERROR, "Not initialized libtrap context, skipping...");
2485  return;
2486  }
2487  for (i = 0; i < c->num_ifc_in; i++) {
2488  c->in_ifc_list[i].create_dump(c->in_ifc_list[i].priv, i, td);
2489  }
2490  for (i = 0; i < c->num_ifc_out; i++) {
2491  c->out_ifc_list[i].create_dump(c->out_ifc_list[i].priv, i, td);
2492  }
2493 }
2494 
2495 int trap_ctx_get_client_count(trap_ctx_t *ctx, uint32_t ifcidx)
2496 {
2497  trap_ctx_priv_t *c = ctx;
2498  if (c == NULL || c->initialized == 0 || ifcidx > c->num_ifc_out) {
2499  return -1;
2500  }
2501  return c->out_ifc_list[ifcidx].get_client_count(c->out_ifc_list[ifcidx].priv);
2502 }
2503 
2504 /**
2505  * @}
2506  */
2507 
2508 /**
2509  * \addtogroup contextapi
2510  * @{
2511  */
2512 /**
2513  * \addtogroup trap_mess_fmt
2514  * @{
2515  */
2516 void trap_ctx_vset_data_fmt(trap_ctx_t *ctx, uint32_t out_ifc_idx, uint8_t data_type, va_list ap)
2517 {
2518  trap_output_ifc_t *ifc;
2519  trap_ctx_priv_t *c = ctx;
2520  char *data_fmt_spec = (char *) va_arg(ap, char *);
2521 
2522  if ((c == NULL) || (data_type == TRAP_FMT_UNKNOWN) || (out_ifc_idx >= c->num_ifc_out)) {
2523  VERBOSE(CL_ERROR, "%s: Uninitialized libtrap context or bad parameters.", __func__);
2524  return;
2525  }
2526 
2527  ifc = &c->out_ifc_list[out_ifc_idx];
2528  /* If the data type is already set, disconnect all connected clients to this output interface (auto-negotiation will be performed again to get new data format and data spec) */
2529  pthread_mutex_lock(&ifc->ifc_mtx);
2530  if (ifc->data_type != TRAP_FMT_UNKNOWN) {
2531  VERBOSE(CL_VERBOSE_LIBRARY, "Data format setter: not initial setting of data_type -> disconnect all clients of the output interface %d.", out_ifc_idx);
2532  if (ifc->disconn_clients != NULL) {
2533  ifc->disconn_clients(ifc->priv);
2534  }
2535  }
2536  ifc->data_type = data_type;
2537  if (data_type != TRAP_FMT_RAW) {
2538  if (ifc->data_fmt_spec != NULL) {
2539  free(ifc->data_fmt_spec);
2540  ifc->data_fmt_spec = NULL;
2541  }
2542  if (data_fmt_spec == NULL) {
2543  ifc->data_fmt_spec = NULL;
2544  } else {
2545  ifc->data_fmt_spec = strdup(data_fmt_spec);
2546  }
2547  }
2548  pthread_mutex_unlock(&ifc->ifc_mtx);
2549 }
2550 
2551 void trap_ctx_set_data_fmt(trap_ctx_t *ctx, uint32_t out_ifc_idx, uint8_t data_type, ...)
2552 {
2553  va_list ap;
2554 
2555  if (ctx == NULL) {
2556  VERBOSE(CL_ERROR, "%s: Uninitialized libtrap context.", __func__);
2557  return;
2558  }
2559 
2560  va_start(ap, data_type);
2561  trap_ctx_vset_data_fmt(ctx, out_ifc_idx, data_type, ap);
2562  va_end(ap);
2563 }
2564 
2565 int trap_ctx_vset_required_fmt(trap_ctx_t *ctx, uint32_t in_ifc_idx, uint8_t data_type, va_list ap)
2566 {
2567  trap_input_ifc_t *ifc;
2568  trap_ctx_priv_t *c = ctx;
2569  char *req_data_fmt_spec = (char *) va_arg(ap, char *);
2570 
2571  if (c == NULL) {
2572  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2573  }
2574 
2575  if (data_type == TRAP_FMT_UNKNOWN) {
2576  return trap_error(ctx, TRAP_E_BADPARAMS);
2577  }
2578 
2579  if (in_ifc_idx >= c->num_ifc_in) {
2580  return trap_error(ctx, TRAP_E_BAD_IFC_INDEX);
2581  }
2582 
2583  ifc = &c->in_ifc_list[in_ifc_idx];
2584  pthread_mutex_lock(&ifc->ifc_mtx);
2585  ifc->req_data_type = data_type;
2586  if (data_type != TRAP_FMT_RAW) {
2587  if (ifc->req_data_fmt_spec != NULL) {
2588  free(ifc->req_data_fmt_spec);
2589  ifc->req_data_fmt_spec = NULL;
2590  }
2591  if (req_data_fmt_spec == NULL) {
2592  ifc->req_data_fmt_spec = NULL;
2593  } else {
2594  ifc->req_data_fmt_spec = strdup(req_data_fmt_spec);
2595  }
2596  }
2597  pthread_mutex_unlock(&ifc->ifc_mtx);
2598 
2599  return trap_error(ctx, TRAP_E_OK);
2600 }
2601 
2602 int trap_ctx_set_required_fmt(trap_ctx_t *ctx, uint32_t in_ifc_idx, uint8_t data_type, ...)
2603 {
2604  va_list ap;
2605  int res;
2606 
2607  if (ctx == NULL) {
2608  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2609  }
2610 
2611  va_start(ap, data_type);
2612  res = trap_ctx_vset_required_fmt(ctx, in_ifc_idx, data_type, ap);
2613  va_end(ap);
2614  return trap_error(ctx, res);
2615 }
2616 
2617 int trap_ctx_get_data_fmt(trap_ctx_t *ctx, uint8_t ifc_dir, uint32_t ifc_idx, uint8_t *data_type, const char **spec)
2618 {
2619  trap_input_ifc_t *inifc;
2620  trap_output_ifc_t *outifc;
2621  trap_ctx_priv_t *c = ctx;
2622 
2623  if (ctx == NULL) {
2624  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2625  }
2626 
2627  if (ifc_dir == TRAPIFC_INPUT) {
2628  if (ifc_idx >= c->num_ifc_in) {
2629  return trap_error(ctx, TRAP_E_BAD_IFC_INDEX);
2630  }
2631 
2632  inifc = &c->in_ifc_list[ifc_idx];
2633 
2634  pthread_mutex_lock(&inifc->ifc_mtx);
2635  if (inifc->data_type == TRAP_FMT_UNKNOWN) {
2636  pthread_mutex_unlock(&inifc->ifc_mtx);
2637  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2638  }
2639 
2640  if (inifc->client_state == FMT_OK || inifc->client_state == FMT_CHANGED) {
2641  (*data_type) = inifc->data_type;
2642  if (inifc->data_type != TRAP_FMT_RAW) {
2643  /* TODO: Should probably do copy. */
2644  (*spec) = inifc->data_fmt_spec;
2645  } else {
2646  (*spec) = NULL;
2647  }
2648  } else {
2649  pthread_mutex_unlock(&inifc->ifc_mtx);
2650  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2651  }
2652  pthread_mutex_unlock(&inifc->ifc_mtx);
2653  } else {
2654  /* TRAPIFC_OUTPUT */
2655  if (ifc_idx >= c->num_ifc_out) {
2656  return trap_error(ctx, TRAP_E_BAD_IFC_INDEX);
2657  }
2658 
2659  outifc = &c->out_ifc_list[ifc_idx];
2660 
2661  pthread_mutex_lock(&outifc->ifc_mtx);
2662  if (outifc->data_type == TRAP_FMT_UNKNOWN) {
2663  pthread_mutex_unlock(&outifc->ifc_mtx);
2664  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2665  }
2666 
2667  (*data_type) = outifc->data_type;
2668  if (*data_type != TRAP_FMT_RAW) {
2669  /* TODO: Should probably do copy. */
2670  (*spec) = outifc->data_fmt_spec;
2671  } else {
2672  (*spec) = NULL;
2673  }
2674  pthread_mutex_unlock(&outifc->ifc_mtx);
2675  }
2676  return trap_error(ctx, TRAP_E_OK);
2677 }
2678 /**
2679  * @}
2680  *//* trap_mess_fmt */
2681 /**
2682  * @}
2683  */
2684 
2685 /**
2686  * \addtogroup simpleapi
2687  * @{
2688  */
2689 /**
2690  * \addtogroup trap_mess_fmt
2691  * @{
2692  */
2693 void trap_set_data_fmt(uint32_t out_ifc_idx, uint8_t data_type, ...)
2694 {
2695  va_list ap;
2696 
2697  va_start(ap, data_type);
2698  trap_ctx_vset_data_fmt(trap_glob_ctx, out_ifc_idx, data_type, ap);
2699  va_end(ap);
2700 }
2701 
2702 int trap_set_required_fmt(uint32_t in_ifc_idx, uint8_t data_type, ...)
2703 {
2704  va_list ap;
2705  int res;
2706 
2707  va_start(ap, data_type);
2708  res = trap_ctx_vset_required_fmt(trap_glob_ctx, in_ifc_idx, data_type, ap);
2709  va_end(ap);
2710 
2711  return res;
2712 }
2713 
2714 int trap_get_data_fmt(uint8_t ifc_dir, uint32_t in_ifc_idx, uint8_t *data_type, const char **spec)
2715 {
2716  return trap_ctx_get_data_fmt(trap_glob_ctx, ifc_dir, in_ifc_idx, data_type, spec);
2717 }
2718 
2719 int trap_ctx_get_in_ifc_state(trap_ctx_t *ctx, uint32_t ifc_idx)
2720 {
2721  if (ctx == NULL) {
2722  return trap_error(ctx, TRAP_E_NOT_INITIALIZED);
2723  }
2724 
2725  trap_ctx_priv_t *c = (trap_ctx_priv_t *) ctx;
2726 
2727  if (ifc_idx >= c->num_ifc_in) {
2728  return trap_error(ctx, TRAP_E_BAD_IFC_INDEX);
2729  }
2730 
2731  return __sync_fetch_and_add(&c->in_ifc_list[ifc_idx].client_state, 0);
2732 }
2733 
2734 int trap_get_in_ifc_state(uint32_t ifc_idx)
2735 {
2736  return trap_ctx_get_in_ifc_state(trap_glob_ctx, ifc_idx);
2737 }
2738 
2739 const char *trap_get_type_and_name_from_string(const char *source, const char **name, const char **type, int *length_name, int *length_type)
2740 {
2741  int length_type_2 = 0, length_name_2 = 0;
2742  const char *source_cpy;
2743  source_cpy = source;
2744  while (*source != 0 && *source != ' ') {
2745  length_type_2++;
2746  source ++;
2747  }
2748  *type = source_cpy;
2749  *length_type = length_type_2;
2750  source ++;
2751  //get name
2752  source_cpy = source;
2753  while (*source != 0 && *source != ',') {
2754  length_name_2++;
2755  source ++;
2756  }
2757  *length_name = length_name_2;
2758  *name = source_cpy;
2759  if (*source == ',') {
2760  source ++;
2761  }
2762  return source;
2763 }
2764 
2765 int trap_ctx_cmp_data_fmt(const char *sender_ifc_data_fmt, const char *receiver_ifc_data_fmt)
2766 {
2767  if (sender_ifc_data_fmt == NULL && receiver_ifc_data_fmt != NULL) {
2768  return TRAP_E_FIELDS_MISMATCH;
2769  } else if (sender_ifc_data_fmt != NULL && receiver_ifc_data_fmt == NULL) {
2770  return TRAP_E_FIELDS_SUBSET;
2771  } else if (sender_ifc_data_fmt == NULL && receiver_ifc_data_fmt == NULL) {
2772  return TRAP_E_OK;
2773  }
2774 
2775  const char *receiver_move,
2776  *sender_move,
2777  *field_name_receiver,
2778  *field_name_sender,
2779  *field_type_receiver,
2780  *field_type_sender;
2781  int field_name_receiver_length = 0,
2782  field_name_sender_length = 0,
2783  field_type_receiver_length = 0,
2784  field_type_sender_length = 0;
2785  int compare_str = 0;
2786  receiver_move = receiver_ifc_data_fmt;
2787  sender_move = sender_ifc_data_fmt;
2788  // go through all fields of receiver and search for each one in set of sender's fields
2789  while (*receiver_move != 0) {
2790  // get a receiver's field
2791  receiver_move = trap_get_type_and_name_from_string(receiver_move, &field_name_receiver,
2792  &field_type_receiver, &field_name_receiver_length, &field_type_receiver_length);
2793  compare_str = 0;
2794  while (*sender_move != 0 && !compare_str) {
2795  // search the field in set of sender's fields
2796  sender_move = trap_get_type_and_name_from_string(sender_move, &field_name_sender,
2797  &field_type_sender, &field_name_sender_length, &field_type_sender_length);
2798  compare_str = (field_name_sender_length == field_name_receiver_length &&
2799  field_type_sender_length == field_type_receiver_length &&
2800  memcmp(field_name_sender, field_name_receiver, field_name_receiver_length) == 0 &&
2801  memcmp(field_type_sender, field_type_receiver, field_type_receiver_length) == 0);
2802  }
2803  if (!compare_str) {
2804  VERBOSE(CL_ERROR, "TRAP Negotiation failed: required field `%.*s %.*s` not offered by sender.\nReceived specifier: %s",
2805  field_type_receiver_length, field_type_receiver,
2806  field_name_receiver_length, field_name_receiver,
2807  sender_ifc_data_fmt);
2808  return TRAP_E_FIELDS_MISMATCH; // one of receiver fields not found
2809  }
2810  // reset pointer to beginning of sender's set of fields
2811  sender_move = sender_ifc_data_fmt;
2812  }
2813  if (strlen(sender_ifc_data_fmt) > strlen(receiver_ifc_data_fmt)) {
2814  // receivers fmt spec is subset of senders fmt spec
2815  return TRAP_E_FIELDS_SUBSET;
2816  }
2817  return TRAP_E_OK;
2818 }
2819 
2821 {
2822  return (trap_ctx_t *) trap_glob_ctx;
2823 }
2824 
2825 /**
2826  * @}
2827  *//* trap_mess_fmt */
2828 /**
2829  * @}
2830  */
2831 
2832 
2833 int output_ifc_negotiation(void *ifc_priv_data, char ifc_type, uint32_t client_idx)
2834 {
2835  VERBOSE(CL_VERBOSE_LIBRARY, "--- Output IFC negotiation ---");
2836 
2837  hello_msg_header_t *hello_msg_header = NULL;
2838  uint32_t size_of_buffer = sizeof(hello_msg_header_t);
2839  char *buffer = (char *) calloc(size_of_buffer, sizeof(char));
2840  char *p = NULL;
2841  uint32_t size = 0;
2842  int ret_val = 0;
2843  int neg_result = NEG_RES_OK;
2844  int compare = 0;
2845  int sock_d = 0;
2846  file_private_t *file_ifc_priv = NULL;
2847  tcpip_sender_private_t *tcp_ifc_priv = NULL;
2848 #if HAVE_OPENSSL
2849  tls_sender_private_t *tls_ifc_priv = NULL;
2850 #endif
2851  uint8_t data_type = TRAP_FMT_UNKNOWN;
2852  char *data_fmt_spec = NULL;
2853  uint32_t ifc_idx = 0;
2854 
2855  // Decide which structure can be used for interfaces private data
2856  if (ifc_type == TRAP_IFC_TYPE_FILE) {
2857  file_ifc_priv = (file_private_t *) ifc_priv_data;
2858  data_type = file_ifc_priv->ctx->out_ifc_list[file_ifc_priv->ifc_idx].data_type;
2859  data_fmt_spec = file_ifc_priv->ctx->out_ifc_list[file_ifc_priv->ifc_idx].data_fmt_spec;
2860  ifc_idx = file_ifc_priv->ifc_idx;
2861 #if HAVE_OPENSSL
2862  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
2863  tls_ifc_priv = (tls_sender_private_t *) ifc_priv_data;
2864  data_type = tls_ifc_priv->ctx->out_ifc_list[tls_ifc_priv->ifc_idx].data_type;
2865  data_fmt_spec = tls_ifc_priv->ctx->out_ifc_list[tls_ifc_priv->ifc_idx].data_fmt_spec;
2866  ifc_idx = tls_ifc_priv->ifc_idx;
2867 #endif
2868  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
2869  tcp_ifc_priv = (tcpip_sender_private_t *) ifc_priv_data;
2870  data_type = tcp_ifc_priv->ctx->out_ifc_list[tcp_ifc_priv->ifc_idx].data_type;
2871  data_fmt_spec = tcp_ifc_priv->ctx->out_ifc_list[tcp_ifc_priv->ifc_idx].data_fmt_spec;
2872  ifc_idx = tcp_ifc_priv->ifc_idx;
2873  sock_d = tcp_ifc_priv->clients[client_idx].sd;
2874  } else {
2875  neg_result = NEG_RES_FAILED;
2876  goto out_neg_exit;
2877  }
2878 
2879  // Prepare hello_msg header with output interfaces data_type and data_fmt_spec size
2880  hello_msg_header = calloc(1, sizeof(hello_msg_header_t));
2881  // Check whether the output interfaces data format and data specifier are set correctly. If not, negotiation will fail.
2882  if (((data_type == TRAP_FMT_UNIREC || data_type == TRAP_FMT_JSON) && data_fmt_spec == NULL) || data_type == TRAP_FMT_UNKNOWN) {
2883  /**
2884  * In case of file output interface, return NEG_RES_FMT_UNKNOWN
2885  * In case of tcpip or unix output interface, send hello message header with format unknown value and return NEG_RES_FMT_UNKNOWN
2886  */
2887  VERBOSE(CL_VERBOSE_LIBRARY, "Output interface negotiation - the data format or specifier of the output interface %d are not set correctly.", ifc_idx);
2888  neg_result = NEG_RES_FMT_UNKNOWN;
2889  if (ifc_type == TRAP_IFC_TYPE_FILE) {
2890  goto out_neg_exit;
2891  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_TLS || ifc_type == TRAP_IFC_TYPE_UNIX) {
2892  VERBOSE(CL_VERBOSE_LIBRARY, "Output interface negotiation - gonna send header with TRAP_FMT_UNKNOWN.");
2893  hello_msg_header->data_type = TRAP_FMT_UNKNOWN;
2894  hello_msg_header->data_fmt_spec_size = 0;
2895  }
2896  } else {
2897  hello_msg_header->data_type = data_type;
2898  if (data_type == TRAP_FMT_RAW) {
2899  hello_msg_header->data_fmt_spec_size = 0;
2900  } else {
2901  hello_msg_header->data_fmt_spec_size = strlen(data_fmt_spec);
2902  }
2903  }
2904 
2905  hello_msg_header_t tmp = *hello_msg_header;
2906  tmp.data_fmt_spec_size = htonl(hello_msg_header->data_fmt_spec_size);
2907 
2908  memcpy(buffer, &tmp, sizeof(hello_msg_header_t));
2909  size = sizeof(hello_msg_header_t);
2910  p = buffer;
2911 
2912  VERBOSE(CL_VERBOSE_LIBRARY, "Step 1: sending hello msg header... ");
2913  if (ifc_type == TRAP_IFC_TYPE_FILE) {
2914  ret_val = fwrite((void *) p, sizeof(char), size, file_ifc_priv->fd);
2915  compare = size;
2916 #if HAVE_OPENSSL
2917  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
2918  ret_val = SSL_write(tls_ifc_priv->clients[client_idx].ssl, p, size);
2919  if (ret_val > 0) {
2920  compare = ret_val;
2921  } else {
2922  compare = ret_val + 1;
2923  }
2924 #endif
2925  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
2926  ret_val = service_send_data(sock_d, size, (void **)&p);
2927  compare = TRAP_E_OK;
2928  }
2929  if (ret_val != compare) {
2930  // Could not send hello message header
2931  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR");
2932  neg_result = NEG_RES_FAILED;
2933  goto out_neg_exit;
2934  } else {
2935  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
2936  }
2937 
2938  // Data format specifier is sent only if the data format is set to JSON or UNIREC
2939  if ((data_type == TRAP_FMT_UNIREC || data_type == TRAP_FMT_JSON) && data_fmt_spec != NULL) {
2940  VERBOSE(CL_VERBOSE_LIBRARY, "Step 2: sending data_fmt_spec... ");
2941  if (hello_msg_header->data_fmt_spec_size == 0) { // JSON can have empty string as format specifier
2942  VERBOSE(CL_VERBOSE_LIBRARY, "SKIPPED because data_fmt_spec_size is 0.");
2943  goto out_neg_exit;
2944  }
2945  memset(buffer, 0, sizeof(hello_msg_header_t));
2946  if ((strlen(data_fmt_spec) + 1) > size_of_buffer) {
2947  buffer = (char *) realloc(buffer, (strlen(data_fmt_spec) + 1) * sizeof(char));
2948  memset(buffer + size_of_buffer, 0, ((strlen(data_fmt_spec) + 1) - size_of_buffer) * sizeof(char));
2949  size_of_buffer = (strlen(data_fmt_spec) + 1);
2950  }
2951  sprintf(buffer,"%s",data_fmt_spec);
2952  size = hello_msg_header->data_fmt_spec_size;
2953  p = buffer;
2954 
2955  if (ifc_type == TRAP_IFC_TYPE_FILE) {
2956  ret_val = fwrite((void *) p, sizeof(char), size, file_ifc_priv->fd);
2957  compare = size;
2958 #if HAVE_OPENSSL
2959  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
2960  ret_val = SSL_write(tls_ifc_priv->clients[client_idx].ssl, p, size);
2961  if (ret_val > 0) {
2962  compare = ret_val;
2963  } else {
2964  compare = ret_val + 1;
2965  }
2966 #endif
2967  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
2968  ret_val = service_send_data(sock_d, size, (void **)&p);
2969  compare = TRAP_E_OK;
2970  }
2971  if (ret_val != compare) {
2972  // Could not send output interface data specifier
2973  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR");
2974  neg_result = NEG_RES_FAILED;
2975  goto out_neg_exit;
2976  } else {
2977  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
2978  }
2979  }
2980 
2981 out_neg_exit:
2982  if (buffer != NULL) {
2983  free(buffer);
2984  buffer = NULL;
2985  }
2986  if (hello_msg_header != NULL) {
2987  free (hello_msg_header);
2988  hello_msg_header = NULL;
2989  }
2990 
2991  return neg_result;
2992 }
2993 
2994 
2995 int input_ifc_negotiation(void *ifc_priv_data, char ifc_type)
2996 {
2997  VERBOSE(CL_VERBOSE_LIBRARY, "--- Input IFC negotiation ---");
2998 
2999  uint32_t size = 0;
3000  hello_msg_header_t *hello_msg_header = calloc(1, sizeof(hello_msg_header_t));
3001  int ret_val = 0;
3002  void *p_p = NULL;
3003  int neg_result = 0;
3004  int compare = 0;
3005 
3006  file_private_t *file_ifc_priv = NULL;
3007 #if HAVE_OPENSSL
3008  tls_receiver_private_t *tls_ifc_priv = NULL;
3009 #endif
3010  tcpip_receiver_private_t *tcp_ifc_priv = NULL;
3011  uint8_t req_data_type = TRAP_FMT_UNKNOWN;
3012  char *req_data_fmt_spec = NULL;
3013  char *current_data_fmt_spec = NULL;
3014  char *recv_data_fmt_spec = NULL;
3015 
3016  // Decide which structure can be used for interfaces private data
3017  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3018  file_ifc_priv = (file_private_t *) ifc_priv_data;
3019  req_data_type = file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].req_data_type;
3020  req_data_fmt_spec = file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].req_data_fmt_spec;
3021  current_data_fmt_spec = file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].data_fmt_spec;
3022 #if HAVE_OPENSSL
3023  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3024  tls_ifc_priv = (tls_receiver_private_t *) ifc_priv_data;
3025  req_data_type = tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].req_data_type;
3026  req_data_fmt_spec = tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].req_data_fmt_spec;
3027  current_data_fmt_spec = tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].data_fmt_spec;
3028 #endif
3029  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3030  tcp_ifc_priv = (tcpip_receiver_private_t *) ifc_priv_data;
3031  req_data_type = tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].req_data_type;
3032  req_data_fmt_spec = tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].req_data_fmt_spec;
3033  current_data_fmt_spec = tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].data_fmt_spec;
3034  } else {
3035  neg_result = NEG_RES_FAILED;
3036  goto in_neg_exit;
3037  }
3038 
3039 
3040  /** Receive hello msg header with data_type and data_fmt_spec_size */
3041  VERBOSE(CL_VERBOSE_LIBRARY, "Step 1: reading hello msg header... ");
3042  size = sizeof(hello_msg_header_t);
3043  p_p = (void *) hello_msg_header;
3044 
3045  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3046  ret_val = fread(p_p, sizeof(char), size, file_ifc_priv->fd);
3047  compare = size;
3048  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3049  ret_val = service_get_data(tcp_ifc_priv->sd, size, &p_p);
3050  compare = TRAP_E_OK;
3051 #if HAVE_OPENSSL
3052  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3053  do {
3054  ret_val = SSL_read(tls_ifc_priv->ssl, p_p, size);
3055  if (ret_val > 0) {
3056  compare = ret_val;
3057  } else if (ret_val == -1) {
3058  ret_val = SSL_get_error(tls_ifc_priv->ssl, ret_val);
3059  if (ret_val == SSL_ERROR_WANT_READ) {
3060  ret_val = -1;
3061  }
3062  } else {
3063  compare = ret_val + 1;
3064  }
3065  } while (ret_val == -1);
3066 #endif
3067  }
3068  if (ret_val != compare) {
3069  // Could not receive hello message header
3070  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR");
3071  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3072  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3073  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3074  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3075 #if HAVE_OPENSSL
3076  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3077  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3078 #endif
3079  }
3080  neg_result = NEG_RES_FAILED;
3081  goto in_neg_exit;
3082  } else {
3083  hello_msg_header->data_fmt_spec_size = ntohl(hello_msg_header->data_fmt_spec_size);
3084 
3085  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
3086  VERBOSE(CL_VERBOSE_LIBRARY, "sender's data_type: %"PRIu8, hello_msg_header->data_type);
3087  VERBOSE(CL_VERBOSE_LIBRARY, "sender's data_fmt_spec_size: %"PRIu32, hello_msg_header->data_fmt_spec_size);
3088  VERBOSE(CL_VERBOSE_LIBRARY, "receiver's data_type: %"PRIu8, req_data_type);
3089  }
3090 
3091 
3092  /** Compare data_type */
3093  // What if input interface has no specified data format or data specifier? TODO!!!
3094  VERBOSE(CL_VERBOSE_LIBRARY, "Step 2: data types comparison... ");
3095  if (hello_msg_header->data_type == TRAP_FMT_UNKNOWN) {
3096  // Received unknown data type in hello message header from senders interface
3097  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR - sender's output interface has unknown data format");
3098  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3099  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3100  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3101  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3102 #if HAVE_OPENSSL
3103  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3104  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3105 #endif
3106  }
3107  neg_result = NEG_RES_FMT_UNKNOWN;
3108  goto in_neg_exit;
3109  } else if (hello_msg_header->data_type != req_data_type) {
3110  // Senders and receivers interface data types are not the same
3111  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR - mismatch of sender's output and receiver's input interface data types");
3112  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3113  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3114  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3115  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3116 #if HAVE_OPENSSL
3117  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3118  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3119 #endif
3120  }
3121  neg_result = NEG_RES_FMT_MISMATCH;
3122  goto in_neg_exit;
3123  } else if (req_data_type == TRAP_FMT_RAW) {
3124  // Both interfaces (senders output and receivers input) have RAW data format -> receive message with the data right after negotiation
3125  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3126  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_OK;
3127  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3128  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_OK;
3129 #if HAVE_OPENSSL
3130  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3131  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_OK;
3132 #endif
3133  }
3134  neg_result = NEG_RES_CONT;
3135  } else {
3136  // Both interfaces (senders output and receivers input) have UNIREC or JSON data format, that's OK
3137  // If type is UNIREC, check data format specifier size (JSON can have empty specifier, but UNIREC don't)
3138  if (hello_msg_header->data_type == TRAP_FMT_UNIREC && hello_msg_header->data_fmt_spec_size <= 0) {
3139  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR - received zero size of UNIREC data format specifier.");
3140  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3141  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3142  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3143  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3144 #if HAVE_OPENSSL
3145  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3146  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3147 #endif
3148  }
3149  neg_result = NEG_RES_FMT_MISMATCH;
3150  goto in_neg_exit;
3151  }
3152  }
3153  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
3154 
3155 
3156  /** Receive data_fmt_spec */
3157  // data_fmt_spec is received only in case of UNIREC and JSON data formats
3158  if (hello_msg_header->data_type == TRAP_FMT_UNIREC || hello_msg_header->data_type == TRAP_FMT_JSON) {
3159  VERBOSE(CL_VERBOSE_LIBRARY, "Step 3: receiving sender's data_fmt_spec... ");
3160  size = hello_msg_header->data_fmt_spec_size;
3161  recv_data_fmt_spec = calloc(size+1, sizeof(char));
3162  p_p = (void *) recv_data_fmt_spec;
3163 
3164  if (hello_msg_header->data_fmt_spec_size > 0) {
3165  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3166  ret_val = fread(p_p, sizeof(char), size, file_ifc_priv->fd);
3167  compare = size;
3168  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3169  ret_val = service_get_data(tcp_ifc_priv->sd, size, &p_p);
3170  compare = TRAP_E_OK;
3171 #if HAVE_OPENSSL
3172  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3173  ret_val = SSL_read(tls_ifc_priv->ssl, p_p, size);
3174  if (ret_val > 0) {
3175  compare = ret_val;
3176  } else {
3177  compare = ret_val + 1;
3178  }
3179 #endif
3180  }
3181 
3182  if (ret_val != compare) {
3183  // Could not receive data formate specifier
3184  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR");
3185  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3186  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3187  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3188  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3189 #if HAVE_OPENSSL
3190  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3191  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_WAITING;
3192 #endif
3193  }
3194  neg_result = NEG_RES_FAILED;
3195  free(recv_data_fmt_spec);
3196  recv_data_fmt_spec = NULL;
3197  goto in_neg_exit;
3198  } else {
3199  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
3200  }
3201  } else { // data_fmt_spec_size == 0
3202  *(char*)p_p = 0; // set to empty string
3203  VERBOSE(CL_VERBOSE_LIBRARY, "SKIPPED because data_fmt_spec_size is 0.");
3204  }
3205  VERBOSE(CL_VERBOSE_LIBRARY, "sender's data_fmt_spec: \"%s\"", recv_data_fmt_spec);
3206  VERBOSE(CL_VERBOSE_LIBRARY, "receiver's data_fmt_spec: \"%s\"", req_data_fmt_spec);
3207 
3208 
3209  /**Compare data_fmt_spec */
3210  VERBOSE(CL_VERBOSE_LIBRARY, "Step 4: comparing senders data_fmt_spec and receivers required data_fmt_spec... ");
3211  if (hello_msg_header->data_type == TRAP_FMT_UNIREC) {
3212  ret_val = trap_ctx_cmp_data_fmt(recv_data_fmt_spec, req_data_fmt_spec);
3213  } else {
3214  // For JSON, misamtch occurs if recevier's format is non-empty and formats are different
3215  ret_val = (req_data_fmt_spec == NULL || req_data_fmt_spec[0] == 0 ||
3216  /*recv_data_fmt_spec == NULL || recv_data_fmt_spec[0] == 0 ||*/ // Uncomment this to enable sender's empty format to match anything
3217  strcmp(req_data_fmt_spec, recv_data_fmt_spec) == 0
3219  }
3220  if (ret_val == TRAP_E_FIELDS_MISMATCH) {
3221  // senders and receivers ifc data_fmt_specs are not same
3222  VERBOSE(CL_VERBOSE_LIBRARY, "ERROR");
3223  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3224  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3225  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3226  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3227 #if HAVE_OPENSSL
3228  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3229  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_MISMATCH;
3230 #endif
3231  }
3232  neg_result = NEG_RES_FMT_MISMATCH;
3233  free(recv_data_fmt_spec);
3234  recv_data_fmt_spec = NULL;
3235  goto in_neg_exit;
3236  } else if (ret_val == TRAP_E_FIELDS_SUBSET) {
3237  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
3238  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3239  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3240  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3241  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3242 #if HAVE_OPENSSL
3243  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3244  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3245 #endif
3246  }
3247  neg_result = NEG_RES_RECEIVER_FMT_SUBSET;
3248  } else {
3249  VERBOSE(CL_VERBOSE_LIBRARY, "OK");
3250  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3251  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_OK;
3252  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3253  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_OK;
3254 #if HAVE_OPENSSL
3255  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3256  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_OK;
3257 #endif
3258  }
3259  neg_result = NEG_RES_CONT;
3260  if (current_data_fmt_spec != NULL) {
3261  VERBOSE(CL_VERBOSE_LIBRARY, "Step 5: comparing old and new sender's data_fmt_spec (not first negotiation)... ");
3262  VERBOSE(CL_VERBOSE_LIBRARY, "old data_fmt_spec: \"%s\"", current_data_fmt_spec);
3263  VERBOSE(CL_VERBOSE_LIBRARY, "new data_fmt_spec: \"%s\"", recv_data_fmt_spec);
3264  if (hello_msg_header->data_type == TRAP_FMT_UNIREC) {
3265  ret_val = trap_ctx_cmp_data_fmt(current_data_fmt_spec, recv_data_fmt_spec);
3266  } else {
3267  ret_val = (strcmp(current_data_fmt_spec, recv_data_fmt_spec) != 0 ? 1 /* CHANGE */ : TRAP_E_OK);
3268  }
3269  if (ret_val != TRAP_E_OK) {
3270  VERBOSE(CL_VERBOSE_LIBRARY, "CHANGE");
3271  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3272  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3273  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3274  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3275 #if HAVE_OPENSSL
3276  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3277  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state = FMT_CHANGED;
3278 #endif
3279  }
3280  if (hello_msg_header->data_type == TRAP_FMT_UNIREC) {
3281  neg_result = NEG_RES_SENDER_FMT_SUBSET;
3282  } else {
3283  neg_result = NEG_RES_FMT_CHANGED;
3284  }
3285  } else {
3286  VERBOSE(CL_VERBOSE_LIBRARY, "SAME");
3287  }
3288  }
3289  }
3290  }
3291 
3292  /** Save senders data_type and data_fmt_spec */
3293  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3294  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].data_type = hello_msg_header->data_type;
3295  if (file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].data_fmt_spec != NULL) {
3296  free(file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].data_fmt_spec);
3297  }
3298  file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].data_fmt_spec = recv_data_fmt_spec;
3299  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3300  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].data_type = hello_msg_header->data_type;
3301  if (tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].data_fmt_spec != NULL) {
3302  free(tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].data_fmt_spec);
3303  }
3304  tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].data_fmt_spec = recv_data_fmt_spec;
3305 #if HAVE_OPENSSL
3306  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3307  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].data_type = hello_msg_header->data_type;
3308  if (tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].data_fmt_spec != NULL) {
3309  free(tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].data_fmt_spec);
3310  }
3311  tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].data_fmt_spec = recv_data_fmt_spec;
3312 #endif
3313  }
3314 
3315 in_neg_exit:
3316  if (ifc_type == TRAP_IFC_TYPE_FILE) {
3317  VERBOSE(CL_VERBOSE_LIBRARY, "input ifc state after connecting: %d", file_ifc_priv->ctx->in_ifc_list[file_ifc_priv->ifc_idx].client_state);
3318  } else if (ifc_type == TRAP_IFC_TYPE_TCPIP || ifc_type == TRAP_IFC_TYPE_UNIX) {
3319  VERBOSE(CL_VERBOSE_LIBRARY, "input ifc state after connecting: %d", tcp_ifc_priv->ctx->in_ifc_list[tcp_ifc_priv->ifc_idx].client_state);
3320 #if HAVE_OPENSSL
3321  } else if (ifc_type == TRAP_IFC_TYPE_TLS) {
3322  VERBOSE(CL_VERBOSE_LIBRARY, "input ifc state after connecting: %d", tls_ifc_priv->ctx->in_ifc_list[tls_ifc_priv->ifc_idx].client_state);
3323 #endif
3324  }
3325 
3326  if (hello_msg_header != NULL) {
3327  free(hello_msg_header);
3328  hello_msg_header = NULL;
3329  }
3330 
3331  return neg_result;
3332 }
3333 
3334 // Local variables:
3335 // c-basic-offset: 3
3336 // End:
ifc_get_id_func_t get_id
Pointer to get_id function.
Definition: trap_ifc.h:182
uint8_t com
Definition: trap.c:2137
void trap_free_ctx_t(trap_ctx_priv_t **ctx)
Definition: trap.c:1258
int trap_get_data_fmt(uint8_t ifc_dir, uint32_t in_ifc_idx, uint8_t *data_type, const char **spec)
Definition: trap.c:2714
Set interface timeout (int32_t): in microseconds for non-blocking mode; timeout can be also: TRAP_WAI...
Definition: trap.h:201
#define TRAP_E_OK
Success, no error.
Definition: trap.h:87
int trap_ctx_get_in_ifc_state(trap_ctx_t *ctx, uint32_t ifc_idx)
Definition: trap.c:2719
int trap_ctx_set_required_fmt(trap_ctx_t *ctx, uint32_t in_ifc_idx, uint8_t data_type,...)
Definition: trap.c:2602
int create_tls_receiver_ifc(trap_ctx_priv_t *ctx, char *params, trap_input_ifc_t *ifc, uint32_t idx)
Constructor of input TCP/IP IFC module. This function is called by TRAP library to initialize one inp...
Definition: ifc_tls.c:738
#define MAX_ERROR_MSG_BUFF_SIZE
Definition: trap_internal.h:57
char * trap_get_param_by_delimiter(const char *source, char **dest, const char delimiter)
Splitter of params string. Cut the first param, copy it into dest and returns pointer to the start of...
Definition: trap.c:1160
#define TRAP_IFC_TIMEOUT
size of default timeout on output interfaces in microseconds
char * data_fmt_spec
Definition: trap_ifc.h:218
int trap_ctx_cmp_data_fmt(const char *sender_ifc_data_fmt, const char *receiver_ifc_data_fmt)
Definition: trap.c:2765
ifc_get_client_stats_json_func_t get_client_stats_json
Pointer to get_client_stats_json function.
Definition: trap_ifc.h:244
#define NEG_RES_SENDER_FMT_SUBSET
If the data format of input and output interfaces is the same and new data specifier of the output in...
Definition: trap_internal.h:76
trap_ctx_t * trap_ctx_init3(const char *name, const char *description, int8_t i_ifcs, int8_t o_ifcs, const char *ifc_spec, const char *service_ifc_name)
Initialize and return the context of libtrap.
Definition: trap.c:1731
Internal functions and macros for libtrap Verbose and debug macros from libcommlbr.
char * req_data_fmt_spec
Definition: trap_ifc.h:231
#define trap_ctx_t
Definition: trap.h:59
#define TRAP_IFC_PARAM_DELIMITER
Definition: trap.h:165
int create_tcpip_receiver_ifc(trap_ctx_priv_t *ctx, char *params, trap_input_ifc_t *ifc, uint32_t idx, enum tcpip_ifc_sockettype type)
Constructor of input TCP/IP IFC module. This function is called by TRAP library to initialize one inp...
Definition: ifc_tcpip.c:636
const char trap_version[]
#define TRAP_E_FORMAT_CHANGED
Returned by trap_recv when format or format spec of the receivers interface has been changed...
Definition: trap.h:100
#define TRAP_NO_WAIT
Definition: trap.h:119
int trap_last_error
Code of last error (one of the codes above)
Definition: trap.c:123
pthread_mutex_t ifc_mtx
Locking mutex for interface.
Definition: trap_ifc.h:246
char * trap_default_socket_path_format
#define X(param, text, align, cut)
char * get_module_name(void)
Definition: trap.c:852
static void print_aligned_multiline(const char *s, uint16_t align, uint16_t cut)
Definition: trap.c:788
static void remove_setter_from_param(char *params, char *setter)
Definition: trap.c:1482
char trap_help_spec
Definition: trap.c:102
#define NEG_RES_FAILED
If receiving the data from output interface fails or sending the data to input interface fails...
Definition: trap_internal.h:84
ifc_autoflush_t * ifc_autoflush_timeout
struct msg_header_s msg_header_t
void trap_json_print_string(char *str)
Definition: trap.c:670
const char * trap_last_error_msg
Human-readable message about last error.
Definition: trap.c:125
volatile int ifc_change
#define TRAP_E_BAD_IFC_INDEX
Interface index out of range.
Definition: trap.h:91
uint32_t ifc_idx
Definition: ifc_file.h:80
trap_ctx_priv_t * ctx
Definition: ifc_file.h:66
Set timeout of automatic buffer flushing for interface, expects uint64_t argument with number of micr...
Definition: trap.h:199
void trap_set_abs_timespec(struct timeval *tm, struct timespec *tmnblk)
Internal function for setting of timeout structs according to libtrap timeout.
Definition: trap.c:1190
int service_send_data(int sock_d, uint32_t size, void **data)
Definition: trap.c:2168
void trap_set_timeouts(int timeout, struct timeval *tm, struct timespec *tmnblk)
Internal function for setting of timeout structs according to libtrap timeout.
Definition: trap.c:1211
const char * trap_get_type_and_name_from_string(const char *source, const char **name, const char **type, int *length_name, int *length_type)
Definition: trap.c:2739
static uint16_t get_terminal_width()
Definition: trap.c:833
void trap_convert_module_info_to_json(const trap_module_info_t *info)
Definition: trap.c:688
ifc_get_id_func_t get_id
Pointer to get_id function.
Definition: trap_ifc.h:236
uint32_t num_ifc_in
#define TRAP_E_FIELDS_MISMATCH
Returned when receiver fields are not subset of sender fields.
Definition: trap.h:98
int trap_ctx_vifcctl(trap_ctx_t *ctx, int8_t type, uint32_t ifcidx, int32_t request, va_list ap)
Control TRAP interface.
Definition: trap.c:2032
Structure for TLS IFC private information.
#define TRAP_IFC_TYPE_BLACKHOLE
trap_ifc_dummy blackhole (output)
Definition: trap.h:172
const char * trap_ctx_get_last_error_msg(trap_ctx_t *ctx)
Get last (error) message from libtrap context.
Definition: trap.c:2108
#define TRAP_E_HELP
Returned by parse_parameters when help is requested.
Definition: trap.h:97
char * buffer_pointer
Internal pointer to current message in buffer.
Definition: trap_ifc.h:189
TRAP file interfaces.
TRAP TCP/IP interfaces private structures.
static void handle_outifc_setters(trap_output_ifc_t *ifc, char *params)
Definition: trap.c:1600
int trap_ctx_send(trap_ctx_t *ctx, unsigned int ifc, const void *data, uint16_t size)
Send data via output interface.
Definition: trap.c:1448
int trap_update_module_param(trap_module_info_t *m, uint16_t param_id, char shortopt, const char *longopt, const char *desc, int req_arg, const char *arg_type)
Definition: trap.c:203
int output_ifc_negotiation(void *ifc_priv_data, char ifc_type, uint32_t client_idx)
Definition: trap.c:2833
trap_ctx_priv_t * ctx
int trap_get_in_ifc_state(uint32_t ifc_idx)
Definition: trap.c:2734
void trap_set_help_section(int level)
Definition: trap.c:324
#define UNIX_PATH_FILENAME_FORMAT
Definition: ifc_tcpip.h:64
static int trap_read_from_buffer(trap_ctx_priv_t *ctx, uint32_t ifc_idx, const void **data, uint16_t *size, int timeout)
Definition: trap.c:253
const char * default_err_msg[256]
Definition: trap_error.c:49
static int trapifc_in_construct(trap_ctx_priv_t *ctx, trap_ifc_spec_t *ifc_spec, int idx)
Definition: trap.c:1542
use UNIX socket as a service interface
Definition: ifc_tcpip.h:73
char error_msg_buffer[MAX_ERROR_MSG_BUFF_SIZE]
Definition: trap.c:127
#define TRAP_E_TERMINATED
Interface was terminated during reading/writing.
Definition: trap.h:94
volatile int terminated
int create_blackhole_ifc(trap_ctx_priv_t *ctx, char *params, trap_output_ifc_t *ifc)
Definition: ifc_dummy.c:227
void trap_check_global_vars(void)
Definition: trap.c:138
uint64_t * counter_dropped_message
trap_ctx_priv_t * trap_create_ctx_t()
Definition: trap.c:1251
ifc_create_dump_func_t create_dump
Pointer to function for generating of dump.
Definition: trap_ifc.h:242
static int trapifc_out_construct(trap_ctx_priv_t *ctx, trap_ifc_spec_t *ifc_spec, int idx)
Definition: trap.c:1675
int create_file_send_ifc(trap_ctx_priv_t *ctx, const char *params, trap_output_ifc_t *ifc, uint32_t idx)
Allocate and initiate file output interface. This function is called by TRAP library to initialize on...
Definition: ifc_file.c:765
#define TRAP_HALFWAIT
Definition: trap.h:130
char ifc_type
Type of interface.
Definition: trap_ifc.h:249
pthread_mutex_t ifc_mtx
Locking mutex for interface.
Definition: trap_ifc.h:193
#define NEG_RES_FMT_CHANGED
If the data format has changed (for JSON type, UNIREC type uses *SUBSET variants) ...
Definition: trap_internal.h:78
char * data_fmt_spec
Definition: trap_ifc.h:277
void trap_get_internal_buffer(trap_ctx_priv_t *ctx, uint16_t ifc_idx, const void **data, uint32_t *size)
Get pointer to data stored in buffer (with headers) and mark buffer as clean.
Definition: trap.c:599
#define VERBOSE(level, format, args...)
TRAP TCP/IP interfaces private structures.
int trap_init(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec)
Definition: trap.c:526
uint32_t num_ifc_out
void trap_ctx_vset_data_fmt(trap_ctx_t *ctx, uint32_t out_ifc_idx, uint8_t data_type, va_list ap)
Definition: trap.c:2516
trap_ctx_priv_t * ctx
#define DEFAULT_MAX_TERMINAL_WIDTH
Definition: trap_internal.h:62
static int trap_errorf(trap_ctx_priv_t *ctx, int err_num, const char *msg,...)
Definition: trap_error.h:92
int service_get_data(int sock_d, uint32_t size, void **data)
Definition: trap.c:2141
int trap_finalize()
Definition: trap.c:578
uint8_t data[0]
trap_in_ifc_state_t client_state
Definition: trap_ifc.h:205
int trap_ifcctl(int8_t type, uint32_t ifcidx, int32_t request,...)
Control TRAP interface.
Definition: trap.c:1231
int create_tls_sender_ifc(trap_ctx_priv_t *ctx, const char *params, trap_output_ifc_t *ifc, uint32_t idx)
Constructor of output TCP/IP IFC module. This function is called by TRAP library to initialize one ou...
Definition: ifc_tls.c:1883
ifc_get_client_count_func_t get_client_count
Pointer to get_client_count function.
Definition: trap_ifc.h:243
#define NEG_RES_CONT
If the data format and data specifier of input and output interface are the same (input interface can...
Definition: trap_internal.h:74
void trap_ctx_send_flush(trap_ctx_t *ctx, uint32_t ifc)
Force flush of buffer.
Definition: trap.c:2115
uint8_t req_data_type
Definition: trap_ifc.h:223
#define TRAP_IFC_TYPE_GENERATOR
trap_ifc_dummy generator (input)
Definition: trap.h:171
ifc_disconn_clients_func_t disconn_clients
Pointer to disconnect_clients function.
Definition: trap_ifc.h:237
int trap_ctx_get_client_count(trap_ctx_t *ctx, uint32_t ifcidx)
Get number of connected clients.
Definition: trap.c:2495
void trap_send_flush(uint32_t ifc)
Force flush of buffer.
Definition: trap.c:1241
pthread_t service_thread
int service_thread_initialized
char datatimeout_fixed
Definition: trap_ifc.h:269
Structure for TCP/IP IFC private information.
interface acts as source of data for module
Definition: trap.h:184
ifc_terminate_func_t terminate
Pointer to terminate function.
Definition: trap_ifc.h:184
int trap_ctx_ifcctl(trap_ctx_t *ctx, int8_t type, uint32_t ifcidx, int32_t request,...)
Control TRAP interface.
Definition: trap.c:2019
#define TRAP_E_BAD_FPARAMS
Bad parameters of function.
Definition: trap.h:92
use UNIX socket for local communication
Definition: ifc_tcpip.h:72
#define TRAP_E_INITIALIZED
TRAP library already initilized.
Definition: trap.h:89
char bufferswitch
Enable (1) or Disable (0) buffering, default is Enabled (1).
Definition: trap_ifc.h:250
uint64_t * counter_recv_message
#define TRAP_IFC_TYPE_TCPIP
trap_ifc_tcpip (input&output part)
Definition: trap.h:173
int trap_ctx_finalize(trap_ctx_t **ctx)
Terminate libtrap context and free resources.
Definition: trap.c:1409
int trap_ctx_recv(trap_ctx_t *ctx, uint32_t ifcidx, const void **data, uint16_t *size)
Read data from input interface.
Definition: trap.c:1379
static void handle_inifc_setters(trap_input_ifc_t *ifc, char *params)
Definition: trap.c:1506
Structure for TCP/IP IFC client information.
use TCP/IP connection
Definition: ifc_tcpip.h:71
int trap_ctx_vset_required_fmt(trap_ctx_t *ctx, uint32_t in_ifc_idx, uint8_t data_type, va_list ap)
Definition: trap.c:2565
pthread_mutex_t error_mtx
int create_file_recv_ifc(trap_ctx_priv_t *ctx, const char *params, trap_input_ifc_t *ifc, uint32_t idx)
Allocate and initiate file input interface. This function is called by TRAP library to initialize one...
Definition: ifc_file.c:432
TRAP TCP/IP interfaces.
ifc_destroy_func_t destroy
Pointer to destructor function.
Definition: trap_ifc.h:185
int32_t datatimeout
Timeout for *_send() calls.
Definition: trap_ifc.h:248
uint8_t data_type
Definition: trap_ifc.h:282
ifc_send_func_t send
Pointer to send function.
Definition: trap_ifc.h:238
#define SERVICE_GET_COM
Signaling a request for module statistics (interfaces stats - received messages and buffers...
Definition: trap_internal.h:65
int32_t datatimeout
Timeout for *_recv() calls.
Definition: trap_ifc.h:191
char bufferswitch_fixed
Definition: trap_ifc.h:262
int trap_ctx_get_last_error(trap_ctx_t *ctx)
Get last result code from libtrap context.
Definition: trap.c:2102
trap_ctx_priv_t * trap_glob_ctx
Definition: trap.c:120
trap_module_info_t * trap_create_module_info(const char *mname, const char *mdesc, int8_t i_ifcs, int8_t o_ifcs, uint16_t param_count)
Definition: trap.c:184
#define TRAP_IFC_DELIMITER
Definition: trap.h:160
#define NEG_RES_FMT_UNKNOWN
If the output interface has not specified data format.
Definition: trap_internal.h:85
uint32_t buffer_unread_bytes
Number of unread bytes in buffer.
Definition: trap_ifc.h:190
#define TRAP_IFC_TYPE_TLS
trap_ifc_tls (input&output part)
Definition: trap.h:174
int trap_ctx_get_data_fmt(trap_ctx_t *ctx, uint8_t ifc_dir, uint32_t ifc_idx, uint8_t *data_type, const char **spec)
Definition: trap.c:2617
int trap_get_verbose_level()
Definition: trap.c:663
const char * trap_last_error_msg
void trap_set_verbose_level(int level)
Definition: trap.c:654
trap_ctx_t * trap_ctx_init2(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec, const char *service_ifc_name)
Initialize and return the context of libtrap.
Definition: trap.c:1802
const char * trap_help_ifcspec
ifc_recv_func_t recv
Pointer to receive function.
Definition: trap_ifc.h:183
uint64_t * recv_delay_timestamp
void * trap_get_global_ctx()
Definition: trap.c:2820
#define NEG_RES_FMT_MISMATCH
If the data format or data specifier of input and output interfaces does not match.
Definition: trap_internal.h:77
char * service_ifc_name
int trap_parse_params(int *argc, char **argv, trap_ifc_spec_t *ifc_spec)
Definition: trap.c:339
int trap_free_ifc_spec(trap_ifc_spec_t ifc_spec)
Definition: trap.c:497
ifc_create_dump_func_t create_dump
Pointer to function for generating of dump.
Definition: trap_ifc.h:186
Enable/disable buffering - could be dangerous on input interface!!! expects char argument with value ...
Definition: trap.h:200
int trap_send_data(unsigned int ifcidx, const void *data, uint16_t size, int timeout)
Definition: trap.c:618
uint64_t * counter_recv_delay_total
char datatimeout_fixed
Definition: trap_ifc.h:200
char * buffer
Internal pointer to buffer for messages.
Definition: trap_ifc.h:188
int64_t timeout
Internal structure to send partial data after timeout (autoflush).
Definition: trap_ifc.h:247
int trap_verbose
Definition: trap_internal.c:57
Error handling for TRAP.
struct hello_msg_header_s hello_msg_header_t
#define TRAP_E_MEMORY
Memory allocation error.
Definition: trap.h:104
#define NEG_RES_OK
Signaling success (hello message successfully sent to input interface)
Definition: trap_internal.h:81
char ifc_type
Type of interface.
Definition: trap_ifc.h:192
void trap_free_global_vars(void)
Definition: trap.c:171
int trap_ctx_terminate(trap_ctx_t *ctx)
Terminate libtrap context.
Definition: trap.c:1342
int encode_cnts_to_json(char **data, trap_ctx_priv_t *ctx)
Definition: trap.c:2192
void trap_set_data_fmt(uint32_t out_ifc_idx, uint8_t data_type,...)
Definition: trap.c:2693
uint32_t data_size
Definition: trap.c:2138
ifc_destroy_func_t destroy
Pointer to destructor function.
Definition: trap_ifc.h:241
int create_tcpip_sender_ifc(trap_ctx_priv_t *ctx, const char *params, trap_output_ifc_t *ifc, uint32_t idx, enum tcpip_ifc_sockettype type)
Constructor of output TCP/IP IFC module. This function is called by TRAP library to initialize one ou...
Definition: ifc_tcpip.c:1730
void trap_ctx_create_ifc_dump(trap_ctx_t *ctx, const char *path)
Create dump files.
Definition: trap.c:2473
uint64_t * counter_recv_buffer
int trap_terminate()
Definition: trap.c:563
ifc_terminate_func_t terminate
Pointer to terminate function.
Definition: trap_ifc.h:240
int trap_recv(uint32_t ifcidx, const void **data, uint16_t *size)
Receive data from input interface.
Definition: trap.c:631
int trap_set_required_fmt(uint32_t in_ifc_idx, uint8_t data_type,...)
Definition: trap.c:2702
uint64_t * counter_recv_delay_last
#define ifcdir2str(type)
Definition: trap.c:130
char ** environ
static int trap_error(trap_ctx_priv_t *ctx, int err_num)
Definition: trap_error.h:63
#define TRAP_E_TIMEOUT
Read or write operation timeout.
Definition: trap.h:88
TRAP dummy interfaces (generator and blackhole)
#define DEFAULT_SOCKET_FORMAT
Definition: ifc_tcpip.h:55
char ** params
Definition: trap.h:215
uint64_t * counter_autoflush
#define NEG_RES_RECEIVER_FMT_SUBSET
If the data format of input and output interfaces is the same and data specifier of the input interfa...
Definition: trap_internal.h:75
Definition: trap.h:247
int create_generator_ifc(trap_ctx_priv_t *ctx, char *params, trap_input_ifc_t *ifc)
Definition: ifc_dummy.c:113
#define TRAP_E_NOT_SELECTED
Interface was not selected reading/writing.
Definition: trap.h:95
#define TRAP_IFC_TYPE_UNIX
trap_ifc_tcpip via UNIX socket(input&output part)
Definition: trap.h:175
static uint64_t get_cur_timestamp()
Definition: trap.c:1370
void trap_print_help(const trap_module_info_t *module_info)
Definition: trap.c:898
trap_ctx_t * trap_ctx_init(trap_module_info_t *module_info, trap_ifc_spec_t ifc_spec)
Initialize and return the context of libtrap.
Definition: trap.c:1786
ifc_flush_func_t flush
Pointer to flush function.
Definition: trap_ifc.h:239
#define TRAP_IFC_TYPE_FILE
trap_ifc_file (input&output part)
Definition: trap.h:177
char * types
Definition: trap.h:214
uint32_t data_fmt_spec_size
#define SEND_DATA()
Definition: trap.c:609
#define TRAP_NO_AUTO_FLUSH
value to disable autoflushing on output interface
Definition: trap.h:134
#define TRAP_WAIT
Definition: trap.h:124
static void print_aligned(const char *s, uint16_t align, uint16_t cut)
Definition: trap.c:723
void * priv
Pointer to instance&#39;s private data.
Definition: trap_ifc.h:187
uint64_t * counter_send_buffer
int input_ifc_negotiation(void *ifc_priv_data, char ifc_type)
Definition: trap.c:2995
ifc_is_conn_func_t is_conn
Pointer to is_connected function.
Definition: trap_ifc.h:181
#define TRAP_E_NOT_INITIALIZED
TRAP library not initilized.
Definition: trap.h:103
void trap_ctx_set_data_fmt(trap_ctx_t *ctx, uint32_t out_ifc_idx, uint8_t data_type,...)
Definition: trap.c:2551
int trap_check_buffer_content(void *buffer, uint32_t buffer_size)
Check content of buffer, iterate over message headers.
Definition: trap.c:222
void * priv
Pointer to instance&#39;s private data.
Definition: trap_ifc.h:245
trap_output_ifc_t * out_ifc_list
static char * get_param_by_delimiter(const char *source, char **dest, const char delimiter)
Definition: trap.c:1185
FILE * fd
Definition: ifc_file.h:67
Interface of TRAP interfaces.
#define TRAP_E_FIELDS_SUBSET
Returned when receivers fields are subset of senders fields and both sets are not identical...
Definition: trap.h:99
uint64_t * counter_send_message
const char trap_git_version[]
uint8_t data_type
Definition: trap_ifc.h:210
#define SERVICE_OK_REPLY
A value used as a reply signaling success.
Definition: trap_internal.h:67
const char trap_version [] __attribute__((used))
trap_input_ifc_t * in_ifc_list
void * service_thread_routine(void *arg)
Definition: trap.c:2294
#define TRAP_E_BADPARAMS
Bad parameters passed to interface initializer.
Definition: trap.h:90
#define DEBUG_BUF(X)
void trap_print_ifc_spec_help()
Definition: trap.c:1138
interface is used for sending data out of module
Definition: trap.h:185
#define TRAP_IFC_MESSAGEQ_SIZE
size of message queue used for buffering
Definition: trap.h:206
#define TRAP_IFC_TYPE_SERVICE
service ifc
Definition: trap.h:176
int trap_send(uint32_t ifcidx, const void *data, uint16_t size)
Send data via output interface.
Definition: trap.c:624
char trap_ifc_type_supported[]
Definition: trap.c:107