LCOV - code coverage report
Current view: top level - daemon - dlt_daemon_socket.c (source / functions) Hit Total Coverage
Test: dlt_final_coverage.info Lines: 31 59 52.5 %
Date: 2024-12-06 04:41:42 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX license identifier: MPL-2.0
       3             :  *
       4             :  * Copyright (C) 2011-2015, BMW AG
       5             :  *
       6             :  * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
       7             :  *
       8             :  * This Source Code Form is subject to the terms of the
       9             :  * Mozilla Public License (MPL), v. 2.0.
      10             :  * If a copy of the MPL was not distributed with this file,
      11             :  * You can obtain one at http://mozilla.org/MPL/2.0/.
      12             :  *
      13             :  * For further information see http://www.covesa.org/.
      14             :  */
      15             : 
      16             : /*!
      17             :  * \author
      18             :  * Alexander Wenzel <alexander.aw.wenzel@bmw.de>
      19             :  * Markus Klein <Markus.Klein@esk.fraunhofer.de>
      20             :  * Mikko Rapeli <mikko.rapeli@bmw.de>
      21             :  *
      22             :  * \copyright Copyright © 2011-2015 BMW AG. \n
      23             :  * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
      24             :  *
      25             :  * \file dlt_daemon_socket.c
      26             :  */
      27             : 
      28             : 
      29             : #include <netdb.h>
      30             : #include <ctype.h>
      31             : #include <stdio.h>      /* for printf() and fprintf() */
      32             : #include <sys/socket.h> /* for socket(), connect(), (), and recv() */
      33             : #include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
      34             : #include <stdlib.h>     /* for atoi() and exit() */
      35             : #include <string.h>     /* for memset() */
      36             : #include <unistd.h>     /* for close() */
      37             : #include <signal.h>
      38             : #include <syslog.h>
      39             : #include <errno.h>
      40             : #include <pthread.h>
      41             : #include <sys/ioctl.h>
      42             : 
      43             : #ifdef linux
      44             : #include <sys/timerfd.h>
      45             : #endif
      46             : #include <sys/time.h>
      47             : #if defined(linux) && defined(__NR_statx)
      48             : #include <linux/stat.h>
      49             : #endif
      50             : 
      51             : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
      52             : #include <systemd/sd-daemon.h>
      53             : #endif
      54             : 
      55             : #include "dlt_types.h"
      56             : #include "dlt_log.h"
      57             : #include "dlt-daemon.h"
      58             : #include "dlt-daemon_cfg.h"
      59             : #include "dlt_daemon_common_cfg.h"
      60             : 
      61             : #include "dlt_daemon_socket.h"
      62             : 
      63           9 : int dlt_daemon_socket_open(int *sock, unsigned int servPort, char *ip)
      64             : {
      65           9 :     int yes = 1;
      66             :     int ret_inet_pton = 1;
      67             :     int lastErrno = 0;
      68             : 
      69             : #ifdef DLT_USE_IPv6
      70             : 
      71             :     /* create socket */
      72           9 :     if ((*sock = socket(AF_INET6, SOCK_STREAM, 0)) == -1) {
      73           0 :         lastErrno = errno;
      74           0 :         dlt_vlog(LOG_ERR, "dlt_daemon_socket_open: socket() error %d: %s\n", lastErrno,
      75             :                  strerror(lastErrno));
      76           0 :         return -1;
      77             :     }
      78             : 
      79             : #else
      80             : 
      81             :     if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
      82             :         lastErrno = errno;
      83             :         dlt_vlog(LOG_ERR, "dlt_daemon_socket_open: socket() error %d: %s\n", lastErrno,
      84             :                  strerror(lastErrno));
      85             :         return -1;
      86             :     }
      87             : 
      88             : #endif
      89             : 
      90           9 :     dlt_vlog(LOG_INFO, "%s: Socket created\n", __FUNCTION__);
      91             : 
      92             :     /* setsockpt SO_REUSEADDR */
      93           9 :     if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
      94           0 :         lastErrno = errno;
      95           0 :         dlt_vlog(
      96             :             LOG_ERR,
      97             :             "dlt_daemon_socket_open: Setsockopt error %d in dlt_daemon_local_connection_init: %s\n",
      98             :             lastErrno,
      99             :             strerror(lastErrno));
     100           0 :         return -1;
     101             :     }
     102             : 
     103             :     /* bind */
     104             : #ifdef DLT_USE_IPv6
     105             :     struct sockaddr_in6 forced_addr;
     106             :     memset(&forced_addr, 0, sizeof(forced_addr));
     107           9 :     forced_addr.sin6_family = AF_INET6;
     108           9 :     forced_addr.sin6_port = htons(servPort);
     109             : 
     110           9 :     if (0 == strcmp(ip, "0.0.0.0")) {
     111           9 :         forced_addr.sin6_addr = in6addr_any;
     112             :     } else {
     113           0 :         ret_inet_pton = inet_pton(AF_INET6, ip, &forced_addr.sin6_addr);
     114             :     }
     115             : 
     116             : #else
     117             :     struct sockaddr_in forced_addr;
     118             :     memset(&forced_addr, 0, sizeof(forced_addr));
     119             :     forced_addr.sin_family = AF_INET;
     120             :     forced_addr.sin_port = htons(servPort);
     121             :     ret_inet_pton = inet_pton(AF_INET, ip, &forced_addr.sin_addr);
     122             : #endif
     123             : 
     124             :     /* inet_pton returns 1 on success */
     125           0 :     if (ret_inet_pton != 1) {
     126           0 :         lastErrno = errno;
     127           0 :         dlt_vlog(
     128             :             LOG_WARNING,
     129             :             "dlt_daemon_socket_open: inet_pton() error %d: %s. Cannot convert IP address: %s\n",
     130             :             lastErrno,
     131             :             strerror(lastErrno),
     132             :             ip);
     133           0 :         return -1;
     134             :     }
     135             : 
     136           9 :     if (bind(*sock, (struct sockaddr *)&forced_addr, sizeof(forced_addr)) == -1) {
     137           0 :         lastErrno = errno;     /*close() may set errno too */
     138           0 :         close(*sock);
     139           0 :         dlt_vlog(LOG_WARNING, "dlt_daemon_socket_open: bind() error %d: %s\n", lastErrno,
     140             :                  strerror(lastErrno));
     141           0 :         return -1;
     142             :     }
     143             : 
     144             :     /*listen */
     145           9 :     dlt_vlog(LOG_INFO, "%s: Listening on ip %s and port: %u\n", __FUNCTION__, ip, servPort);
     146             : 
     147             :     /* get socket buffer size */
     148           9 :     dlt_vlog(LOG_INFO, "dlt_daemon_socket_open: Socket send queue size: %d\n",
     149             :              dlt_daemon_socket_get_send_qeue_max_size(*sock));
     150             : 
     151           9 :     if (listen(*sock, 3) < 0) {
     152           0 :         lastErrno = errno;
     153           0 :         dlt_vlog(LOG_WARNING,
     154             :                  "dlt_daemon_socket_open: listen() failed with error %d: %s\n",
     155             :                  lastErrno,
     156             :                  strerror(lastErrno));
     157           0 :         return -1;
     158             :     }
     159             : 
     160             :     return 0; /* OK */
     161             : }
     162             : 
     163           0 : int dlt_daemon_socket_close(int sock)
     164             : {
     165           0 :     close(sock);
     166             : 
     167           0 :     return 0;
     168             : }
     169             : 
     170          16 : int dlt_daemon_socket_send(int sock,
     171             :                            void *data1,
     172             :                            int size1,
     173             :                            void *data2,
     174             :                            int size2,
     175             :                            char serialheader)
     176             : {
     177             :     int ret = DLT_RETURN_OK;
     178             : 
     179             :     /* Optional: Send serial header, if requested */
     180          16 :     if (serialheader) {
     181           0 :         ret = dlt_daemon_socket_sendreliable(sock,
     182             :                                              (void *)dltSerialHeader,
     183             :                                              sizeof(dltSerialHeader));
     184             : 
     185           0 :         if (ret != DLT_RETURN_OK) {
     186             :             return ret;
     187             :         }
     188             :     }
     189             : 
     190             :     /* Send data */
     191          16 :     if ((data1 != NULL) && (size1 > 0)) {
     192          16 :         ret = dlt_daemon_socket_sendreliable(sock, data1, size1);
     193             : 
     194          16 :         if (ret != DLT_RETURN_OK) {
     195             :             return ret;
     196             :         }
     197             :     }
     198             : 
     199          16 :     if ((data2 != NULL) && (size2 > 0)) {
     200          16 :         ret = dlt_daemon_socket_sendreliable(sock, data2, size2);
     201             :     }
     202             : 
     203             :     return ret;
     204             : }
     205             : 
     206           9 : int dlt_daemon_socket_get_send_qeue_max_size(int sock)
     207             : {
     208           9 :     int n = 0;
     209           9 :     socklen_t m = sizeof(n);
     210           9 :     if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&n, &m) < 0) {
     211           0 :         dlt_vlog(LOG_ERR,
     212             :                  "%s: socket get failed!\n", __func__);
     213           0 :         return -errno;
     214             :     }
     215             : 
     216           9 :     return n;
     217             : }
     218             : 
     219         466 : int dlt_daemon_socket_sendreliable(int sock, void *data_buffer, int message_size)
     220             : {
     221             :     int data_sent = 0;
     222             : 
     223         932 :     while (data_sent < message_size) {
     224         466 :         ssize_t ret = send(sock,
     225             :                            (uint8_t *)data_buffer + data_sent,
     226         466 :                            message_size - data_sent,
     227             :                            0);
     228             : 
     229         466 :         if (ret < 0) {
     230           0 :             dlt_vlog(LOG_WARNING,
     231           0 :                      "%s: socket send failed [errno: %d]!\n", __func__, errno);
     232             : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
     233             :             /* notify systemd here that we are still alive
     234             :              * otherwise we might miss notifying the watchdog when
     235             :              * the watchdog interval is small and multiple timeouts occur back to back
     236             :              */
     237             :             if (sd_notify(0, "WATCHDOG=1") < 0)
     238             :                 dlt_vlog(LOG_WARNING, "%s: Could not reset systemd watchdog\n", __func__);
     239             : #endif
     240           0 :             return DLT_DAEMON_ERROR_SEND_FAILED;
     241             :         } else {
     242         466 :             data_sent += ret;
     243             :         }
     244             :     }
     245             : 
     246             :     return DLT_DAEMON_ERROR_OK;
     247             : }

Generated by: LCOV version 1.14