LCOV - code coverage report
Current view: top level - daemon - dlt_daemon_connection.c (source / functions) Coverage Total Hit
Test: dlt_final_coverage.info Lines: 88.6 % 114 101
Test Date: 2025-03-25 20:53:42 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :  * SPDX license identifier: MPL-2.0
       3              :  *
       4              :  * Copyright (C) 2015 Advanced Driver Information Technology.
       5              :  * This code is developed by Advanced Driver Information Technology.
       6              :  * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
       7              :  *
       8              :  * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
       9              :  *
      10              :  * This Source Code Form is subject to the terms of the
      11              :  * Mozilla Public License (MPL), v. 2.0.
      12              :  * If a copy of the MPL was not distributed with this file,
      13              :  * You can obtain one at http://mozilla.org/MPL/2.0/.
      14              :  *
      15              :  * For further information see http://www.covesa.org/.
      16              :  */
      17              : 
      18              : /*!
      19              :  * \author
      20              :  * Frederic Berat <fberat@de.adit-jv.com>
      21              :  *
      22              :  * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
      23              :  * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
      24              :  *
      25              :  * \file dlt_daemon_connection.c
      26              :  */
      27              : 
      28              : #include <errno.h>
      29              : #include <stdio.h>
      30              : #include <stdlib.h>
      31              : #include <string.h>
      32              : #include <unistd.h>
      33              : 
      34              : #include <sys/socket.h>
      35              : #include <syslog.h>
      36              : #include <sys/stat.h>
      37              : #include <sys/types.h>
      38              : 
      39              : #include "dlt_daemon_connection_types.h"
      40              : #include "dlt_daemon_connection.h"
      41              : #include "dlt_daemon_event_handler_types.h"
      42              : #include "dlt_daemon_event_handler.h"
      43              : #include "dlt-daemon.h"
      44              : #include "dlt-daemon_cfg.h"
      45              : #include "dlt_daemon_common.h"
      46              : #include "dlt_common.h"
      47              : #include "dlt_log.h"
      48              : #include "dlt_gateway.h"
      49              : #include "dlt_daemon_socket.h"
      50              : 
      51              : static DltConnectionId connectionId;
      52              : extern char *app_recv_buffer;
      53              : 
      54              : /** @brief Generic sending function.
      55              :  *
      56              :  * We manage different type of connection which have similar send/write
      57              :  * functions. We can then abstract the data transfer using this function,
      58              :  * moreover as we often transfer data to different kind of connection
      59              :  * within the same loop.
      60              :  *
      61              :  * @param conn The connection structure.
      62              :  * @param msg The message buffer to be sent
      63              :  * @param msg_size The length of the message to be sent
      64              :  *
      65              :  * @return DLT_DAEMON_ERROR_OK on success, DLT_DAEMON_ERROR_SEND_FAILED
      66              :  *         on send failure, DLT_DAEMON_ERROR_UNKNOWN otherwise.
      67              :  *         errno is appropriately set.
      68              :  */
      69          436 : DLT_STATIC int dlt_connection_send(DltConnection *conn,
      70              :                                    void *msg,
      71              :                                    size_t msg_size)
      72              : {
      73              :     DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
      74              :     int ret = 0;
      75              : 
      76          436 :     if ((conn != NULL) && (conn->receiver != NULL))
      77          436 :         type = conn->type;
      78              : 
      79          436 :     switch (type) {
      80            1 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
      81              : 
      82            1 :         if (write(conn->receiver->fd, msg, msg_size) > 0)
      83              :             return DLT_DAEMON_ERROR_OK;
      84              : 
      85              :         return DLT_DAEMON_ERROR_UNKNOWN;
      86              : 
      87          434 :     case DLT_CONNECTION_CLIENT_MSG_TCP:
      88          434 :         ret = dlt_daemon_socket_sendreliable(conn->receiver->fd,
      89              :                                              msg,
      90              :                                              msg_size);
      91          434 :         return ret;
      92              :     default:
      93              :         return DLT_DAEMON_ERROR_UNKNOWN;
      94              :     }
      95              : }
      96              : 
      97              : /** @brief Send up to two messages through a connection.
      98              :  *
      99              :  * We often need to send 2 messages through a specific connection, plus
     100              :  * the serial header. This function groups these different calls.
     101              :  *
     102              :  * @param con The connection to send the messages through.
     103              :  * @param data1 The first message to be sent.
     104              :  * @param size1 The size of the first message.
     105              :  * @param data2 The second message to be send.
     106              :  * @param size2 The second message size.
     107              :  * @param sendserialheader Whether we need or not to send the serial header.
     108              :  *
     109              :  * @return DLT_DAEMON_ERROR_OK on success, -1 otherwise. errno is properly set.
     110              :  */
     111          219 : int dlt_connection_send_multiple(DltConnection *con,
     112              :                                  void *data1,
     113              :                                  int size1,
     114              :                                  void *data2,
     115              :                                  int size2,
     116              :                                  int sendserialheader)
     117              : {
     118              :     int ret = 0;
     119              : 
     120          219 :     if (con == NULL)
     121              :         return DLT_DAEMON_ERROR_UNKNOWN;
     122              : 
     123          218 :     if (sendserialheader)
     124            1 :         ret = dlt_connection_send(con,
     125              :                                   (void *)dltSerialHeader,
     126              :                                   sizeof(dltSerialHeader));
     127              : 
     128          218 :     if ((data1 != NULL) && (ret == DLT_RETURN_OK))
     129          218 :         ret = dlt_connection_send(con, data1, size1);
     130              : 
     131          218 :     if ((data2 != NULL) && (ret == DLT_RETURN_OK))
     132          214 :         ret = dlt_connection_send(con, data2, size2);
     133              : 
     134              :     return ret;
     135              : }
     136              : 
     137              : /** @brief Get the next connection filtered with a type mask.
     138              :  *
     139              :  * In some cases we need the next connection available of a specific type or
     140              :  * specific different types. This function returns the next available connection
     141              :  * that is of one of the types included in the mask. The current connection can
     142              :  * be returned.
     143              :  *
     144              :  * @param current The current connection pointer.
     145              :  * @param type_mask A bit mask representing the connection types to be filtered.
     146              :  *
     147              :  * @return The next available connection of the considered types or NULL.
     148              :  */
     149            2 : DltConnection *dlt_connection_get_next(DltConnection *current, int type_mask)
     150              : {
     151            3 :     while (current && !((1 << current->type) & type_mask))
     152            1 :         current = current->next;
     153              : 
     154            2 :     return current;
     155              : }
     156              : 
     157           49 : DLT_STATIC void dlt_connection_destroy_receiver(DltConnection *con)
     158              : {
     159           49 :     if (!con)
     160              :         return;
     161              : 
     162           49 :     switch (con->type) {
     163              :     case DLT_CONNECTION_GATEWAY:
     164              :         /* We rely on the gateway for clean-up */
     165              :         break;
     166            9 :     case DLT_CONNECTION_APP_MSG:
     167            9 :         dlt_receiver_free_global_buffer(con->receiver);
     168            9 :         free(con->receiver);
     169            9 :         con->receiver = NULL;
     170            9 :         break;
     171           36 :     default:
     172           36 :         (void)dlt_receiver_free(con->receiver);
     173           36 :         free(con->receiver);
     174           36 :         con->receiver = NULL;
     175           36 :         break;
     176              :     }
     177              : }
     178              : 
     179              : /** @brief Get the receiver structure associated to a connection.
     180              :  *
     181              :  * The receiver structure is sometimes needed while handling the event.
     182              :  * This behavior is mainly due to the fact that it's not intended to modify
     183              :  * the whole design of the daemon while implementing the new event handling.
     184              :  * Based on the connection type provided, this function returns the pointer
     185              :  * to the DltReceiver structure corresponding.
     186              :  *
     187              :  * @param daemon_local Structure where to take the DltReceiver pointer from.
     188              :  * @param type Type of the connection.
     189              :  * @param fd File descriptor
     190              :  *
     191              :  * @return DltReceiver structure or NULL if none corresponds to the type.
     192              :  */
     193           48 : DLT_STATIC DltReceiver *dlt_connection_get_receiver(DltDaemonLocal *daemon_local,
     194              :                                                     DltConnectionType type,
     195              :                                                     int fd)
     196              : {
     197              :     DltReceiver *ret = NULL;
     198              :     DltReceiverType receiver_type = DLT_RECEIVE_FD;
     199              :     struct stat statbuf;
     200              : 
     201           48 :     switch (type) {
     202           25 :     case DLT_CONNECTION_CONTROL_CONNECT:
     203              :     /* FALL THROUGH */
     204              :     case DLT_CONNECTION_CONTROL_MSG:
     205              :     /* FALL THROUGH */
     206              :     case DLT_CONNECTION_CLIENT_CONNECT:
     207              :     /* FALL THROUGH */
     208              :     case DLT_CONNECTION_CLIENT_MSG_TCP:
     209           25 :         ret = calloc(1, sizeof(DltReceiver));
     210              : 
     211           25 :         if (ret)
     212           25 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_SOCKET, DLT_DAEMON_RCVBUFSIZESOCK);
     213              : 
     214              :         break;
     215            1 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
     216            1 :         ret = calloc(1, sizeof(DltReceiver));
     217              : 
     218            1 :         if (ret)
     219            1 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_FD, DLT_DAEMON_RCVBUFSIZESERIAL);
     220              : 
     221              :         break;
     222            9 :     case DLT_CONNECTION_APP_MSG:
     223            9 :         ret = calloc(1, sizeof(DltReceiver));
     224              : 
     225              :         receiver_type = DLT_RECEIVE_FD;
     226              : 
     227            9 :         if (fstat(fd, &statbuf) == 0) {
     228            9 :             if (S_ISSOCK(statbuf.st_mode))
     229              :                 receiver_type = DLT_RECEIVE_SOCKET;
     230              :         } else {
     231            0 :             dlt_vlog(LOG_WARNING,
     232              :                      "Failed to determine receive type for DLT_CONNECTION_APP_MSG, using \"FD\"\n");
     233              :         }
     234              : 
     235            9 :         if (ret)
     236            9 :             dlt_receiver_init_global_buffer(ret, fd, receiver_type, &app_recv_buffer);
     237              : 
     238              :         break;
     239              : #if defined DLT_DAEMON_USE_UNIX_SOCKET_IPC || defined DLT_DAEMON_VSOCK_IPC_ENABLE
     240              :     case DLT_CONNECTION_APP_CONNECT:
     241              :     /* FALL THROUGH */
     242              : #endif
     243           10 :     case DLT_CONNECTION_ONE_S_TIMER:
     244              :     /* FALL THROUGH */
     245              :     case DLT_CONNECTION_SIXTY_S_TIMER:
     246              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     247              :     /* FALL THROUGH */
     248              :     case DLT_CONNECTION_SYSTEMD_TIMER:
     249              : #endif
     250              :     /* FALL THROUGH */
     251              :     case DLT_CONNECTION_GATEWAY_TIMER:
     252           10 :         ret = calloc(1, sizeof(DltReceiver));
     253              : 
     254           10 :         if (ret)
     255           10 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_FD, DLT_DAEMON_RCVBUFSIZE);
     256              : 
     257              :         break;
     258            3 :     case DLT_CONNECTION_GATEWAY:
     259              :         /* We rely on the gateway for init */
     260            3 :         ret = dlt_gateway_get_connection_receiver(&daemon_local->pGateway, fd);
     261            3 :         break;
     262              :     default:
     263              :         ret = NULL;
     264              :     }
     265              : 
     266           48 :     return ret;
     267              : }
     268              : 
     269              : /** @brief Get the callback from a specific connection.
     270              :  *
     271              :  * The callback retrieved that way is used to handle event for this connection.
     272              :  * It as been chosen to proceed that way instead of having the callback directly
     273              :  * in the structure in order to have some way to check that the structure is
     274              :  * still valid, or at least gracefully handle errors instead of crashing.
     275              :  *
     276              :  * @param con The connection to retrieve the callback from.
     277              :  *
     278              :  * @return Function pointer or NULL.
     279              :  */
     280         1396 : void *dlt_connection_get_callback(DltConnection *con)
     281              : {
     282              :     void *ret = NULL;
     283              :     DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
     284              : 
     285         1396 :     if (con)
     286         1396 :         type = con->type;
     287              : 
     288         1396 :     switch (type) {
     289              :     case DLT_CONNECTION_CLIENT_CONNECT:
     290              :         ret = dlt_daemon_process_client_connect;
     291              :         break;
     292            6 :     case DLT_CONNECTION_CLIENT_MSG_TCP:
     293              :         ret = dlt_daemon_process_client_messages;
     294            6 :         break;
     295            0 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
     296              :         ret = dlt_daemon_process_client_messages_serial;
     297            0 :         break;
     298              : #if defined DLT_DAEMON_USE_UNIX_SOCKET_IPC || defined DLT_DAEMON_VSOCK_IPC_ENABLE
     299              :     case DLT_CONNECTION_APP_CONNECT:
     300              :         ret = dlt_daemon_process_app_connect;
     301              :         break;
     302              : #endif
     303         1367 :     case DLT_CONNECTION_APP_MSG:
     304              :         ret = dlt_daemon_process_user_messages;
     305         1367 :         break;
     306           11 :     case DLT_CONNECTION_ONE_S_TIMER:
     307              :         ret = dlt_daemon_process_one_s_timer;
     308           11 :         break;
     309            0 :     case DLT_CONNECTION_SIXTY_S_TIMER:
     310              :         ret = dlt_daemon_process_sixty_s_timer;
     311            0 :         break;
     312              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     313              :     case DLT_CONNECTION_SYSTEMD_TIMER:
     314              :         ret = dlt_daemon_process_systemd_timer;
     315              :         break;
     316              : #endif
     317            2 :     case DLT_CONNECTION_CONTROL_CONNECT:
     318              :         ret = dlt_daemon_process_control_connect;
     319            2 :         break;
     320            4 :     case DLT_CONNECTION_CONTROL_MSG:
     321              :         ret = dlt_daemon_process_control_messages;
     322            4 :         break;
     323            2 :     case DLT_CONNECTION_GATEWAY:
     324              :         ret = dlt_gateway_process_passive_node_messages;
     325            2 :         break;
     326            0 :     case DLT_CONNECTION_GATEWAY_TIMER:
     327              :         ret = dlt_gateway_process_gateway_timer;
     328            0 :         break;
     329            0 :     default:
     330              :         ret = NULL;
     331              :     }
     332              : 
     333         1396 :     return ret;
     334              : }
     335              : 
     336              : /** @brief Destroys a connection.
     337              :  *
     338              :  * This function closes and frees the corresponding connection. This is expected
     339              :  * to be called by the connection owner: the DltEventHandler.
     340              :  * Ownership of the connection is given during the registration to
     341              :  * the DltEventHandler.
     342              :  *
     343              :  * @param to_destroy Connection to be destroyed.
     344              :  */
     345           48 : void dlt_connection_destroy(DltConnection *to_destroy)
     346              : {
     347           48 :     to_destroy->id = 0;
     348           48 :     close(to_destroy->receiver->fd);
     349           48 :     dlt_connection_destroy_receiver(to_destroy);
     350           48 :     free(to_destroy);
     351           48 : }
     352              : 
     353              : /** @brief Creates a connection and registers it to the DltEventHandler.
     354              :  *
     355              :  * The function will allocate memory for the connection, and give the pointer
     356              :  * to the DltEventHandler in order to register it for incoming events.
     357              :  * The connection is then destroyed later on, once it's not needed anymore or
     358              :  * it the event handler is destroyed.
     359              :  *
     360              :  * @param daemon_local Structure were some needed information is.
     361              :  * @param evh DltEventHandler to register the connection to.
     362              :  * @param fd File descriptor of the connection.
     363              :  * @param mask Event list bit mask.
     364              :  * @param type Connection type.
     365              :  *
     366              :  * @return 0 On success, -1 otherwise.
     367              :  */
     368           47 : int dlt_connection_create(DltDaemonLocal *daemon_local,
     369              :                           DltEventHandler *evh,
     370              :                           int fd,
     371              :                           int mask,
     372              :                           DltConnectionType type)
     373              : {
     374              :     DltConnection *temp = NULL;
     375              : 
     376           47 :     if (fd < 0)
     377              :         /* Nothing to do */
     378              :         return 0;
     379              : 
     380           47 :     if (dlt_event_handler_find_connection(evh, fd) != NULL)
     381              :         /* No need for the same client to be registered twice
     382              :          * for the same event.
     383              :          * TODO: If another mask can be expected,
     384              :          * we need it to update the poll event here.
     385              :          */
     386              :         return 0;
     387              : 
     388           47 :     temp = (DltConnection *)malloc(sizeof(DltConnection));
     389              : 
     390           47 :     if (temp == NULL) {
     391            0 :         dlt_log(LOG_CRIT, "Allocation of client handle failed\n");
     392            0 :         return -1;
     393              :     }
     394              : 
     395              :     memset(temp, 0, sizeof(DltConnection));
     396              : 
     397           47 :     temp->receiver = dlt_connection_get_receiver(daemon_local, type, fd);
     398              : 
     399           47 :     if (!temp->receiver) {
     400            0 :         dlt_vlog(LOG_CRIT, "Unable to get receiver from %u connection.\n",
     401              :                  type);
     402            0 :         free(temp);
     403            0 :         return -1;
     404              :     }
     405              : 
     406              :     struct timeval timeout;
     407           47 :     timeout.tv_sec = 5;
     408           47 :     timeout.tv_usec = 0;
     409              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     410              :     char *watchdogUSec = getenv("WATCHDOG_USEC");
     411              :     if (watchdogUSec) {
     412              :         timeout.tv_sec = atoi(watchdogUSec) / 1000000;
     413              :         timeout.tv_usec = atoi(watchdogUSec) % 1000000;
     414              :     }
     415              : #endif
     416              : 
     417           47 :     if (setsockopt (temp->receiver->fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout) < 0)  {
     418           20 :         dlt_vlog(LOG_WARNING, "Unable to set send timeout %s.\n", strerror(errno));
     419              :         // as this function is used for non socket connection as well
     420              :         // we only can return an error here if it is a socket
     421           20 :         if (errno != ENOTSOCK) {
     422            1 :             free(temp);
     423            1 :             return -1;
     424              :         }
     425              :     }
     426              : 
     427              :     /* We are single threaded no need for protection. */
     428           46 :     temp->id = connectionId++;
     429              : 
     430           46 :     if (!temp->id)
     431              :         /* Skipping 0 */
     432           10 :         temp->id = connectionId++;
     433              : 
     434           46 :     temp->type = type;
     435           46 :     temp->status = ACTIVE;
     436              : 
     437              :     /* Now give the ownership of the newly created connection
     438              :      * to the event handler, by registering for events.
     439              :      */
     440           46 :     return dlt_event_handler_register_connection(evh, daemon_local, temp, mask);
     441              : }
        

Generated by: LCOV version 2.0-1