Libtrap: Internal development docs  1.16.1
ifc_tls.c
Go to the documentation of this file.
1 /**
2  * \file ifc_tls.c
3  * \brief TRAP TCP with TLS interfaces
4  * \author Tomas Cejka <cejkat@cesnet.cz>
5  * \author Jaroslav Hlavac <hlavaj20@fit.cvut.cz>
6  * \date 2018
7  */
8 /*
9  * Copyright (C) 2013-2018 CESNET
10  *
11  * LICENSE TERMS
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in
20  * the documentation and/or other materials provided with the
21  * distribution.
22  * 3. Neither the name of the Company nor the names of its contributors
23  * may be used to endorse or promote products derived from this
24  * software without specific prior written permission.
25  *
26  * ALTERNATIVELY, provided that this notice is retained in full, this
27  * product may be distributed under the terms of the GNU General Public
28  * License (GPL) version 2 or later, in which case the provisions
29  * of the GPL apply INSTEAD OF those given above.
30  *
31  * This software is provided ``as is'', and any express or implied
32  * warranties, including, but not limited to, the implied warranties of
33  * merchantability and fitness for a particular purpose are disclaimed.
34  * In no event shall the company or contributors be liable for any
35  * direct, indirect, incidental, special, exemplary, or consequential
36  * damages (including, but not limited to, procurement of substitute
37  * goods or services; loss of use, data, or profits; or business
38  * interruption) however caused and on any theory of liability, whether
39  * in contract, strict liability, or tort (including negligence or
40  * otherwise) arising in any way out of the use of this software, even
41  * if advised of the possibility of such damage.
42  *
43  */
44 
45 #define _GNU_SOURCE
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <netinet/in.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/socket.h>
53 #include <sys/un.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <inttypes.h>
59 #include <pthread.h>
60 #include <errno.h>
61 #include <semaphore.h>
62 #include <assert.h>
63 
64 #include <openssl/ssl.h>
65 #include <openssl/err.h>
66 #include <openssl/bio.h>
67 #include <openssl/pem.h>
68 #include <openssl/x509.h>
69 #include <openssl/x509_vfy.h>
70 
71 
72 #include "../include/libtrap/trap.h"
73 #include "trap_internal.h"
74 #include "trap_ifc.h"
75 #include "trap_error.h"
76 #include "ifc_tls.h"
77 #include "ifc_tls_internal.h"
78 #include "ifc_socket_common.h"
79 
80 /**
81  * \addtogroup trap_ifc TRAP communication module interface
82  * @{
83  */
84 /**
85  * \addtogroup tls_ifc TLS communication interface module
86  * @{
87  */
88 
89 #define MAX_RECOVERY_TRY 10
90 /* must be smaller than 1000000 */
91 #define RECOVERY_WAIT_USEC 500000
92 #define USEC_IN_SEC 1000000
93 #define ACK_MESS_SIZE 1
94 #define CRIT_1VS2SEND 10000
95 #ifndef MAX
96 #define MAX(a,b) ((a)<(b)?(b):(a))
97 #endif
98 #ifndef MIN
99 #define MIN(a,b) ((a)>(b)?(b):(a))
100 #endif
101 
102 static SSL_CTX *tlsserver_create_context()
103 {
104  const SSL_METHOD *method;
105  SSL_CTX *ctx;
106 
107  method = SSLv23_server_method();
108 
109  ctx = SSL_CTX_new(method);
110  if (!ctx) {
111  perror("Unable to create SSL context");
112  ERR_print_errors_fp(stderr);
113  return NULL;
114  }
115 
116 #if defined(SSL_CTX_set_ecdh_auto)
117  SSL_CTX_set_ecdh_auto(ctx, 1);
118 #else
119  SSL_CTX_set_tmp_ecdh(ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
120 #endif
121 
122  return ctx;
123 }
124 
125 static SSL_CTX *tlsclient_create_context()
126 {
127  const SSL_METHOD *method;
128  SSL_CTX *ctx = NULL;
129 
130  method = SSLv23_client_method();
131 
132  ctx = SSL_CTX_new(method);
133  if (!ctx) {
134  perror("Unable to create SSL context");
135  ERR_print_errors_fp(stderr);
136  }
137 
138  return ctx;
139 }
140 
141 /**
142  * \brief Verify context of ssl.
143  * \param[in] arg pointer to SSL (usually stored in tls_receiver_private_t resp. in an array of tlsclient_s inside tls_sender_private_t for input resp. output IFC)
144  * \return 1 on failure, 0 on success
145  * Disabling undesired versions of TLS/SSL and adding supported CAs to SSL_CTX.
146  */
147 static int verify_certificate(SSL *arg)
148 {
149  X509 *cert = NULL;
150  int ret = 0;
151 
152  cert = SSL_get_peer_certificate(arg);
153  if (cert == NULL) {
154  VERBOSE(CL_ERROR, "Could not retrieve peer certificate file.");
155  return EXIT_FAILURE;
156  }
157 
158  if (SSL_get_verify_result(arg) == X509_V_OK) {
159  ret = EXIT_SUCCESS;
160  } else {
161  ret = EXIT_FAILURE;
162  }
163 
164  X509_free(cert);
165  return ret;
166 }
167 
168 /**
169  * \brief Configure context of ssl server.
170  * \param[in] cert path to certfile
171  * \param[in] ctx ssl context to be configured
172  * \return 1 on failure, 0 on success
173  * Disabling undesired versions of TLS/SSL and adding supported CAs to SSL_CTX.
174  */
175 static int tls_server_configure_ctx(const char *cert, SSL_CTX *ctx)
176 {
177  X509* certificate = X509_new();
178  BIO* bio_cert = BIO_new_file(cert, "r");
179 
180  PEM_read_bio_X509(bio_cert, &certificate, NULL, NULL);
181  if (certificate == NULL) {
182  VERBOSE(CL_ERROR, "Could not load certificate file.");
183  return EXIT_FAILURE;
184  }
185  if (SSL_CTX_add_client_CA(ctx, certificate) != 1) {
186  VERBOSE(CL_ERROR, "Could not add certificate to SSL_CTX.");
187  return EXIT_FAILURE;
188  }
189  /* disabling undesired versions of TLS */
190  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
191  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
192  SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
193  SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1);
194 
195  X509_free(certificate);
196  BIO_free_all(bio_cert);
197  return EXIT_SUCCESS;
198 }
199 
200 /**
201  * \brief Configure ssl context of new connection.
202  * \param[in] ctx ssl context to be configured
203  * \param[in] key path to keyfile
204  * \param[in] crt path to certfile
205  * \param[in] ca path to CA file
206  * \return 1 on failure, 0 on success
207  * Loading certificate and key to SSL_CTX. Setting location of CA that is used for verification of
208  * incomming certificates. Also forcing peer to send it's certificate.
209  */
210 static int tls_configure_ctx(SSL_CTX *ctx, const char *key, const char *crt, const char *ca)
211 {
212  int ret;
213 
214  /* Set the key and cert */
215  ret = SSL_CTX_use_certificate_chain_file(ctx, crt);
216  if (ret != 1) {
217  VERBOSE(CL_ERROR, "Loading certificate (%s) failed. %s",
218  crt, ERR_reason_error_string(ERR_get_error()));
219  return EXIT_FAILURE;
220  }
221 
222  ret = SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM);
223  if (ret != 1) {
224  VERBOSE(CL_ERROR, "Loading private key (%s) failed: %s",
225  key, ERR_reason_error_string(ERR_get_error()));
226  return EXIT_FAILURE;
227  }
228 
229  if (SSL_CTX_check_private_key(ctx) == 0) {
230  VERBOSE(CL_ERROR, "Private key does not match the certificate public key.");
231  return EXIT_FAILURE;
232  }
233 
234 
235  if (SSL_CTX_load_verify_locations(ctx, ca, NULL) != 1) {
236  VERBOSE(CL_ERROR, "Could not load CA location used for verification.");
237  return EXIT_FAILURE;
238  }
239  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
240 
241  return EXIT_SUCCESS;
242 }
243 
244 /***** TCPIP server *****/
245 
246 /**
247  * Internal union for host address storage, common for tcpip & unix
248  */
250  struct addrinfo tls_addr; ///< used for TCPIP socket
251  struct sockaddr_un unix_addr; ///< used for path of UNIX socket
252 };
253 
254 static int client_socket_connect(tls_receiver_private_t *priv, struct timeval *tv);
255 static void client_socket_disconnect(void *priv);
256 static int server_socket_open(void *priv);
257 
258 /**
259  * \brief Get sockaddr, IPv4 or IPv6
260  * \param[in] sa structure with input socket address
261  * \return converted ponter to address
262  */
263 static void *get_in_addr(struct sockaddr *sa)
264 {
265  if (sa->sa_family == AF_INET) {
266  return &(((struct sockaddr_in*)sa)->sin_addr);
267  }
268 
269  return &(((struct sockaddr_in6*)sa)->sin6_addr);
270 }
271 
272 /**
273  * \addtogroup tls_receiver TLS Input IFC
274  * @{
275  */
276 /* Receiver (client socket) */
277 // Receiver is a client that connects itself to the source of data (to sender) = server
278 
279 /**
280  * Receive data
281  * \param[in] priv private IFC data
282  * \param[out] data received data
283  * \param[in,out] size expected size to wait for, it is used to return size that was not read
284  * \param[in] tm timeout
285  */
286 static int receive_part(void *priv, void **data, uint32_t *size, struct timeval *tm)
287 {
288  void *data_p = (*data);
290  ssize_t numbytes = *size;
291  int recvb, retval;
292  fd_set set;
293 
294  assert(data_p != NULL);
295 
296  while (config->is_terminated == 0) {
297  DEBUG_IFC(if (tm) {VERBOSE(CL_VERBOSE_LIBRARY, "Try to receive data in timeout %" PRIu64
298  "s%"PRIu64"us", tm->tv_sec, tm->tv_usec)});
299 
300  FD_ZERO(&set);
301  FD_SET(config->sd, &set);
302  /*
303  * Blocking or with timeout?
304  * With timeout 0,0 - non-blocking
305  */
306  retval = select(config->sd + 1, &set, NULL, NULL, tm);
307  if (retval > 0) {
308  if (FD_ISSET(config->sd, &set)) {
309  do {
310  recvb = SSL_read(config->ssl, data_p, numbytes);
311  if (recvb < 1) {
312  if (recvb == 0) {
313  errno = EPIPE;
314  }
315  switch (errno) {
316  case EINTR:
317  VERBOSE(CL_ERROR, "EINTR occured");
318  if (config->is_terminated == 1) {
320  return TRAP_E_TERMINATED;
321  }
322  break;
323  case EBADF:
324  case EPIPE:
326  return TRAP_E_IO_ERROR;
327  case EAGAIN:
328  (*size) = numbytes;
329  (*data) = data_p;
330  return TRAP_E_TIMEOUT;
331  }
332  }
333  numbytes -= recvb;
334  data_p += recvb;
335  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "receive_part got %" PRId32 "B", recvb));
336  } while (numbytes > 0);
337  (*size) = numbytes;
338  (*data) = data_p;
339  return TRAP_E_OK;
340  } else {
341  continue;
342  }
343  } else if (retval == 0) {
344  VERBOSE(CL_VERBOSE_LIBRARY, "Timeout elapsed - non-blocking call used.");
345  (*size) = numbytes;
346  return TRAP_E_TIMEOUT;
347  } else if (retval < 0 && errno == EINTR) { /* signal received */
348  /** \todo continue with timeout minus time already waited */
349  VERBOSE(CL_VERBOSE_BASIC, "select interrupted");
350  continue;
351  } else { /* some error has occured */
352  VERBOSE(CL_VERBOSE_OFF, "select() returned %i (%s)", retval, strerror(errno));
354  return TRAP_E_IO_ERROR;
355  }
356  }
357  return TRAP_E_TERMINATED;
358 }
359 
360 /**
361  * \brief Receive data from interface.
362  *
363  * It is expected that data is always the same pointer because it is buffer given by trap.c.
364  *
365  * This function contains finite state machine that controls receiving messages (header
366  * and payload), handles timeouts and sleep (to offload CPU during waiting for connection).
367  * The transition graph is:
368  * \dot
369  * digraph fsm { label="tls_receiver_recv()";labelloc=t;
370  * init -> conn_wait;
371  * init -> head_wait;
372  * init -> mess_wait;
373  * discard -> reset;
374  * reset -> init;
375  * reset -> init;
376  * reset -> reset;
377  * reset -> init;
378  * conn_wait -> reset;
379  * conn_wait -> head_wait;
380  * head_wait -> discard;
381  * head_wait -> reset;
382  * head_wait -> reset;
383  * head_wait -> mess_wait;
384  * mess_wait -> discard;
385  * mess_wait -> reset;
386  * }
387  * \enddot
388  *
389  * \param [in,out] priv private configuration structure
390  * \param [out] data where received data are stored
391  * \param [out] size size of received data
392  * \param [in] timeout timeout in usec, can be TRAP_WAIT, TRAP_HALFWAIT, or TRAP_NO_WAIT
393  * \return TRAP_E_OK (0) on success
394  */
395 int tls_receiver_recv(void *priv, void *data, uint32_t *size, int timeout)
396 {
397 #ifdef LIMITED_RECOVERY
398  uint32_t recovery = 0;
399 #endif
400  /** messageframe contains header that is read (even partially) in HEAD_WAIT */
401  trap_buffer_header_t messageframe;
403  void *p = &messageframe;
404  struct timeval tm, *temptm;
405  int retval;
406  /* first timestamp for global timeout in this function...
407  * in the RESET state, we should check the timeout given by caller
408  * with elapsed time from entry_time.
409  * Timeout is in microseconds... */
410  struct timespec spec_time;
411 
412  clock_gettime(CLOCK_MONOTONIC, &spec_time);
413  /* entry_time is in microseconds seconds -> secs * microsends + nanoseconds */
414  uint64_t entry_time = spec_time.tv_sec * 1000000 + (spec_time.tv_nsec / 1000);
415  uint64_t curr_time = 0;
416 
417  /* sleeptime (in usec) with sleeptimespec are used to wait
418  * for a while before next connecting when non-blocking. */
419  uint64_t sleeptime;
420  struct timespec sleeptimespec;
421 
422  /* correct module will pass only possitive timeout or TRAP_WAIT.
423  * TRAP_HALFWAIT is not valid value */
424  assert(timeout > TRAP_HALFWAIT);
425 
426  if ((config == NULL) || (data == NULL) || (size == NULL)) {
427  return TRAP_E_BAD_FPARAMS;
428  }
429  (*size) = 0;
430 
431  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv trap_recv() was called"));
432 
433  /* convert libtrap timeout into timespec and timeval */
434  trap_set_timeouts(timeout, &tm, NULL);
435  temptm = (timeout==TRAP_WAIT?NULL:&tm);
436 
437  while (config->is_terminated == 0) {
438 init:
439  p = &messageframe;
440  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv INIT"));
441  if (config->connected == 0) {
442  goto conn_wait;
443  } else {
444  if (config->data_pointer == NULL) {
445  goto head_wait;
446  } else {
447  /* continue where we timedout earlier */
448  p = config->data_pointer;
449  goto mess_wait;
450  }
451  }
452 discard:
453  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv DISCARD"));
454  config->data_pointer = NULL;
455  goto reset;
456 reset:
457  if (config->is_terminated != 0) {
458  /* TRAP_E_TERMINATED is returned outside the loop */
459  break;
460  }
461  /* failure, next state is exit when we are non-blocking or INIT on blocking,
462  this state is a great place for handling timeouts. */
463  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv RESET"));
464  if (timeout == TRAP_WAIT) {
465 #ifdef LIMITED_RECOVERY
466  if (++recovery > MAX_RECOVERY_TRY) {
467  goto init;
468  } else {
469  return TRAP_E_TIMEOUT;
470  }
471 #else
472  goto init;
473 #endif
474  } else {
475  /* non-blocking mode, let's check elapsed time */
476  clock_gettime(CLOCK_MONOTONIC, &spec_time);
477  curr_time = spec_time.tv_sec * 1000000 + (spec_time.tv_nsec / 1000);
478  if ((curr_time - entry_time) >= timeout) {
479  return TRAP_E_TIMEOUT;
480  } else {
481  if (config->connected == 0) {
482  /* wait at most 1 second before return to INIT */
483 
484  /* sleeptime is in usec */
485  sleeptime = timeout - (curr_time - entry_time);
486  /* if remaining sleeptime is higher than 1s, use 1s */
487  if (sleeptime < 1000000) {
488  sleeptimespec.tv_sec = sleeptime / 1000000;
489  sleeptimespec.tv_nsec = (sleeptime % 1000000) * 1000;
490  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "sleep time set %" PRIu64
491  " us: %"PRIu64"s%"PRIu64"ns", sleeptime,
492  sleeptimespec.tv_sec, sleeptimespec.tv_nsec));
493  } else {
494  sleeptimespec.tv_sec = 1;
495  sleeptimespec.tv_nsec = 0;
496  }
497  /* We are not interested in reminder, because timeout will be
498  * checked again later. */
499  if (nanosleep(&sleeptimespec, NULL) == -1) {
500  if (errno == EINTR) {
501  goto reset;
502  } else {
503  VERBOSE(CL_ERROR, "recv nanosleep(): %s", strerror(errno));
504  }
505  }
506  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv nanosleep finished"));
507  }
508 
509  /* update timeout that is used for recv after successful connection */
510  clock_gettime(CLOCK_MONOTONIC, &spec_time);
511  curr_time = spec_time.tv_sec * 1000000 + (spec_time.tv_nsec / 1000);
512  sleeptime = timeout - (int) (curr_time - entry_time);
513  if ((int) sleeptime > 0) {
514  trap_set_timeouts(sleeptime, &tm, NULL);
515  } else {
516  return TRAP_E_TIMEOUT;
517  }
518 
519  goto init;
520  }
521  }
522 conn_wait:
523  /* check if connected -> try to connect -> check if connected; next state is RESET or HEAD_WAIT */
524  /* expected next state is waiting for header */
525  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv CONN_WAIT"));
526  if (config->connected == 0) {
527  /* we don't have connection, we must try to connect before accepting header */
528  retval = client_socket_connect(config, temptm);
529  if (retval == TRAP_E_FIELDS_MISMATCH) {
530  config->connected = 1;
531  return TRAP_E_FORMAT_MISMATCH;
532  } else if (retval == TRAP_E_OK) {
533  config->connected = 1;
534  /* ok, wait for header as we planned */
535  } else if (TRAP_E_BAD_CERT) {
536  /* TODO replace with TRAP_E_IO_ERROR and change it in test_echo_reply.c */
537  return TRAP_E_TERMINATED;
538  } else {
539  /* failed, reseting... */
540  if (timeout == TRAP_WAIT) {
541  /* Create a delay when blocking...
542  * This is specific situation, many attempts would be unpleasant */
543  sleep(1);
544  }
545  goto reset;
546  }
547  }
548  goto head_wait;
549 head_wait:
550  /* get and check header of message, next state can be MESS_WAIT or RESET */
551  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv HEAD_WAIT (%p)", p));
552  config->data_wait_size = sizeof(trap_buffer_header_t);
553  retval = receive_part(config, &p, &config->data_wait_size, temptm);
554  if (retval != TRAP_E_OK) {
555  /* receiving failed */
556  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv failed HEAD (%p) waiting %d B", p, config->data_wait_size));
557  if (retval == TRAP_E_IO_ERROR) {
558  /* disconnected -> drop data */
559  goto discard;
560  }
561  goto reset;
562  } else {
563  /* we expect to receive data */
564  messageframe.data_length = ntohl(messageframe.data_length);
565  config->data_wait_size = messageframe.data_length;
566  config->ext_buffer_size = messageframe.data_length;
567 #ifdef ENABLE_CHECK_HEADER
568  /* check if header is ok: */
569  if (tls_check_header(&messageframe) == 0) {
570  goto reset;
571  }
572 #endif
573  /* we got header, now we can start receiving payload */
574  p = data;
575  config->ext_buffer = data;
576  goto mess_wait;
577  }
578 mess_wait:
579  /* get and check payload of message, next state can be RESET or success exit */
580  /* receive payload */
581  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv waiting MESS (%p) %d B", p, config->data_wait_size));
582  retval = receive_part(config, &p, &config->data_wait_size, temptm);
583  if (retval == TRAP_E_OK) {
584  /* Success! Data was already set by recv */
585  config->data_pointer = NULL;
586  (*size) = messageframe.data_length;
587  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv get MESS (%p) remains: %d B", p, config->data_wait_size));
588  return TRAP_E_OK;
589  } else {
590  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv get MESS (%p) still waiting for %d B", p, config->data_wait_size));
591  if (retval == TRAP_E_IO_ERROR) {
592  /* disconnected -> drop data */
593  goto discard;
594  }
595  config->data_pointer = p;
596  goto reset;
597  }
598  }
599  return TRAP_E_TERMINATED;
600 }
601 
602 /**
603  * \brief Set interface state as terminated.
604  * \param[in] priv pointer to module private data
605  */
606 void tls_receiver_terminate(void *priv)
607 {
609  if (config != NULL) {
610  config->is_terminated = 1;
611  } else {
612  VERBOSE(CL_ERROR, "Bad parameter of tls_receiver_terminate()!");
613  }
614  return;
615 }
616 
617 
618 /**
619  * \brief Destructor of TLS receiver (input ifc)
620  * \param[in] priv pointer to module private data
621  */
622 void tls_receiver_destroy(void *priv)
623 {
625  if (config != NULL) {
626  if (config->connected == 1) {
627  close(config->sd);
628  }
629  free(config->ssl);
630  free(config->sslctx);
631  free(config->dest_addr);
632  free(config->dest_port);
633  free(config->keyfile);
634  free(config->certfile);
635  free(config->cafile);
636  free(config);
637  } else {
638  VERBOSE(CL_ERROR, "Destroying IFC that is probably not initialized.");
639  }
640  return;
641 }
642 
643 static void tls_receiver_create_dump(void *priv, uint32_t idx, const char *path)
644 {
646  /* return value */
647  int r;
648  /* config file trap-i<number>-config.txt */
649  char *conf_file = NULL;
650  /* config file trap-i<number>-buffer.dat */
651  char *buf_file = NULL;
652  FILE *f = NULL;
653  trap_buffer_header_t aux = { 0 };
654  aux.data_length = htonl(c->ext_buffer_size);
655 
656  r = asprintf(&conf_file, "%s/trap-i%02"PRIu32"-config.txt", path, idx);
657  if (r == -1) {
658  VERBOSE(CL_ERROR, "Not enough memory, dump failed. (%s:%d)", __FILE__, __LINE__);
659  conf_file = NULL;
660  goto exit;
661  }
662  f = fopen(conf_file, "w");
663  fprintf(f, "Dest addr: %s\nDest port: %s\nConnected: %d\n"
664  "Terminated: %d\nSocket descriptor: %d\n"
665  "Data pointer: %p\nData wait size: %"PRIu32"\nMessage header: %"PRIu32"\n"
666  "Extern buffer pointer: %p\nExtern buffer data size: %"PRIu32"\n"
667  "Timeout: %"PRId32"us (%s)\nPrivate key: %s\nCertificate: %s\n",
668  c->dest_addr, c->dest_port, c->connected, c->is_terminated, c->sd,
671  c->ctx->in_ifc_list[idx].datatimeout,
673  c->keyfile, c->certfile);
674  fclose(f);
675  f = NULL;
676 
677  r = asprintf(&buf_file, "%s/trap-i%02"PRIu32"-buffer.dat", path, idx);
678  if (r == -1) {
679  buf_file = NULL;
680  VERBOSE(CL_ERROR, "Not enough memory, dump failed. (%s:%d)", __FILE__, __LINE__);
681  goto exit;
682  }
683  f = fopen(buf_file, "w");
684  if (fwrite(&aux, sizeof(c->ext_buffer_size), 1, f) != 1) {
685  VERBOSE(CL_ERROR, "Writing buffer header failed. (%s:%d)", __FILE__, __LINE__);
686  goto exit;
687  }
688  if (fwrite(c->ext_buffer, c->ext_buffer_size, 1, f) != 1) {
689  VERBOSE(CL_ERROR, "Writing buffer content failed. (%s:%d)", __FILE__, __LINE__);
690  goto exit;
691  }
692 exit:
693  if (f != NULL) {
694  fclose(f);
695  }
696  free(conf_file);
697  free(buf_file);
698  return;
699 }
700 
701 char *tls_recv_ifc_get_id(void *priv)
702 {
703  if (priv == NULL) {
704  return NULL;
705  }
706 
708  if (config->dest_port == NULL) {
709  return NULL;
710  }
711  return config->dest_port;
712 }
713 
714 uint8_t tls_recv_ifc_is_conn(void *priv)
715 {
716  if (priv == NULL) {
717  return 0;
718  }
720  if (config->connected == 1) {
721  return 1;
722  }
723  return 0;
724 }
725 
726 /**
727  * \brief Constructor of input TCP/IP IFC module.
728  * This function is called by TRAP library to initialize one input interface.
729  *
730  * \param[in,out] ctx Pointer to the private libtrap context data (trap_ctx_init()).
731  * \param[in] params Configuration string containing space separated values of these parameters (in this exact order): *dest_addr* *dest_port*,
732  * where dest_addr is destination address of output TCP/IP IFC module and
733  * dest_port is the port where sender is listening.
734  * \param[in,out] ifc IFC interface used for calling TCP/IP module.
735  * \param[in] idx Index of IFC that is created.
736  * \return 0 on success (TRAP_E_OK)
737  */
738 int create_tls_receiver_ifc(trap_ctx_priv_t *ctx, char *params, trap_input_ifc_t *ifc, uint32_t idx)
739 {
740  int result = TRAP_E_OK;
741  char *param_iterator = NULL;
742  char *dest_addr = NULL;
743  char *dest_port = NULL;
744  char *keyfile = NULL;
745  char *certfile = NULL;
746  char *cafile = NULL;
747  tls_receiver_private_t *config = NULL;
748 
749  if (params == NULL) {
750  VERBOSE(CL_ERROR, "IFC requires at least three parameters (port:keyfile:certfile).");
751  return TRAP_E_BADPARAMS;
752  }
753 
754  config = (tls_receiver_private_t *) calloc(1, sizeof(tls_receiver_private_t));
755  if (config == NULL) {
756  VERBOSE(CL_ERROR, "Failed to allocate internal memory for input IFC.");
757  return TRAP_E_MEMORY;
758  }
759  config->ctx = ctx;
760  config->is_terminated = 0;
761  config->ifc_idx = idx;
762 
763  /* Parsing params */
764  param_iterator = trap_get_param_by_delimiter(params, &dest_addr, TRAP_IFC_PARAM_DELIMITER);
765  /* error! we expect 2 parameters */
766  if ((dest_addr == NULL) || (strlen(dest_addr) == 0)) {
767  VERBOSE(CL_ERROR, "Expected parameters: 'destination address:port:keyfile:certfile' are missing.");
768  result = TRAP_E_BADPARAMS;
769  goto failsafe_cleanup;
770  }
771  if (param_iterator != NULL) {
772  param_iterator = trap_get_param_by_delimiter(param_iterator, &dest_port, TRAP_IFC_PARAM_DELIMITER);
773  } else {
774  VERBOSE(CL_ERROR, "Missing 'dest_port', 'keyfile', 'certfile' and trusted 'CAfile' parameters.");
775  result = TRAP_E_BADPARAMS;
776  goto failsafe_cleanup;
777  }
778  if (param_iterator != NULL) {
779  param_iterator = trap_get_param_by_delimiter(param_iterator, &keyfile, TRAP_IFC_PARAM_DELIMITER);
780  } else {
781  VERBOSE(CL_ERROR, "Missing 'keyfile', 'certfile' and trusted 'CAfile' parameters.");
782  result = TRAP_E_BADPARAMS;
783  goto failsafe_cleanup;
784  }
785  if (param_iterator != NULL) {
786  param_iterator = trap_get_param_by_delimiter(param_iterator, &certfile, TRAP_IFC_PARAM_DELIMITER);
787  } else {
788  VERBOSE(CL_ERROR, "Missing 'certfile' and trusted 'CAfile' parameters.");
789  result = TRAP_E_BADPARAMS;
790  goto failsafe_cleanup;
791  }
792  if (param_iterator != NULL) {
793  param_iterator = trap_get_param_by_delimiter(param_iterator, &cafile, TRAP_IFC_PARAM_DELIMITER);
794  } else {
795  /* dest_addr skipped, move parameters */
796  cafile = certfile;
797  certfile = keyfile;
798  keyfile = dest_port;
799  dest_port = dest_addr;
800  dest_addr = strdup("localhost");
801  VERBOSE(CL_ERROR, "Only 3 parameters given, using 'localhost' as a destination address.");
802  }
803 
804  /* set global buffer size */
806  /* Parsing params ended */
807 
808  config->dest_addr = dest_addr;
809  config->dest_port = dest_port;
810  config->keyfile = keyfile;
811  config->certfile = certfile;
812  config->cafile = cafile;
813 
814  if ((config->dest_addr == NULL) || (config->dest_port == NULL)) {
815  /* no delimiter found even if we expect two parameters */
816  VERBOSE(CL_ERROR, "Malformed params for input IFC, missing destination address and port.");
817  result = TRAP_E_BADPARAMS;
818  goto failsafe_cleanup;
819  }
820 
821  VERBOSE(CL_VERBOSE_ADVANCED, "config:\ndest_addr=\"%s\"\ndest_port=\"%s\"\n"
822  "TDU size: %u\n", config->dest_addr, config->dest_port,
823  config->int_mess_header.data_length);
824 
825  config->sslctx = tlsclient_create_context();
826  if (config->sslctx == NULL) {
827  result = TRAP_E_MEMORY;
828  goto failsafe_cleanup;
829  }
830  if (tls_configure_ctx(config->sslctx, keyfile, certfile, cafile) == EXIT_FAILURE) {
831  result = TRAP_E_BADPARAMS;
832  goto failsafe_cleanup;
833  }
834 
835  /*
836  * In constructor, we do not know timeout yet.
837  * Use 5 seconds to wait for connection to output interface.
838  */
839 #ifndef ENABLE_NEGOTIATION
840  int retval = 0;
841  struct timeval tv = {5, 0};
842  retval = client_socket_connect(config, &tv);
843  if (retval != TRAP_E_OK) {
844  config->connected = 0;
845  if ((retval == TRAP_E_BAD_FPARAMS) || (retval == TRAP_E_IO_ERROR)) {
846  VERBOSE(CL_VERBOSE_BASIC, "Could not connect to sender due to bad parameters.");
847  result = TRAP_E_BADPARAMS;
848  goto failsafe_cleanup;
849  }
850  } else {
851  config->connected = 1;
852  }
853 #endif
854 
855  /* hook functions and store priv */
856  ifc->recv = tls_receiver_recv;
860  ifc->priv = config;
863 
864 #ifndef ENABLE_NEGOTIATION
865  if (config->connected == 0) {
866  VERBOSE(CL_VERBOSE_BASIC, "Could not connect to sender.");
867  if ((retval == TRAP_E_BAD_FPARAMS) || (retval == TRAP_E_IO_ERROR)) {
868  result = retval;
869  goto failsafe_cleanup;
870  }
871  }
872 #endif
873  return TRAP_E_OK;
874 failsafe_cleanup:
875  free(dest_addr);
876  free(dest_port);
877  free(keyfile);
878  free(certfile);
879  free(cafile);
880  if (config != NULL && config->sslctx != NULL) {
881  SSL_CTX_free(config->sslctx);
882  }
883  free(config);
884  return result;
885 }
886 
887 /**
888  * Disconnect from output IFC.
889  *
890  * \param[in,out] priv pointer to private structure of input IFC (client)
891  */
892 static void client_socket_disconnect(void *priv)
893 {
895  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv Disconnected."));
896  if (config->connected == 1) {
897  VERBOSE(CL_VERBOSE_BASIC, "TLS ifc client disconnecting");
898  SSL_free(config->ssl);
899  config->ssl = NULL;
900  close(config->sd);
901  config->connected = 0;
902  }
903 }
904 
905 /**
906  * Function waits for non-blocking connect().
907  *
908  * \param[in] sock socket descriptor of client
909  * \param[in] tv timeout
910  * \return TRAP_E_OK on success, TRAP_E_TIMEOUT on error (can be caused by interrupt)
911  */
912 static int wait_for_connection(int sock, struct timeval *tv)
913 {
914  int rv;
915  fd_set fdset;
916  FD_ZERO(&fdset);
917  FD_SET(sock, &fdset);
918  VERBOSE(CL_VERBOSE_LIBRARY, "wait for connection");
919 
920  rv = select(sock + 1, NULL, &fdset, NULL, tv);
921  if (rv == 1) {
922  int so_error;
923  socklen_t len = sizeof so_error;
924 
925  getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
926 
927  if (so_error == 0) {
928  return TRAP_E_OK;
929  }
930  }
931  return TRAP_E_TIMEOUT;
932 }
933 
934 
935 /**
936  * \brief client_socket is used as a receiver
937  * \param[in] c pointer to module private data
938  * \param[in] tv timeout
939  * \return TRAP_E_OK on success
940  */
941 static int client_socket_connect(tls_receiver_private_t *c, struct timeval *tv)
942 {
943  int sockfd = -1, options;
944  union tls_socket_addr addr;
945  struct addrinfo *servinfo, *p = NULL;
946  int rv, addr_count = 0;
947  char s[INET6_ADDRSTRLEN];
948 
949  if ((c == NULL) || (c->dest_addr == NULL) || (c->dest_port == NULL)) {
950  return TRAP_E_BAD_FPARAMS;
951  }
952 
953  memset(&addr, 0, sizeof(addr));
954 
955  addr.tls_addr.ai_family = AF_UNSPEC;
956  addr.tls_addr.ai_socktype = SOCK_STREAM;
957 
958  if ((rv = getaddrinfo(c->dest_addr, c->dest_port, &addr.tls_addr, &servinfo)) != 0) {
959  VERBOSE(CL_ERROR, "getaddrinfo: %s", gai_strerror(rv));
960  return TRAP_E_IO_ERROR;
961  }
962 
963  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv Try to connect"));
964 
965  if (tv != NULL) {
966  /* compute uniform intervals for all possible address */
967  for (p = servinfo; p != NULL; p = p->ai_next) {
968  addr_count++;
969  }
970  tv->tv_sec = (tv->tv_sec * 1000000 + tv->tv_usec) / addr_count;
971  tv->tv_usec = tv->tv_sec % 1000000;
972  tv->tv_sec /= 1000000;
973  VERBOSE(CL_VERBOSE_LIBRARY, "Every address will be tried for timeout: %"PRId64"s%"PRId64"us",
974  tv->tv_sec, tv->tv_usec);
975  }
976 
977  /* loop through all the results and connect to the first we can */
978  for (p = servinfo; p != NULL; p = p->ai_next) {
979  if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
980  continue;
981  }
982  if ((options = fcntl(sockfd, F_GETFL)) != -1) {
983  if (fcntl(sockfd, F_SETFL, O_NONBLOCK | options) == -1) {
984  VERBOSE(CL_ERROR, "Could not set socket to non-blocking.");
985  }
986  }
987  if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
988  if (errno != EINPROGRESS && errno != EAGAIN) {
989  DEBUG_IFC(VERBOSE(CL_VERBOSE_LIBRARY, "recv TLS ifc connect error %d (%s)", errno,
990  strerror(errno)));
991  close(sockfd);
992  sockfd = -1;
993  continue;
994  } else {
995  rv = wait_for_connection(sockfd, tv);
996  if (rv == TRAP_E_TIMEOUT) {
997  if (c->is_terminated) {
998  rv = TRAP_E_TERMINATED;
999  break;
1000  }
1001  /* try another address */
1002  close(sockfd);
1003  sockfd = -1;
1004  continue;
1005  } else {
1006  /* success */
1007  rv = TRAP_E_OK;
1008  break;
1009  }
1010  }
1011  }
1012  break;
1013  }
1014  /* there was no successfull connection for whole servinfo struct */
1015  if (p == NULL) {
1016  VERBOSE(CL_VERBOSE_LIBRARY, "recv client: Connection failed.");
1017  rv = TRAP_E_TIMEOUT;
1018  }
1019 
1020  /* catching all possible errors from setting up socket before atempting tls handshake */
1021  if (rv != TRAP_E_OK) {
1022  freeaddrinfo(servinfo);
1023  if (sockfd >= 0)
1024  close(sockfd);
1025  return rv;
1026  }
1027 
1028  if (p != NULL) {
1029  if (inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s) != NULL) {
1030  VERBOSE(CL_VERBOSE_LIBRARY, "recv client: connected to %s", s);
1031  }
1032  }
1033  freeaddrinfo(servinfo);
1034  servinfo = NULL;
1035 
1036  c->sd = sockfd;
1037  c->ssl = SSL_new(c->sslctx);
1038  if (c->ssl == NULL) {
1039  VERBOSE(CL_ERROR, "Creating SSL structure failed: %s", ERR_reason_error_string(ERR_get_error()));
1040  return TRAP_E_MEMORY;
1041  }
1042 
1043  /* setting tcp socket to be used for ssl connection */
1044  if (SSL_set_fd(c->ssl, c->sd) != 1) {
1045  VERBOSE(CL_ERROR, "Setting SSL file descriptor to tcp socket failed: %s",
1046  ERR_reason_error_string(ERR_get_error()));
1047  return TRAP_E_IO_ERROR;
1048  }
1049  SSL_set_connect_state(c->ssl);
1050 
1051  do {
1052  rv = SSL_connect(c->ssl);
1053  if (rv < 1) {
1054  rv = ERR_get_error();
1055  switch (rv) {
1056  case SSL_ERROR_NONE:
1057  case SSL_ERROR_WANT_CONNECT:
1058  case SSL_ERROR_WANT_X509_LOOKUP:
1059  case SSL_ERROR_WANT_READ:
1060  case SSL_ERROR_WANT_WRITE:
1061  break;
1062  default:
1063  VERBOSE(CL_ERROR, "SSL connection failed, could be wrong certificate. %s",
1064  ERR_reason_error_string(ERR_get_error()));
1065  SSL_free(c->ssl);
1066  c->ssl = NULL;
1067  close(c->sd);
1068  return TRAP_E_IO_ERROR;
1069  }
1070  }
1071  } while (rv < 1);
1072  VERBOSE(CL_VERBOSE_BASIC, "SSL successfully connected")
1073 
1074  int ret_ver = verify_certificate(c->ssl); /* server certificate verification */
1075  if (ret_ver != 0){
1076  VERBOSE(CL_VERBOSE_LIBRARY, "verify_certificate: failed to verify server's certificate");
1077  SSL_free(c->ssl);
1078  c->ssl = NULL;
1079  return TRAP_E_BAD_CERT;
1080  }
1081 
1082  /** Input interface negotiation */
1083 #ifdef ENABLE_NEGOTIATION
1085  case NEG_RES_FMT_UNKNOWN:
1086  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: failed (unknown data format of the output interface).");
1087  close(sockfd);
1088  return TRAP_E_TIMEOUT;
1089 
1090  case NEG_RES_CONT:
1091  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: success.");
1092  return TRAP_E_OK;
1093 
1094  case NEG_RES_FMT_CHANGED: /* used on format change with JSON */
1095  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: success (format has changed; it was not first negotiation).");
1096  return TRAP_E_OK;
1097 
1098  case NEG_RES_RECEIVER_FMT_SUBSET: /* used on format change with UniRec */
1099  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: success (required set of fields of the input interface is subset of the recevied format).");
1100  return TRAP_E_OK;
1101 
1102  case NEG_RES_SENDER_FMT_SUBSET: /* used on format change with UniRec */
1103  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: success (new recevied format specifier is subset of the old one; it was not first negotiation).");
1104  return TRAP_E_OK;
1105 
1106  case NEG_RES_FAILED:
1107  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: failed (error while receiving hello message from output interface).");
1109 
1110  case NEG_RES_FMT_MISMATCH:
1111  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: failed (data type or data format specifier mismatch).");
1112  return TRAP_E_FIELDS_MISMATCH;
1113 
1114  default:
1115  VERBOSE(CL_VERBOSE_LIBRARY, "Input_ifc_negotiation result: default case");
1116  break;
1117  }
1118 #endif
1119 
1120 
1121  return TRAP_E_OK;
1122 }
1123 
1124 /**
1125  * @}
1126  *//* tls_receiver */
1127 
1128 /**
1129  * \addtogroup tls_sender TLS Output IFC
1130  * @{
1131  */
1132 
1133 /**
1134  * \brief This function is called when a client was/is being disconnected.
1135  *
1136  * \param[in] priv Pointer to interface's private data structure.
1137  * \param[in] cl_id Index of the client in 'clients' array.
1138  */
1139 static inline void disconnect_client(tls_sender_private_t *priv, int cl_id)
1140 {
1141  int i;
1142  tlsclient_t *c = &priv->clients[cl_id];
1143 
1144  for (i = 0; i < priv->buffer_count; ++i) {
1145  del_index(&priv->buffers[i].clients_bit_arr, cl_id);
1146  if (priv->buffers[i].clients_bit_arr == 0) {
1147  pthread_cond_broadcast(&priv->cond_full_buffer);
1148  }
1149  }
1150  del_index(&priv->clients_bit_arr, cl_id);
1151  __sync_sub_and_fetch(&priv->connected_clients, 1);
1152 
1153  shutdown(c->sd, SHUT_RDWR);
1154  close(c->sd);
1155  SSL_free(c->ssl);
1156  c->sd = -1;
1157  c->ssl = NULL;
1158  c->pending_bytes = 0;
1159  c->sending_pointer = NULL;
1160 }
1161 
1162 /**
1163  * \brief Function disconnects all clients of the output interface whose private structure is passed via "priv" parameter.
1164  *
1165  * \param[in] priv Pointer to output interface private structure.
1166  */
1168 {
1169  uint32_t i;
1171 
1172  for (i = 0; i<c->clients_arr_size; i++) {
1173  if (c->clients[i].sd > 0) {
1174  disconnect_client(priv, i);
1175  }
1176  }
1177 }
1178 
1179 /**
1180  * Return current time in microseconds.
1181  *
1182  * This is used to get current timestamp in tls_sender_send().
1183  *
1184  * \return current timestamp
1185  */
1186 static inline uint64_t get_cur_timestamp()
1187 {
1188  struct timespec spec_time;
1189 
1190  clock_gettime(CLOCK_MONOTONIC, &spec_time);
1191  /* time in microseconds seconds -> secs * microsends + nanoseconds */
1192  return spec_time.tv_sec * 1000000 + (spec_time.tv_nsec / 1000);
1193 }
1194 
1195 /**
1196  * \brief This function runs in a separate thread and handles new client's connection requests.
1197  *
1198  * \param[in] arg Pointer to interface's private data structure.
1199  */
1200 static void *accept_clients_thread(void *arg)
1201 {
1202  char remoteIP[INET6_ADDRSTRLEN];
1203  struct sockaddr_storage remoteaddr; /* client address */
1204  struct tlsclient_s *cl;
1205  socklen_t addrlen;
1206  int newclient, fdmax;
1207  fd_set scset;
1209  int i;
1210  struct sockaddr *tmpaddr;
1211  uint32_t client_id = 0;
1212 
1213  /* handle new connections */
1214  addrlen = sizeof(remoteaddr);
1215  while (1) {
1216  if (c->is_terminated != 0) {
1217  break;
1218  }
1219  FD_ZERO(&scset);
1220  FD_SET(c->server_sd, &scset);
1221  fdmax = c->server_sd;
1222 
1223  if (select(fdmax + 1, &scset, NULL, NULL, NULL) == -1) {
1224  if (errno == EINTR) {
1225  if (c->is_terminated != 0) {
1226  break;
1227  }
1228  continue;
1229  } else {
1230  VERBOSE(CL_ERROR, "%s:%d unexpected error code %d", __func__, __LINE__, errno);
1231  }
1232  }
1233 
1234  if (FD_ISSET(c->server_sd, &scset)) {
1235  newclient = accept(c->server_sd, (struct sockaddr *) &remoteaddr, &addrlen);
1236  if (newclient == -1) {
1237  VERBOSE(CL_ERROR, "Accepting new client failed.");
1238  } else {
1239  tmpaddr = (struct sockaddr *) &remoteaddr;
1240  switch(((struct sockaddr *) tmpaddr)->sa_family) {
1241  case AF_INET:
1242  client_id = ntohs(((struct sockaddr_in *) tmpaddr)->sin_port);
1243  break;
1244  case AF_INET6:
1245  client_id = ntohs(((struct sockaddr_in6 *) tmpaddr)->sin6_port);
1246  break;
1247  }
1248  VERBOSE(CL_VERBOSE_ADVANCED, "New connection from %s on socket %d",
1249  inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*) &remoteaddr), remoteIP, INET6_ADDRSTRLEN),
1250  newclient);
1251 
1252  if (c->connected_clients < c->clients_arr_size) {
1253  cl = NULL;
1254  for (i = 0; i < c->clients_arr_size; ++i) {
1255  if (c->clients[i].sd < 1) {
1256  cl = &c->clients[i];
1257  break;
1258  }
1259  }
1260  if (cl == NULL) {
1261  goto refuse_client;
1262  }
1263  cl->ssl = SSL_new(c->sslctx);
1264  if (cl->ssl == NULL) {
1265  VERBOSE(CL_ERROR, "Creating SSL structure failed: %s", ERR_reason_error_string(ERR_get_error()));
1266  goto refuse_client;
1267  }
1268  if (SSL_set_fd(cl->ssl, newclient) != 1) {
1269  VERBOSE(CL_ERROR, "Setting SSL file descriptor to tcp socket failed: %s",
1270  ERR_reason_error_string(ERR_get_error()));
1271  SSL_free(cl->ssl);
1272  cl->ssl = NULL;
1273  goto refuse_client;
1274  }
1275 
1276  if (SSL_accept(cl->ssl) <= 0) {
1277  ERR_print_errors_fp(stderr);
1278  SSL_free(cl->ssl);
1279  cl->ssl = NULL;
1280  goto refuse_client;
1281  }
1282 
1283  /** Verifying SSL certificate of client. */
1284  int ret_ver = verify_certificate(cl->ssl);
1285  if (ret_ver != 0){
1286  VERBOSE(CL_VERBOSE_LIBRARY, "verify_certificate: failed to verify client's certificate");
1287  goto refuse_client;
1288  }
1289 
1290  cl->sd = newclient;
1291  cl->sending_pointer = NULL;
1292  cl->pending_bytes = 0;
1293  cl->timer_total = 0;
1294  cl->id = client_id;
1295  cl->assigned_buffer = c->active_buffer;
1296  cl->timeouts = 0;
1297 
1298 #ifdef ENABLE_NEGOTIATION
1299  int ret_val = output_ifc_negotiation(c, TRAP_IFC_TYPE_TLS, i);
1300  if (ret_val == NEG_RES_OK) {
1301  VERBOSE(CL_VERBOSE_LIBRARY, "Output_ifc_negotiation result: success.");
1302  } else if (ret_val == NEG_RES_FMT_UNKNOWN) {
1303  VERBOSE(CL_VERBOSE_LIBRARY, "Output_ifc_negotiation result: failed (unknown data format of this output interface -> refuse client).");
1304  cl->sd = -1;
1305  goto refuse_client;
1306  } else { // ret_val == NEG_RES_FAILED, sending the data to input interface failed, refuse client
1307  VERBOSE(CL_VERBOSE_LIBRARY, "Output_ifc_negotiation result: failed (error while sending hello message to input interface).");
1308  cl->sd = -1;
1309  goto refuse_client;
1310  }
1311 #endif
1312 
1313  set_index(&c->clients_bit_arr, i);
1314  __sync_add_and_fetch(&c->connected_clients, 1);
1315  } else {
1316 refuse_client:
1317  VERBOSE(CL_VERBOSE_LIBRARY, "Shutting down client we do not have additional resources (%u/%u)",
1319  shutdown(newclient, SHUT_RDWR);
1320  close(newclient);
1321  }
1322  }
1323  }
1324  }
1325  pthread_exit(NULL);
1326 }
1327 
1328 /**
1329  * \brief Write buffer size to its header and shift active index.
1330  *
1331  * \param[in] priv Pointer to output interface private structure.
1332  * \param[in] buffer Pointer to the buffer.
1333  */
1334 static inline void finish_buffer(tls_sender_private_t *priv, buffer_t *buffer)
1335 {
1337 
1338  if (buffer->clients_bit_arr == 0 && buffer->wr_index != 0) {
1339  uint32_t header = htonl(buffer->wr_index);
1340  memcpy(buffer->header, &header, sizeof(header));
1341 
1342  priv->active_buffer = (priv->active_buffer + 1) % priv->buffer_count;
1343 
1344  buffer->clients_bit_arr = priv->clients_bit_arr;
1345  buffer->wr_index = 0;
1346  }
1347 
1348  pthread_mutex_lock(&priv->mtx_no_data);
1349  pthread_cond_broadcast(&priv->cond_no_data);
1350  pthread_mutex_unlock(&priv->mtx_no_data);
1351 }
1352 
1353 /**
1354  * \brief Force flush of active buffer
1355  *
1356  * \param[in] priv pointer to interface private data
1357  */
1358 void tls_sender_flush(void *priv)
1359 {
1362 
1363  pthread_mutex_lock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1364 
1365  buffer_t *buffer = &c->buffers[c->active_buffer];
1366  if (buffer->clients_bit_arr == 0 && buffer->wr_index != 0) {
1367  finish_buffer(c, buffer);
1368  __sync_add_and_fetch(&c->ctx->counter_autoflush[c->ifc_idx], 1);
1369  }
1370 
1371  pthread_mutex_unlock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1372 }
1373 
1374 /**
1375  * \brief Send data to client from his assigned buffer.
1376  *
1377  * \param[in] priv Pointer to iterface's private data structure.
1378  * \param[in] c Pointer to the client's structure.
1379  * \param[in] cl_id Client's index in the 'clients' array.
1380  *
1381  * \return TRAP_E_OK successfully sent.
1382  * \return TRAP_E_TERMINATED TRAP was terminated.
1383  * \return TRAP_E_IO_ERROR send failed although TRAP was not terminated.
1384  */
1385 static inline int send_data(tls_sender_private_t *priv, tlsclient_t *c, uint32_t cl_id)
1386 {
1387  int sent;
1388  /* Pointer to client's assigned buffer */
1389  buffer_t *buffer = &priv->buffers[c->assigned_buffer];
1390 
1391 again:
1392  sent = SSL_write(c->ssl, c->sending_pointer, c->pending_bytes);
1393 
1394  if (sent < 0) {
1395  /* Send failed */
1396  if (priv->is_terminated != 0) {
1397  return TRAP_E_TERMINATED;
1398  }
1399  switch (SSL_get_error(c->ssl, sent)) {
1400  case SSL_ERROR_ZERO_RETURN:
1401  case SSL_ERROR_SYSCALL:
1402  return TRAP_E_IO_ERROR;
1403  case SSL_ERROR_WANT_READ:
1404  case SSL_ERROR_WANT_WRITE:
1405  goto again;
1406  default:
1407  VERBOSE(CL_VERBOSE_OFF, "Unhandled error from ssl_write in send_data");
1408  return TRAP_E_IO_ERROR;
1409  }
1410  } else {
1411  c->pending_bytes -= sent;
1412  c->sending_pointer = (uint8_t *) c->sending_pointer + sent;
1413 
1414  /* Client received whole buffer */
1415  if (c->pending_bytes <= 0) {
1416  del_index(&buffer->clients_bit_arr, cl_id);
1417  if (buffer->clients_bit_arr == 0) {
1418  __sync_add_and_fetch(&priv->ctx->counter_send_buffer[priv->ifc_idx], 1);
1419  pthread_cond_broadcast(&priv->cond_full_buffer);
1420  }
1421 
1422  /* Assign client the next buffer in sequence */
1423  c->assigned_buffer = (c->assigned_buffer + 1) % priv->buffer_count;
1424  }
1425  }
1426  return TRAP_E_OK;
1427 }
1428 
1429 /**
1430  * \brief This function runs in a separate thread. It handles sending data
1431  to connected clients for TLS interface.
1432  * \param[in] priv pointer to interface private data
1433  */
1434 static void *sending_thread_func(void *priv)
1435 {
1436  uint32_t i, j;
1437  int res;
1438  int maxsd = -1;
1439  fd_set set, disset;
1440  tlsclient_t *cl;
1441  buffer_t *assigned_buffer;
1442  uint8_t buffer[DEFAULT_MAX_DATA_LENGTH];
1443  uint64_t send_entry_time;
1444  uint64_t send_exit_time;
1445  uint8_t waiting_clients;
1446  struct timeval select_timeout;
1447 
1449 
1450  while (1) {
1451  if (c->is_terminated != 0) {
1452  pthread_exit(NULL);
1453  }
1454  if (c->connected_clients == 0) {
1455  usleep(NO_CLIENTS_SLEEP);
1456  continue;
1457  }
1458 
1459  if ((get_cur_timestamp() - c->autoflush_timestamp) > c->ctx->out_ifc_list[c->ifc_idx].timeout) {
1460  tls_sender_flush(c);
1461  }
1462 
1463  FD_ZERO(&disset);
1464  FD_ZERO(&set);
1465  waiting_clients = 0;
1466  select_timeout.tv_sec = 1;
1467  select_timeout.tv_usec = 0;
1468 
1469  /* Add term_pipe for reading into the disconnect client set */
1470  FD_SET(c->term_pipe[0], &disset);
1471  if (maxsd < c->term_pipe[0]) {
1472  maxsd = c->term_pipe[0];
1473  }
1474 
1475  /* Check whether clients are connected and there is data for them to receive. */
1476  for (i = j = 0; i < c->clients_arr_size; ++i) {
1477  if (j == c->connected_clients) {
1478  break;
1479  }
1480 
1481  if (check_index(c->clients_bit_arr, i) == 0) {
1482  continue;
1483  }
1484 
1485  ++j;
1486 
1487  cl = &(c->clients[i]);
1488  assigned_buffer = &c->buffers[cl->assigned_buffer];
1489 
1490  if (cl->sd >= 0) {
1491  FD_SET(cl->sd, &disset);
1492  }
1493 
1494  if (maxsd < cl->sd) {
1495  maxsd = cl->sd;
1496  }
1497 
1498  if (check_index(assigned_buffer->clients_bit_arr, i) == 0) {
1499  ++waiting_clients;
1500  continue;
1501  }
1502 
1503  if (cl->pending_bytes <= 0) {
1504  cl->sending_pointer = assigned_buffer->header;
1505  cl->pending_bytes = ntohl(*((uint32_t *) assigned_buffer->header)) + sizeof(uint32_t);
1506  }
1507 
1508  if (cl->sd >= 0) {
1509  FD_SET(cl->sd, &set);
1510  }
1511  }
1512 
1513  if (waiting_clients == c->connected_clients) {
1514  pthread_mutex_lock(&c->mtx_no_data);
1515  pthread_cond_wait(&c->cond_no_data, &c->mtx_no_data);
1516  pthread_mutex_unlock(&c->mtx_no_data);
1517  continue;
1518  }
1519 
1520  res = select(maxsd + 1, &disset, &set, NULL, &select_timeout);
1521  if (res < 0) {
1522  /* Select returned with an error */
1523  if (c->is_terminated == 0) {
1524  switch (errno) {
1525  case EINTR:
1526  continue;
1527  default:
1528  VERBOSE(CL_ERROR, "Sending thread: unexpected error in select (errno: %i)", errno);
1529  pthread_exit(NULL);
1530  }
1531  } else {
1532  VERBOSE(CL_VERBOSE_ADVANCED, "Sending thread: terminating...");
1533  pthread_exit(NULL);
1534  }
1535  } else if (res == 0) {
1536  /* Select timed out - no client will be receiving */
1537  continue;
1538  }
1539 
1540  if (FD_ISSET(c->term_pipe[0], &disset)) {
1541  /* Sending was interrupted by terminate(), exit even from TRAP_WAIT function call. */
1542  VERBOSE(CL_VERBOSE_ADVANCED, "Sending was interrupted by terminate()");
1543  pthread_exit(NULL);
1544  }
1545 
1546  /* Check file descriptors. Disconnect "inactive" clients and send data to those designated by select */
1547  for (i = j = 0; i < c->clients_arr_size; ++i) {
1548  if (j == c->connected_clients) {
1549  break;
1550  }
1551 
1552  cl = &(c->clients[i]);
1553  if (cl->sd < 1) {
1554  continue;
1555  }
1556 
1557  ++j;
1558 
1559  /* Check if client is still connected */
1560  if (FD_ISSET(cl->sd, &disset)) {
1561  res = recv(cl->sd, buffer, DEFAULT_MAX_DATA_LENGTH, 0);
1562  if (res < 1) {
1563  disconnect_client(c, i);
1564  VERBOSE(CL_VERBOSE_LIBRARY, "Client %u disconnected", cl->id);
1565  continue;
1566  }
1567  }
1568 
1569  /* Check if client is ready for data */
1570  if (FD_ISSET(cl->sd, &set)) {
1571  send_entry_time = get_cur_timestamp();
1572  res = send_data(c, cl, i);
1573  send_exit_time = get_cur_timestamp();
1574 
1575  /* Measure how much time we spent sending to this client (in microseconds) */
1576  cl->timer_last = (send_exit_time - send_entry_time);
1577  cl->timer_total += cl->timer_last;
1578 
1579  if (res != TRAP_E_OK) {
1580  VERBOSE(CL_VERBOSE_OFF, "Disconnected client %d (ret val: %d)", cl->id, res);
1581  disconnect_client(c, i);
1582  }
1583  }
1584  }
1585  }
1586 }
1587 
1588 /**
1589  * \brief Store message into buffer.
1590  *
1591  * \param[in] priv pointer to module private data
1592  * \param[in] data pointer to data to write
1593  * \param[in] size size of data to write
1594  * \param[in] timeout maximum time spent waiting for the message to be stored [microseconds]
1595  *
1596  * \return TRAP_E_OK Success.
1597  * \return TRAP_E_TIMEOUT Message was not stored into buffer and the attempt should be repeated.
1598  * \return TRAP_E_TERMINATED Libtrap was terminated during the process.
1599  */
1600 int tls_sender_send(void *priv, const void *data, uint16_t size, int timeout)
1601 {
1602  int res, i;
1603  uint32_t free_bytes;
1604  struct timespec ts;
1605  buffer_t *buffer;
1606 
1608  uint8_t block = (timeout == TRAP_WAIT || (timeout == TRAP_HALFWAIT && c->connected_clients != 0)) ? 1 : 0;
1609 
1610  /* Can we put message at least into empty buffer? In the worst case, we could end up with SEGFAULT -> rather skip with error */
1611  if ((size + sizeof(size)) > c->buffer_size) {
1612  VERBOSE(CL_ERROR, "Buffer is too small for this message. Skipping...");
1613  goto timeout;
1614  }
1615 
1616  /* If timeout is wait or half wait, we need to set some valid timeout value (>= 0)*/
1617  if (timeout == TRAP_WAIT || timeout == TRAP_HALFWAIT) {
1618  timeout = 10000;
1619  }
1620 
1621 repeat:
1622  if (c->is_terminated != 0) {
1623  return TRAP_E_TERMINATED;
1624  }
1625  if (block && c->connected_clients == 0) {
1626  usleep(NO_CLIENTS_SLEEP);
1627  goto repeat;
1628  }
1629 
1630  pthread_mutex_lock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1631  buffer = &c->buffers[c->active_buffer];
1632  while (buffer->clients_bit_arr != 0) {
1633  clock_gettime(CLOCK_REALTIME, &ts);
1634 
1635  ts.tv_nsec += (ts.tv_sec * 1000000000L) + (timeout * 1000L);
1636  ts.tv_sec = (ts.tv_nsec / 1000000000L);
1637  ts.tv_nsec %= 1000000000L;
1638 
1639  /* Wait until woken up by sending thread or until timeout elapses */
1640  res = pthread_cond_timedwait(&c->cond_full_buffer, &c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx, &ts);
1641  switch (res) {
1642  case 0:
1643  /* Succesfully locked, buffer can be used */
1644  break;
1645  case ETIMEDOUT:
1646  /* Desired buffer is still full after timeout */
1647  if (block) {
1648  /* Blocking send, wait until buffer is free to use */
1649  pthread_mutex_unlock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1650  goto repeat;
1651  } else {
1652  /* Non-blocking send, drop message or force buffer reset (not implemented) */
1653  goto timeout;
1654  }
1655  default:
1656  VERBOSE(CL_ERROR, "Unexpected error in pthread_mutex_timedlock()");
1657  goto timeout;
1658  }
1659  }
1660 
1661  /* Check if there is enough space in buffer */
1662  free_bytes = c->buffer_size - buffer->wr_index;
1663  if (free_bytes >= (size + sizeof(size))) {
1664  /* Store message into buffer */
1665  insert_into_buffer(buffer, data, size);
1666 
1667  /* If bufferswitch is 0, only 1 message is allowed to be stored in buffer */
1668  if (c->ctx->out_ifc_list[c->ifc_idx].bufferswitch == 0) {
1669  finish_buffer(c, buffer);
1670  }
1671 
1672  pthread_mutex_unlock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1673  return TRAP_E_OK;
1674  } else {
1675  /* Not enough space for message, finish current buffer and try to store message into next buffer */
1676  finish_buffer(c, buffer);
1677  buffer = &c->buffers[c->active_buffer];
1678 
1679  pthread_mutex_unlock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1680  goto repeat;
1681  }
1682 
1683 timeout:
1684  for (i = 0; i < c->clients_arr_size; i++) {
1685  if (c->clients[i].sd > 0 && c->clients[i].assigned_buffer == c->active_buffer) {
1686  c->clients[i].timeouts++;
1687  }
1688  }
1689  pthread_mutex_unlock(&c->ctx->out_ifc_list[c->ifc_idx].ifc_mtx);
1690  return TRAP_E_TIMEOUT;
1691 }
1692 
1693 /**
1694  * \brief Set interface state as terminated.
1695  * \param[in] priv pointer to module private data
1696  */
1697 void tls_sender_terminate(void *priv)
1698 {
1700 
1701  uint32_t i;
1702  uint64_t sum;
1703 
1704  /* Wait for connected clients to receive all finished buffers before terminating */
1705  if (c != NULL) {
1706  do {
1707  usleep(10000); //prevents busy waiting
1708  sum = 0;
1709  for (i = 0; i < c->buffer_count; i++) {
1710  sum |= c->buffers[i].clients_bit_arr;
1711  }
1712  } while (sum != 0);
1713 
1714  c->is_terminated = 1;
1715  close(c->term_pipe[1]);
1716  VERBOSE(CL_VERBOSE_LIBRARY, "Closed term_pipe, it should break select()");
1717  } else {
1718  VERBOSE(CL_ERROR, "Destroying IFC that is probably not initialized.");
1719  }
1720  return;
1721 }
1722 
1723 /**
1724  * \brief Destructor of TCP sender (output ifc)
1725  * \param[in] priv pointer to module private data
1726  */
1727 void tls_sender_destroy(void *priv)
1728 {
1730  void *res;
1731  int32_t i;
1732 
1733  /* free private data */
1734  if (c != NULL) {
1735  SSL_CTX_free(c->sslctx);
1736  free(c->server_port);
1737  free(c->keyfile);
1738  free(c->certfile);
1739  free(c->cafile);
1740 
1741  if (c->initialized) {
1742  pthread_cancel(c->send_thr);
1743  pthread_cancel(c->accept_thr);
1744  pthread_join(c->send_thr, &res);
1745  pthread_join(c->accept_thr, &res);
1746  }
1747 
1748  /* close server socket */
1749  close(c->server_sd);
1750 
1751  /* disconnect all clients */
1752  if (c->clients != NULL) {
1754  free(c->clients);
1755  }
1756 
1757  if (c->buffers != NULL) {
1758  for (i = 0; i < c->buffer_count; i++) {
1759  free(c->buffers[i].header);
1760  }
1761  free(c->buffers);
1762  }
1763 
1764  pthread_mutex_destroy(&c->mtx_no_data);
1765  pthread_cond_destroy(&c->cond_no_data);
1766  pthread_cond_destroy(&c->cond_full_buffer);
1767  free(c);
1768  }
1769 }
1770 
1771 int32_t tls_sender_get_client_count(void *priv)
1772 {
1774 
1775  if (c == NULL) {
1776  return 0;
1777  }
1778 
1779  return c->connected_clients;
1780 }
1781 
1782 int8_t tls_sender_get_client_stats_json(void* priv, json_t *client_stats_arr)
1783 {
1784  int i;
1785  json_t *client_stats = NULL;
1787 
1788  if (c == NULL) {
1789  return 0;
1790  }
1791 
1792  for (i = 0; i < c->clients_arr_size; ++i) {
1793  if (check_index(c->clients_bit_arr, i) == 0) {
1794  continue;
1795  }
1796 
1797  client_stats = json_pack("{sisisisi}", "id", c->clients[i].id, "timer_total", c->clients[i].timer_total, "timer_last", c->clients[i].timer_last, "timeouts", c->clients[i].timeouts);
1798  if (client_stats == NULL) {
1799  return 0;
1800  }
1801 
1802  if (json_array_append_new(client_stats_arr, client_stats) == -1) {
1803  return 0;
1804  }
1805  }
1806  return 1;
1807 }
1808 
1809 static void tls_sender_create_dump(void *priv, uint32_t idx, const char *path)
1810 {
1812  /* return value */
1813  int r;
1814  /* config file trap-i<number>-config.txt */
1815  char *conf_file = NULL;
1816  FILE *f = NULL;
1817  int32_t i;
1818  tlsclient_t *cl;
1819 
1820  r = asprintf(&conf_file, "%s/trap-o%02"PRIu32"-config.txt", path, idx);
1821  if (r == -1) {
1822  VERBOSE(CL_ERROR, "Not enough memory, dump failed. (%s:%d)", __FILE__, __LINE__);
1823  conf_file = NULL;
1824  goto exit;
1825  }
1826  f = fopen(conf_file, "w");
1827  fprintf(f, "Server port: %s\n"
1828  "Server socket descriptor: %d\n"
1829  "Connected clients: %d\n"
1830  "Max clients: %d\n"
1831  "Active buffer: %d\n"
1832  "Buffer count: %u\n"
1833  "Buffer size: %u\n"
1834  "Terminated: %d\n"
1835  "Initialized: %d\n"
1836  "Timeout: %u us\n",
1837  c->server_port,
1838  c->server_sd,
1839  c->connected_clients,
1840  c->clients_arr_size,
1841  c->active_buffer,
1842  c->buffer_size,
1843  c->buffer_size,
1844  c->is_terminated,
1845  c->initialized,
1846  c->ctx->out_ifc_list[idx].datatimeout);
1847  fprintf(f, "Clients:\n");
1848  for (i = 0; i < c->clients_arr_size; i++) {
1849  cl = &c->clients[i];
1850  fprintf(f, "\t{%d, %d, %p, %d}\n", cl->sd, cl->assigned_buffer, cl->sending_pointer, cl->pending_bytes);
1851  }
1852  fclose(f);
1853 exit:
1854  free(conf_file);
1855  return;
1856 }
1857 
1858 char *tls_send_ifc_get_id(void *priv)
1859 {
1860  if (priv == NULL) {
1861  return NULL;
1862  }
1863 
1864  tls_sender_private_t *config = (tls_sender_private_t *) priv;
1865  if (config->server_port == NULL) {
1866  return NULL;
1867  }
1868  return config->server_port;
1869 }
1870 
1871 /**
1872  * \brief Constructor of output TCP/IP IFC module.
1873  * This function is called by TRAP library to initialize one output interface.
1874  *
1875  * \param[in,out] ctx Pointer to the private libtrap context data (trap_ctx_init()).
1876  * \param[in] params Configuration string containing space separated values of these parameters (in this exact order): *server_port* *max_clients*,
1877  * where dest_addr is destination address of output TCP/IP IFC module and
1878  * dest_port is the port where sender is listening.
1879  * \param[in,out] ifc IFC interface used for calling TCP/IP module.
1880  * \param[in] idx Index of IFC that is created.
1881  * \return 0 on success (TRAP_E_OK)
1882  */
1883 int create_tls_sender_ifc(trap_ctx_priv_t *ctx, const char *params, trap_output_ifc_t *ifc, uint32_t idx)
1884 {
1885  int result = TRAP_E_OK;
1886  char *param_iterator = NULL;
1887  char *param_str = NULL;
1888  char *server_port = NULL;
1889  char *keyfile = NULL;
1890  char *certfile = NULL;
1891  char *cafile = NULL;
1892  tls_sender_private_t *priv = NULL;
1893  unsigned int max_clients = DEFAULT_MAX_CLIENTS;
1894  unsigned int buffer_count = DEFAULT_BUFFER_COUNT;
1895  unsigned int buffer_size = DEFAULT_BUFFER_SIZE;
1896  uint32_t i;
1897 
1898 #define X(pointer) free(pointer); \
1899  pointer = NULL;
1900 
1901  /* Check parameters */
1902  if (params == NULL) {
1903  VERBOSE(CL_ERROR, "IFC requires at least three parameters (port:keyfile:certfile).");
1904  return TRAP_E_BADPARAMS;
1905  }
1906 
1907  /* Create structure to store private data */
1908  priv = (tls_sender_private_t *) calloc(1, sizeof(tls_sender_private_t));
1909  if (priv == NULL) {
1910  result = TRAP_E_MEMORY;
1911  goto failsafe_cleanup;
1912  }
1913 
1914  /* Parsing params */
1915  param_iterator = trap_get_param_by_delimiter(params, &server_port, TRAP_IFC_PARAM_DELIMITER);
1916  if ((server_port == NULL) || (strlen(server_port) == 0)) {
1917  VERBOSE(CL_ERROR, "Missing 'port' for TLS IFC.");
1918  result = TRAP_E_BADPARAMS;
1919  goto failsafe_cleanup;
1920  }
1921  if (param_iterator != NULL) {
1922  param_iterator = trap_get_param_by_delimiter(param_iterator, &keyfile, TRAP_IFC_PARAM_DELIMITER);
1923  } else {
1924  VERBOSE(CL_ERROR, "Missing 'keyfile', 'certfile' and trusted 'CAfile' for TLS IFC.");
1925  result = TRAP_E_BADPARAMS;
1926  goto failsafe_cleanup;
1927  }
1928  if (param_iterator != NULL) {
1929  param_iterator = trap_get_param_by_delimiter(param_iterator, &certfile, TRAP_IFC_PARAM_DELIMITER);
1930  } else {
1931  VERBOSE(CL_ERROR, "Missing 'certfile' and trusted 'CAfile' for TLS IFC.");
1932  result = TRAP_E_BADPARAMS;
1933  goto failsafe_cleanup;
1934  }
1935  if (param_iterator != NULL) {
1936  param_iterator = trap_get_param_by_delimiter(param_iterator, &cafile, TRAP_IFC_PARAM_DELIMITER);
1937  } else {
1938  VERBOSE(CL_ERROR, "Missing trusted 'CAfile' for TLS IFC.");
1939  result = TRAP_E_BADPARAMS;
1940  goto failsafe_cleanup;
1941  }
1942 
1943  /* Optional params */
1944  while (param_iterator != NULL) {
1945  param_iterator = trap_get_param_by_delimiter(param_iterator, &param_str, TRAP_IFC_PARAM_DELIMITER);
1946  if (param_str == NULL)
1947  continue;
1948  if (strncmp(param_str, "buffer_count=x", BUFFER_COUNT_PARAM_LENGTH) == 0) {
1949  if (sscanf(param_str + BUFFER_COUNT_PARAM_LENGTH, "%u", &buffer_count) != 1) {
1950  VERBOSE(CL_ERROR, "Optional buffer count given, but it is probably in wrong format.");
1951  buffer_count = DEFAULT_BUFFER_COUNT;
1952  }
1953  } else if (strncmp(param_str, "buffer_size=x", BUFFER_SIZE_PARAM_LENGTH) == 0) {
1954  if (sscanf(param_str + BUFFER_SIZE_PARAM_LENGTH, "%u", &buffer_size) != 1) {
1955  VERBOSE(CL_ERROR, "Optional buffer size given, but it is probably in wrong format.");
1956  buffer_size = DEFAULT_BUFFER_SIZE;
1957  }
1958  } else if (strncmp(param_str, "max_clients=x", MAX_CLIENTS_PARAM_LENGTH) == 0) {
1959  if (sscanf(param_str + MAX_CLIENTS_PARAM_LENGTH, "%u", &max_clients) != 1) {
1960  VERBOSE(CL_ERROR, "Optional max clients number given, but it is probably in wrong format.");
1961  max_clients = DEFAULT_MAX_CLIENTS;
1962  }
1963  } else {
1964  VERBOSE(CL_ERROR, "Unknown parameter \"%s\".", param_str);
1965  }
1966  X(param_str);
1967  }
1968  /* Parsing params ended */
1969 
1970  priv->buffers = calloc(buffer_count, sizeof(buffer_t));
1971  if (priv->buffers == NULL) {
1972  /* if some memory could not have been allocated, we cannot continue */
1973  goto failsafe_cleanup;
1974  }
1975  for (i = 0; i < buffer_count; ++i) {
1976  buffer_t *b = &(priv->buffers[i]);
1977 
1978  b->header = malloc(buffer_size + sizeof(buffer_size));
1979  b->data = b->header + sizeof(buffer_size);
1980  b->wr_index = 0;
1981  b->clients_bit_arr = 0;
1982  }
1983 
1984  priv->clients = calloc(max_clients, sizeof(tlsclient_t));
1985  if (priv->clients == NULL) {
1986  /* if some memory could not have been allocated, we cannot continue */
1987  goto failsafe_cleanup;
1988  }
1989  for (i = 0; i < max_clients; ++i) {
1990  tlsclient_t *client = &(priv->clients[i]);
1991 
1992  client->assigned_buffer = 0;
1993  client->sd = -1;
1994  client->timer_total = 0;
1995  client->pending_bytes = 0;
1996  client->sending_pointer = NULL;
1997  }
1998 
1999  priv->keyfile = keyfile;
2000  priv->certfile = certfile;
2001  priv->cafile = cafile;
2002  priv->ctx = ctx;
2003  priv->ifc_idx = idx;
2004  priv->server_port = server_port;
2005  priv->buffer_size = buffer_size;
2006  priv->buffer_count = buffer_count;
2007  priv->clients_arr_size = max_clients;
2008  priv->clients_bit_arr = 0;
2009  priv->connected_clients = 0;
2010  priv->is_terminated = 0;
2011  priv->active_buffer = 0;
2013 
2014  pthread_mutex_init(&priv->mtx_no_data, NULL);
2015  pthread_cond_init(&priv->cond_no_data, NULL);
2016  pthread_cond_init(&priv->cond_full_buffer, NULL);
2017 
2018  VERBOSE(CL_VERBOSE_ADVANCED, "config:\nserver_port:\t%s\nmax_clients:\t%u\nbuffer count:\t%u\nbuffer size:\t%uB\n",
2019  priv->server_port, priv->clients_arr_size,priv->buffer_count, priv->buffer_size);
2020 
2021  result = server_socket_open(priv);
2022  if (result != TRAP_E_OK) {
2023  VERBOSE(CL_ERROR, "Socket could not be opened on given port '%s'.", server_port);
2024  goto failsafe_cleanup;
2025  }
2026 
2027  if (pipe(priv->term_pipe) != 0) {
2028  VERBOSE(CL_ERROR, "Opening of pipe failed. Using stdin as a fall back.");
2029  priv->term_pipe[0] = 0;
2030  }
2031 
2032  priv->sslctx = tlsserver_create_context();
2033  if (priv->sslctx == NULL) {
2034  result = TRAP_E_MEMORY;
2035  goto failsafe_cleanup;
2036  }
2037 
2038  if (tls_server_configure_ctx(priv->certfile, priv->sslctx) != 0) {
2039  VERBOSE(CL_ERROR, "Configuring server context failed.");
2040  goto failsafe_cleanup;
2041  }
2042 
2043  if (tls_configure_ctx(priv->sslctx, keyfile, certfile, cafile) == EXIT_FAILURE) {
2044  result = TRAP_E_BADPARAMS;
2045  goto failsafe_cleanup;
2046  }
2047 
2048  /* Fill struct defining the interface */
2050  ifc->send = tls_sender_send;
2051  ifc->flush = tls_sender_flush;
2053  ifc->destroy = tls_sender_destroy;
2057  ifc->priv = priv;
2058  ifc->get_id = tls_send_ifc_get_id;
2059  return result;
2060 
2061 failsafe_cleanup:
2062  X(server_port);
2063  X(param_str);
2064  X(certfile);
2065  X(cafile);
2066  X(keyfile);
2067  if (priv != NULL) {
2068  if (priv->buffers != NULL) {
2069  for (i = 0; i < priv->buffer_count; i++) {
2070  X(priv->buffers[i].header);
2071  }
2072  X(priv->buffers)
2073  }
2074  if (priv->clients != NULL) {
2075  X(priv->clients);
2076  }
2077  pthread_mutex_destroy(&priv->mtx_no_data);
2078  pthread_cond_destroy(&priv->cond_no_data);
2079  pthread_cond_destroy(&priv->cond_full_buffer);
2080  X(priv);
2081  }
2082 #undef X
2083  return result;
2084 }
2085 
2086 /**
2087  * \brief Open TLS socket for sender module
2088  * \param[in] priv tls_sender_private_t structure (private data)
2089  * \return 0 on success (TRAP_E_OK), TRAP_E_IO_ERROR on error
2090  */
2091 static int server_socket_open(void *priv)
2092 {
2093  int yes = 1; /* for setsockopt() SO_REUSEADDR, below */
2094  int rv;
2095 
2096  union tls_socket_addr addr;
2097  struct addrinfo *ai, *p = NULL;
2099  if (c->server_port == NULL) {
2100  return TRAP_E_BAD_FPARAMS;
2101  }
2102 
2103  memset(&addr, 0, sizeof(addr));
2104 
2105  /* get us a socket and bind it */
2106  addr.tls_addr.ai_family = AF_UNSPEC;
2107  addr.tls_addr.ai_socktype = SOCK_STREAM;
2108  addr.tls_addr.ai_flags = AI_PASSIVE;
2109  if ((rv = getaddrinfo(NULL, c->server_port, &addr.tls_addr, &ai)) != 0) {
2110  return trap_errorf(c->ctx, TRAP_E_IO_ERROR, "selectserver: %s\n", gai_strerror(rv));
2111  }
2112 
2113  for (p = ai; p != NULL; p = p->ai_next) {
2114  c->server_sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
2115  if (c->server_sd < 0) {
2116  continue;
2117  }
2118 
2119  /* lose the pesky "address already in use" error message */
2120  if (setsockopt(c->server_sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
2121  VERBOSE(CL_ERROR, "Failed to set socket to reuse address. (%d)", errno);
2122  }
2123 
2124  if (bind(c->server_sd, p->ai_addr, p->ai_addrlen) < 0) {
2125  close(c->server_sd);
2126  continue;
2127  }
2128  break; /* found socket to bind */
2129  }
2130  freeaddrinfo(ai);
2131 
2132  if (p == NULL) {
2133  /* if we got here, it means we didn't get bound */
2134  VERBOSE(CL_VERBOSE_LIBRARY, "selectserver: failed to bind");
2135  return TRAP_E_IO_ERROR;
2136  }
2137 
2138  /* listen */
2139  if (listen(c->server_sd, c->clients_arr_size) == -1) {
2140  VERBOSE(CL_ERROR, "Listen failed");
2141  return TRAP_E_IO_ERROR;
2142  }
2143 
2144  if (pthread_create(&c->send_thr, NULL, sending_thread_func, priv) != 0) {
2145  VERBOSE(CL_ERROR, "Failed to create sending thread.");
2146  return TRAP_E_IO_ERROR;
2147  }
2148 
2149  if (pthread_create(&c->accept_thr, NULL, accept_clients_thread, priv) != 0) {
2150  VERBOSE(CL_ERROR, "Failed to create accept_thread.");
2151  return TRAP_E_IO_ERROR;
2152  }
2153 
2154  c->initialized = 1;
2155  return 0;
2156 }
2157 
2158 /**
2159  * @}
2160  *//* tls_sender */
2161 
2162 
2163 /**
2164  * @}
2165  *//* tls_ifc module */
2166 
2167 /**
2168  * @}
2169  *//* ifc modules */
uint64_t timer_total
ifc_get_id_func_t get_id
Pointer to get_id function.
Definition: trap_ifc.h:182
uint8_t * data
#define BUFFER_SIZE_PARAM_LENGTH
static uint64_t get_cur_timestamp()
Definition: ifc_tls.c:1186
#define TRAP_E_OK
Success, no error.
Definition: trap.h:87
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
static SSL_CTX * tlsserver_create_context()
Definition: ifc_tls.c:102
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
ifc_get_client_stats_json_func_t get_client_stats_json
Pointer to get_client_stats_json function.
Definition: trap_ifc.h:244
pthread_cond_t cond_full_buffer
#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
static void tls_sender_create_dump(void *priv, uint32_t idx, const char *path)
Definition: ifc_tls.c:1809
Internal functions and macros for libtrap Verbose and debug macros from libcommlbr.
uint32_t wr_index
Output buffer structure.
#define TRAP_IFC_PARAM_DELIMITER
Definition: trap.h:165
static int receive_part(void *priv, void **data, uint32_t *size, struct timeval *tm)
Definition: ifc_tls.c:286
static void * accept_clients_thread(void *arg)
This function runs in a separate thread and handles new client&#39;s connection requests.
Definition: ifc_tls.c:1200
void tls_receiver_terminate(void *priv)
Set interface state as terminated.
Definition: ifc_tls.c:606
struct trap_buffer_header_s trap_buffer_header_t
uint32_t pending_bytes
static int tls_configure_ctx(SSL_CTX *ctx, const char *key, const char *crt, const char *ca)
Configure ssl context of new connection.
Definition: ifc_tls.c:210
pthread_mutex_t ifc_mtx
Locking mutex for interface.
Definition: trap_ifc.h:246
#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
void tls_sender_destroy(void *priv)
Destructor of TCP sender (output ifc)
Definition: ifc_tls.c:1727
pthread_cond_t cond_no_data
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
static void disconnect_client(tls_sender_private_t *priv, int cl_id)
This function is called when a client was/is being disconnected.
Definition: ifc_tls.c:1139
ifc_get_id_func_t get_id
Pointer to get_id function.
Definition: trap_ifc.h:236
#define TRAP_TIMEOUT_STR(t)
Definition: trap.h:132
static int wait_for_connection(int sock, struct timeval *tv)
Definition: ifc_tls.c:912
#define TRAP_E_FIELDS_MISMATCH
Returned when receiver fields are not subset of sender fields.
Definition: trap.h:98
Structure for TLS IFC private information.
int output_ifc_negotiation(void *ifc_priv_data, char ifc_type, uint32_t client_idx)
Definition: trap.c:2833
static void insert_into_buffer(file_buffer_t *buffer, const void *data, uint16_t size)
Definition: ifc_file.c:647
static void set_index(uint64_t *bits, int i)
Set i-th element (one bit) of &#39;bits&#39; to 1.
trap_ctx_priv_t * ctx
void tls_server_disconnect_all_clients(void *priv)
Function disconnects all clients of the output interface whose private structure is passed via "priv"...
Definition: ifc_tls.c:1167
void tls_receiver_destroy(void *priv)
Destructor of TLS receiver (input ifc)
Definition: ifc_tls.c:622
#define X(pointer)
static void del_index(uint64_t *bits, int i)
Set i-th element (one bit) of &#39;bits&#39; to 0.
#define TRAP_E_TERMINATED
Interface was terminated during reading/writing.
Definition: trap.h:94
ifc_create_dump_func_t create_dump
Pointer to function for generating of dump.
Definition: trap_ifc.h:242
#define TRAP_HALFWAIT
Definition: trap.h:130
static void client_socket_disconnect(void *priv)
Definition: ifc_tls.c:892
#define TRAP_E_IO_ERROR
IO Error.
Definition: trap.h:93
#define NEG_RES_FMT_CHANGED
If the data format has changed (for JSON type, UNIREC type uses *SUBSET variants) ...
Definition: trap_internal.h:78
#define VERBOSE(level, format, args...)
TRAP TCP/IP interfaces private structures.
struct sockaddr_un unix_addr
used for path of UNIX socket
Definition: ifc_tls.c:251
static int verify_certificate(SSL *arg)
Verify context of ssl.
Definition: ifc_tls.c:147
int tls_receiver_recv(void *priv, void *data, uint32_t *size, int timeout)
Receive data from interface.
Definition: ifc_tls.c:395
trap_ctx_priv_t * ctx
static int trap_errorf(trap_ctx_priv_t *ctx, int err_num, const char *msg,...)
Definition: trap_error.h:92
uint8_t data[0]
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
void tls_sender_flush(void *priv)
Force flush of active buffer.
Definition: ifc_tls.c:1358
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
ifc_disconn_clients_func_t disconn_clients
Pointer to disconnect_clients function.
Definition: trap_ifc.h:237
ifc_terminate_func_t terminate
Pointer to terminate function.
Definition: trap_ifc.h:184
#define TRAP_E_BAD_FPARAMS
Bad parameters of function.
Definition: trap.h:92
static int server_socket_open(void *priv)
Open TLS socket for sender module.
Definition: ifc_tls.c:2091
static int tls_server_configure_ctx(const char *cert, SSL_CTX *ctx)
Configure context of ssl server.
Definition: ifc_tls.c:175
uint8_t tls_recv_ifc_is_conn(void *priv)
Definition: ifc_tls.c:714
char bufferswitch
Enable (1) or Disable (0) buffering, default is Enabled (1).
Definition: trap_ifc.h:250
struct addrinfo tls_addr
used for TCPIP socket
Definition: ifc_tls.c:250
#define DEFAULT_BUFFER_SIZE
#define DEBUG_IFC(X)
static uint64_t check_index(uint64_t bits, int i)
Return value of i-th element (one bit) in the &#39;bits&#39; array.
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
#define TRAP_E_NEGOTIATION_FAILED
Returned by trap_recv when negotiation of the output and input interfaces failed. ...
Definition: trap.h:102
Structure for TLS IFC client information.
ifc_send_func_t send
Pointer to send function.
Definition: trap_ifc.h:238
int32_t datatimeout
Timeout for *_recv() calls.
Definition: trap_ifc.h:191
void * sending_pointer
#define NEG_RES_FMT_UNKNOWN
If the output interface has not specified data format.
Definition: trap_internal.h:85
#define TRAP_IFC_TYPE_TLS
trap_ifc_tls (input&output part)
Definition: trap.h:174
#define DEFAULT_MAX_CLIENTS
ifc_recv_func_t recv
Pointer to receive function.
Definition: trap_ifc.h:183
#define TRAP_E_FORMAT_MISMATCH
Returned by trap_recv when data format or data specifier of the output and input interfaces doesn&#39;t m...
Definition: trap.h:101
#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
ifc_create_dump_func_t create_dump
Pointer to function for generating of dump.
Definition: trap_ifc.h:186
#define DEFAULT_BUFFER_COUNT
uint8_t * header
Error handling for TRAP.
#define TRAP_E_MEMORY
Memory allocation error.
Definition: trap.h:104
int8_t tls_sender_get_client_stats_json(void *priv, json_t *client_stats_arr)
Definition: ifc_tls.c:1782
#define NEG_RES_OK
Signaling success (hello message successfully sent to input interface)
Definition: trap_internal.h:81
int tls_sender_send(void *priv, const void *data, uint16_t size, int timeout)
Store message into buffer.
Definition: ifc_tls.c:1600
uint32_t timer_last
static void finish_buffer(tls_sender_private_t *priv, buffer_t *buffer)
Write buffer size to its header and shift active index.
Definition: ifc_tls.c:1334
static void * get_in_addr(struct sockaddr *sa)
Get sockaddr, IPv4 or IPv6.
Definition: ifc_tls.c:263
#define MAX_RECOVERY_TRY
Definition: ifc_tls.c:89
int32_t tls_sender_get_client_count(void *priv)
Definition: ifc_tls.c:1771
#define TRAP_E_BAD_CERT
Wrong certificate given to TLS interface.
Definition: trap.h:96
ifc_destroy_func_t destroy
Pointer to destructor function.
Definition: trap_ifc.h:241
ifc_terminate_func_t terminate
Pointer to terminate function.
Definition: trap_ifc.h:240
This file contains common functions and structures used in socket based interfaces (tcp-ip / tls)...
uint64_t clients_bit_arr
static int send_data(tls_sender_private_t *priv, tlsclient_t *c, uint32_t cl_id)
Send data to client from his assigned buffer.
Definition: ifc_tls.c:1385
#define TRAP_E_TIMEOUT
Read or write operation timeout.
Definition: trap.h:88
static SSL_CTX * tlsclient_create_context()
Definition: ifc_tls.c:125
uint32_t assigned_buffer
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
static void * sending_thread_func(void *priv)
This function runs in a separate thread. It handles sending data to connected clients for TLS interfa...
Definition: ifc_tls.c:1434
void tls_sender_terminate(void *priv)
Set interface state as terminated.
Definition: ifc_tls.c:1697
#define DEFAULT_MAX_DATA_LENGTH
static int client_socket_connect(tls_receiver_private_t *priv, struct timeval *tv)
client_socket is used as a receiver
Definition: ifc_tls.c:941
ifc_flush_func_t flush
Pointer to flush function.
Definition: trap_ifc.h:239
uint64_t timeouts
trap_buffer_header_t int_mess_header
char * tls_send_ifc_get_id(void *priv)
Definition: ifc_tls.c:1858
#define TRAP_WAIT
Definition: trap.h:124
void * priv
Pointer to instance&#39;s private data.
Definition: trap_ifc.h:187
static void tls_receiver_create_dump(void *priv, uint32_t idx, const char *path)
Definition: ifc_tls.c:643
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
void * priv
Pointer to instance&#39;s private data.
Definition: trap_ifc.h:245
pthread_mutex_t mtx_no_data
trap_output_ifc_t * out_ifc_list
char * tls_recv_ifc_get_id(void *priv)
Definition: ifc_tls.c:701
#define MAX_CLIENTS_PARAM_LENGTH
Interface of TRAP interfaces.
#define BUFFER_COUNT_PARAM_LENGTH
trap_input_ifc_t * in_ifc_list
#define TRAP_E_BADPARAMS
Bad parameters passed to interface initializer.
Definition: trap.h:90
#define NO_CLIENTS_SLEEP