LCOV - code coverage report
Current view: top level - daemon - dlt_daemon_connection.c (source / functions) Coverage Total Hit
Test: dlt_final_coverage.info Lines: 83.6 % 116 97
Test Date: 2026-08-27 10:11:10 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            8 : DLT_STATIC int dlt_connection_send(DltConnection* conn, const void* msg, size_t msg_size)
      70              : {
      71              :     DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
      72              :     int ret = 0;
      73              : 
      74            8 :     if ((conn != NULL) && (conn->receiver != NULL))
      75            8 :         type = conn->type;
      76              : 
      77            8 :     switch (type) {
      78            1 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
      79            1 :         if (msg_size > 0 && msg_size <= SSIZE_MAX) {
      80            1 :             if (write(conn->receiver->fd, msg, msg_size) > 0)
      81              :                 return DLT_DAEMON_ERROR_OK;
      82              :         }
      83              :         return DLT_DAEMON_ERROR_UNKNOWN;
      84              : 
      85            6 :     case DLT_CONNECTION_CLIENT_MSG_TCP:
      86            6 :         if (msg_size > INT_MAX) {
      87              :             return DLT_DAEMON_ERROR_UNKNOWN;
      88              :         }
      89            6 :         ret = dlt_daemon_socket_sendreliable(conn->receiver->fd, msg, (int)msg_size);
      90            6 :         return ret;
      91              :     default:
      92              :         return DLT_DAEMON_ERROR_UNKNOWN;
      93              :     }
      94              : }
      95              : 
      96              : /** @brief Send up to two messages through a connection.
      97              :  *
      98              :  * We often need to send 2 messages through a specific connection, plus
      99              :  * the serial header. This function groups these different calls.
     100              :  *
     101              :  * @param con The connection to send the messages through.
     102              :  * @param data1 The first message to be sent.
     103              :  * @param size1 The size of the first message.
     104              :  * @param data2 The second message to be send.
     105              :  * @param size2 The second message size.
     106              :  * @param sendserialheader Whether we need or not to send the serial header.
     107              :  *
     108              :  * @return DLT_DAEMON_ERROR_OK on success, -1 otherwise. errno is properly set.
     109              :  */
     110            3 : int dlt_connection_send_multiple(
     111              :     DltConnection* con, void* data1, int size1, void* data2, int size2, int sendserialheader)
     112              : {
     113              :     int ret = 0;
     114              : 
     115            3 :     if (con == NULL)
     116              :         return DLT_DAEMON_ERROR_UNKNOWN;
     117              : 
     118            2 :     if (sendserialheader)
     119            1 :         ret = dlt_connection_send(con, (const void*)dltSerialHeader, (size_t)sizeof(dltSerialHeader));
     120              : 
     121            2 :     if ((data1 != NULL) && (ret == DLT_RETURN_OK) && size1 > 0) {
     122            2 :         ret = dlt_connection_send(con, data1, (size_t)size1);
     123              :     }
     124              : 
     125            2 :     if ((data2 != NULL) && (ret == DLT_RETURN_OK) && size2 > 0) {
     126            2 :         ret = dlt_connection_send(con, data2, (size_t)size2);
     127              :     }
     128              : 
     129              :     return ret;
     130              : }
     131              : 
     132              : /** @brief Get the next connection filtered with a type mask.
     133              :  *
     134              :  * In some cases we need the next connection available of a specific type or
     135              :  * specific different types. This function returns the next available connection
     136              :  * that is of one of the types included in the mask. The current connection can
     137              :  * be returned.
     138              :  *
     139              :  * @param current The current connection pointer.
     140              :  * @param type_mask A bit mask representing the connection types to be filtered.
     141              :  *
     142              :  * @return The next available connection of the considered types or NULL.
     143              :  */
     144            2 : DltConnection* dlt_connection_get_next(DltConnection* current, int type_mask)
     145              : {
     146            3 :     while (current && !((1 << current->type) & type_mask))
     147            1 :         current = current->next;
     148              : 
     149            2 :     return current;
     150              : }
     151              : 
     152           10 : DLT_STATIC void dlt_connection_destroy_receiver(DltConnection* con)
     153              : {
     154           10 :     if (!con)
     155              :         return;
     156              : 
     157           10 :     switch (con->type) {
     158              :     case DLT_CONNECTION_GATEWAY:
     159              :         /* We rely on the gateway for clean-up */
     160              :         break;
     161            1 :     case DLT_CONNECTION_APP_MSG:
     162            1 :         dlt_receiver_free_global_buffer(con->receiver);
     163            1 :         free(con->receiver);
     164            1 :         con->receiver = NULL;
     165            1 :         break;
     166            6 :     default:
     167            6 :         (void)dlt_receiver_free(con->receiver);
     168            6 :         free(con->receiver);
     169            6 :         con->receiver = NULL;
     170            6 :         break;
     171              :     }
     172              : }
     173              : 
     174              : /** @brief Get the receiver structure associated to a connection.
     175              :  *
     176              :  * The receiver structure is sometimes needed while handling the event.
     177              :  * This behavior is mainly due to the fact that it's not intended to modify
     178              :  * the whole design of the daemon while implementing the new event handling.
     179              :  * Based on the connection type provided, this function returns the pointer
     180              :  * to the DltReceiver structure corresponding.
     181              :  *
     182              :  * @param daemon_local Structure where to take the DltReceiver pointer from.
     183              :  * @param type Type of the connection.
     184              :  * @param fd File descriptor
     185              :  *
     186              :  * @return DltReceiver structure or NULL if none corresponds to the type.
     187              :  */
     188            9 : DLT_STATIC DltReceiver* dlt_connection_get_receiver(DltDaemonLocal* daemon_local, DltConnectionType type, int fd)
     189              : {
     190              :     DltReceiver* ret = NULL;
     191              :     DltReceiverType receiver_type = DLT_RECEIVE_FD;
     192              :     struct stat statbuf;
     193              : 
     194            9 :     switch (type) {
     195            4 :     case DLT_CONNECTION_CONTROL_CONNECT:
     196              :     /* FALL THROUGH */
     197              :     case DLT_CONNECTION_CONTROL_MSG:
     198              :     /* FALL THROUGH */
     199              :     case DLT_CONNECTION_CLIENT_CONNECT:
     200              :     /* FALL THROUGH */
     201              :     case DLT_CONNECTION_CLIENT_MSG_TCP:
     202            4 :         ret = calloc(1, sizeof(DltReceiver));
     203              : 
     204            4 :         if (ret)
     205            4 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_SOCKET, DLT_DAEMON_RCVBUFSIZESOCK);
     206              : 
     207              :         break;
     208            1 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
     209            1 :         ret = calloc(1, sizeof(DltReceiver));
     210              : 
     211            1 :         if (ret)
     212            1 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_FD, DLT_DAEMON_RCVBUFSIZESERIAL);
     213              : 
     214              :         break;
     215            1 :     case DLT_CONNECTION_APP_MSG:
     216            1 :         ret = calloc(1, sizeof(DltReceiver));
     217              : 
     218              :         receiver_type = DLT_RECEIVE_FD;
     219              : 
     220            1 :         if (fstat(fd, &statbuf) == 0) {
     221            1 :             if (S_ISSOCK(statbuf.st_mode))
     222              :                 receiver_type = DLT_RECEIVE_SOCKET;
     223              :         } else {
     224            0 :             dlt_vlog(LOG_WARNING, "Failed to determine receive type for DLT_CONNECTION_APP_MSG, using \"FD\"\n");
     225              :         }
     226              : 
     227            1 :         if (ret)
     228            1 :             dlt_receiver_init_global_buffer(ret, fd, receiver_type, &app_recv_buffer);
     229              : 
     230              :         break;
     231              : #if defined DLT_DAEMON_USE_UNIX_SOCKET_IPC || defined DLT_DAEMON_VSOCK_IPC_ENABLE
     232              :     case DLT_CONNECTION_APP_CONNECT:
     233              :         /* FALL THROUGH */
     234              : #endif
     235            1 :     case DLT_CONNECTION_ONE_S_TIMER:
     236              :     /* FALL THROUGH */
     237              :     case DLT_CONNECTION_SIXTY_S_TIMER:
     238              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     239              :     /* FALL THROUGH */
     240              :     case DLT_CONNECTION_SYSTEMD_TIMER:
     241              : #endif
     242              :     /* FALL THROUGH */
     243              :     case DLT_CONNECTION_GATEWAY_TIMER:
     244            1 :         ret = calloc(1, sizeof(DltReceiver));
     245              : 
     246            1 :         if (ret)
     247            1 :             dlt_receiver_init(ret, fd, DLT_RECEIVE_FD, DLT_DAEMON_RCVBUFSIZE);
     248              : 
     249              :         break;
     250            2 :     case DLT_CONNECTION_GATEWAY:
     251              :         /* We rely on the gateway for init */
     252            2 :         ret = dlt_gateway_get_connection_receiver(&daemon_local->pGateway, fd);
     253            2 :         break;
     254              :     default:
     255              :         ret = NULL;
     256              :     }
     257              : 
     258            9 :     return ret;
     259              : }
     260              : 
     261              : /** @brief Get the callback from a specific connection.
     262              :  *
     263              :  * The callback retrieved that way is used to handle event for this connection.
     264              :  * It as been chosen to proceed that way instead of having the callback directly
     265              :  * in the structure in order to have some way to check that the structure is
     266              :  * still valid, or at least gracefully handle errors instead of crashing.
     267              :  *
     268              :  * @param con The connection to retrieve the callback from.
     269              :  *
     270              :  * @return Function pointer or NULL.
     271              :  */
     272          272 : void* dlt_connection_get_callback(DltConnection* con)
     273              : {
     274              :     void* ret = NULL;
     275              :     DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
     276              : 
     277          272 :     if (con)
     278          272 :         type = con->type;
     279              : 
     280          272 :     switch (type) {
     281              :     case DLT_CONNECTION_CLIENT_CONNECT:
     282              :         ret = (void*)(intptr_t)dlt_daemon_process_client_connect;
     283              :         break;
     284            0 :     case DLT_CONNECTION_CLIENT_MSG_TCP:
     285              :         ret = (void*)(intptr_t)dlt_daemon_process_client_messages;
     286            0 :         break;
     287            0 :     case DLT_CONNECTION_CLIENT_MSG_SERIAL:
     288              :         ret = (void*)(intptr_t)dlt_daemon_process_client_messages_serial;
     289            0 :         break;
     290              : #if defined DLT_DAEMON_USE_UNIX_SOCKET_IPC || defined DLT_DAEMON_VSOCK_IPC_ENABLE
     291              :     case DLT_CONNECTION_APP_CONNECT:
     292              :         ret = (void*)(intptr_t)dlt_daemon_process_app_connect;
     293              :         break;
     294              : #endif
     295          269 :     case DLT_CONNECTION_APP_MSG:
     296              :         ret = (void*)(intptr_t)dlt_daemon_process_user_messages;
     297          269 :         break;
     298            0 :     case DLT_CONNECTION_ONE_S_TIMER:
     299              :         ret = (void*)(intptr_t)dlt_daemon_process_one_s_timer;
     300            0 :         break;
     301            0 :     case DLT_CONNECTION_SIXTY_S_TIMER:
     302              :         ret = (void*)(intptr_t)dlt_daemon_process_sixty_s_timer;
     303            0 :         break;
     304              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     305              :     case DLT_CONNECTION_SYSTEMD_TIMER:
     306              :         ret = (void*)(intptr_t)dlt_daemon_process_systemd_timer;
     307              :         break;
     308              : #endif
     309            1 :     case DLT_CONNECTION_CONTROL_CONNECT:
     310              :         ret = (void*)(intptr_t)dlt_daemon_process_control_connect;
     311            1 :         break;
     312            2 :     case DLT_CONNECTION_CONTROL_MSG:
     313              :         ret = (void*)(intptr_t)dlt_daemon_process_control_messages;
     314            2 :         break;
     315            0 :     case DLT_CONNECTION_GATEWAY:
     316              :         ret = (void*)(intptr_t)dlt_gateway_process_passive_node_messages;
     317            0 :         break;
     318            0 :     case DLT_CONNECTION_GATEWAY_TIMER:
     319              :         ret = (void*)(intptr_t)dlt_gateway_process_gateway_timer;
     320            0 :         break;
     321            0 :     default:
     322              :         ret = NULL;
     323              :     }
     324              : 
     325          272 :     return ret;
     326              : }
     327              : 
     328              : /** @brief Destroys a connection.
     329              :  *
     330              :  * This function closes and frees the corresponding connection. This is expected
     331              :  * to be called by the connection owner: the DltEventHandler.
     332              :  * Ownership of the connection is given during the registration to
     333              :  * the DltEventHandler.
     334              :  *
     335              :  * @param to_destroy Connection to be destroyed.
     336              :  */
     337            9 : void dlt_connection_destroy(DltConnection* to_destroy)
     338              : {
     339            9 :     to_destroy->id = 0;
     340            9 :     close(to_destroy->receiver->fd);
     341            9 :     dlt_connection_destroy_receiver(to_destroy);
     342            9 :     free(to_destroy);
     343            9 : }
     344              : 
     345              : /** @brief Creates a connection and registers it to the DltEventHandler.
     346              :  *
     347              :  * The function will allocate memory for the connection, and give the pointer
     348              :  * to the DltEventHandler in order to register it for incoming events.
     349              :  * The connection is then destroyed later on, once it's not needed anymore or
     350              :  * it the event handler is destroyed.
     351              :  *
     352              :  * @param daemon_local Structure were some needed information is.
     353              :  * @param evh DltEventHandler to register the connection to.
     354              :  * @param fd File descriptor of the connection.
     355              :  * @param mask Event list bit mask.
     356              :  * @param type Connection type.
     357              :  *
     358              :  * @return 0 On success, -1 otherwise.
     359              :  */
     360            8 : int dlt_connection_create(DltDaemonLocal* daemon_local, DltEventHandler* evh, int fd, int mask, DltConnectionType type)
     361              : {
     362              :     DltConnection* temp = NULL;
     363              : 
     364            8 :     if (fd < 0)
     365              :         /* Nothing to do */
     366              :         return 0;
     367              : 
     368            8 :     if (dlt_event_handler_find_connection(evh, fd) != NULL)
     369              :         /* No need for the same client to be registered twice
     370              :          * for the same event.
     371              :          * TODO: If another mask can be expected,
     372              :          * we need it to update the poll event here.
     373              :          */
     374              :         return 0;
     375              : 
     376            8 :     temp = (DltConnection*)malloc(sizeof(DltConnection));
     377              : 
     378            8 :     if (temp == NULL) {
     379            0 :         dlt_log(LOG_CRIT, "Allocation of client handle failed\n");
     380            0 :         return -1;
     381              :     }
     382              : 
     383              :     memset(temp, 0, sizeof(DltConnection));
     384              : 
     385            8 :     temp->receiver = dlt_connection_get_receiver(daemon_local, type, fd);
     386              : 
     387            8 :     if (!temp->receiver) {
     388            0 :         dlt_vlog(LOG_CRIT, "Unable to get receiver from %u connection.\n", type);
     389            0 :         free(temp);
     390            0 :         return -1;
     391              :     }
     392              : 
     393              :     struct timeval timeout;
     394            8 :     timeout.tv_sec = 5;
     395            8 :     timeout.tv_usec = 0;
     396              : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     397              :     char* watchdogUSec = getenv("WATCHDOG_USEC");
     398              :     if (watchdogUSec) {
     399              :         timeout.tv_sec = atoi(watchdogUSec) / 1000000;
     400              :         timeout.tv_usec = atoi(watchdogUSec) % 1000000;
     401              :     }
     402              : #endif
     403              : 
     404            8 :     if (setsockopt(temp->receiver->fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout) < 0) {
     405            3 :         dlt_vlog(LOG_WARNING, "Unable to set send timeout %s.\n", strerror(errno));
     406              :         // as this function is used for non socket connection as well
     407              :         // we only can return an error here if it is a socket
     408            3 :         if (errno != ENOTSOCK) {
     409            1 :             free(temp);
     410            1 :             return -1;
     411              :         }
     412              :     }
     413              : 
     414              :     /* We are single threaded no need for protection. */
     415            7 :     temp->id = connectionId++;
     416              : 
     417            7 :     if (!temp->id)
     418              :         /* Skipping 0 */
     419            2 :         temp->id = connectionId++;
     420              : 
     421            7 :     temp->type = type;
     422            7 :     temp->status = ACTIVE;
     423              : 
     424              :     /* Now give the ownership of the newly created connection
     425              :      * to the event handler, by registering for events.
     426              :      */
     427            7 :     return dlt_event_handler_register_connection(evh, daemon_local, temp, mask);
     428              : }
        

Generated by: LCOV version 2.0-1