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 :
34 : #pragma GCC diagnostic ignored "-Wconversion"
35 : #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
36 : #pragma GCC diagnostic push
37 : #pragma GCC diagnostic pop
38 :
39 : #include <stdlib.h> /* for atoi() and exit() */
40 : #include <string.h> /* for memset() */
41 : #include <unistd.h> /* for close() */
42 : #include <signal.h>
43 : #include <syslog.h>
44 : #include <errno.h>
45 : #include <pthread.h>
46 : #include <sys/ioctl.h>
47 :
48 : #ifdef linux
49 : #include <sys/timerfd.h>
50 : #endif
51 : #include <sys/time.h>
52 : #if defined(linux) && defined(__NR_statx)
53 : #include <linux/stat.h>
54 : #endif
55 :
56 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
57 : #include <systemd/sd-daemon.h>
58 : #endif
59 :
60 : #include "dlt_types.h"
61 : #include "dlt_log.h"
62 : #include "dlt-daemon.h"
63 : #include "dlt-daemon_cfg.h"
64 : #include "dlt_daemon_common_cfg.h"
65 :
66 : #include "dlt_daemon_socket.h"
67 :
68 1 : int dlt_daemon_socket_open(int* sock, unsigned int servPort, char* ip)
69 : {
70 1 : int yes = 1;
71 : int ret_inet_pton = 1;
72 : int lastErrno = 0;
73 :
74 : #ifdef DLT_USE_IPv6
75 :
76 : /* create socket */
77 1 : if ((*sock = socket(AF_INET6, SOCK_STREAM, 0)) == -1) {
78 0 : lastErrno = errno;
79 0 : dlt_vlog(LOG_ERR, "dlt_daemon_socket_open: socket() error %d: %s\n", lastErrno, strerror(lastErrno));
80 0 : return -1;
81 : }
82 :
83 : #else
84 :
85 : if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
86 : lastErrno = errno;
87 : dlt_vlog(LOG_ERR, "dlt_daemon_socket_open: socket() error %d: %s\n", lastErrno, strerror(lastErrno));
88 : return -1;
89 : }
90 :
91 : #endif
92 :
93 1 : dlt_vlog(LOG_INFO, "%s: Socket created\n", __func__);
94 :
95 : /* setsockpt SO_REUSEADDR */
96 1 : if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
97 0 : lastErrno = errno;
98 0 : dlt_vlog(
99 : LOG_ERR, "dlt_daemon_socket_open: Setsockopt error %d in dlt_daemon_local_connection_init: %s\n", lastErrno,
100 : strerror(lastErrno));
101 0 : return -1;
102 : }
103 :
104 : /* bind */
105 : #ifdef DLT_USE_IPv6
106 : struct sockaddr_in6 forced_addr;
107 : memset(&forced_addr, 0, sizeof(forced_addr));
108 1 : forced_addr.sin6_family = AF_INET6;
109 1 : forced_addr.sin6_port = htons(servPort);
110 :
111 1 : if (0 == strcmp(ip, "0.0.0.0")) {
112 1 : forced_addr.sin6_addr = in6addr_any;
113 : } else {
114 0 : ret_inet_pton = inet_pton(AF_INET6, ip, &forced_addr.sin6_addr);
115 : }
116 :
117 : #else
118 : struct sockaddr_in forced_addr;
119 : memset(&forced_addr, 0, sizeof(forced_addr));
120 : forced_addr.sin_family = AF_INET;
121 : forced_addr.sin_port = htons(servPort);
122 : ret_inet_pton = inet_pton(AF_INET, ip, &forced_addr.sin_addr);
123 : #endif
124 :
125 : /* inet_pton returns 1 on success */
126 0 : if (ret_inet_pton != 1) {
127 0 : lastErrno = errno;
128 0 : dlt_vlog(
129 : LOG_WARNING, "dlt_daemon_socket_open: inet_pton() error %d: %s. Cannot convert IP address: %s\n", lastErrno,
130 : strerror(lastErrno), ip);
131 0 : return -1;
132 : }
133 :
134 1 : if (bind(*sock, (struct sockaddr*)&forced_addr, sizeof(forced_addr)) == -1) {
135 0 : lastErrno = errno; /*close() may set errno too */
136 0 : close(*sock);
137 0 : dlt_vlog(LOG_WARNING, "dlt_daemon_socket_open: bind() error %d: %s\n", lastErrno, strerror(lastErrno));
138 0 : return -1;
139 : }
140 :
141 : /*listen */
142 1 : dlt_vlog(LOG_INFO, "%s: Listening on ip %s and port: %u\n", __func__, ip, servPort);
143 :
144 : /* get socket buffer size */
145 1 : dlt_vlog(
146 : LOG_INFO, "dlt_daemon_socket_open: Socket send queue size: %d\n",
147 : dlt_daemon_socket_get_send_qeue_max_size(*sock));
148 :
149 1 : if (listen(*sock, 3) < 0) {
150 0 : lastErrno = errno;
151 0 : dlt_vlog(
152 : LOG_WARNING, "dlt_daemon_socket_open: listen() failed with error %d: %s\n", lastErrno, strerror(lastErrno));
153 0 : return -1;
154 : }
155 :
156 : return 0; /* OK */
157 : }
158 :
159 0 : int dlt_daemon_socket_close(int sock)
160 : {
161 0 : close(sock);
162 :
163 0 : return 0;
164 : }
165 :
166 1 : int dlt_daemon_socket_send(int sock, void* data1, int size1, void* data2, int size2, char serialheader)
167 : {
168 : int ret = DLT_RETURN_OK;
169 :
170 : /* Optional: Send serial header, if requested */
171 1 : if (serialheader) {
172 0 : ret = dlt_daemon_socket_sendreliable(sock, dltSerialHeader, sizeof(dltSerialHeader));
173 :
174 0 : if (ret != DLT_RETURN_OK) {
175 : return ret;
176 : }
177 : }
178 :
179 : /* Send data */
180 1 : if ((data1 != NULL) && (size1 > 0)) {
181 1 : ret = dlt_daemon_socket_sendreliable(sock, data1, size1);
182 :
183 1 : if (ret != DLT_RETURN_OK) {
184 : return ret;
185 : }
186 : }
187 :
188 1 : if ((data2 != NULL) && (size2 > 0)) {
189 1 : ret = dlt_daemon_socket_sendreliable(sock, data2, size2);
190 : }
191 :
192 : return ret;
193 : }
194 :
195 1 : int dlt_daemon_socket_get_send_qeue_max_size(int sock)
196 : {
197 1 : int n = 0;
198 1 : socklen_t m = sizeof(n);
199 1 : if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&n, &m) < 0) {
200 0 : dlt_vlog(LOG_ERR, "%s: socket get failed!\n", __func__);
201 0 : return -errno;
202 : }
203 :
204 1 : return n;
205 : }
206 :
207 8 : int dlt_daemon_socket_sendreliable(int sock, const void* data_buffer, int message_size)
208 : {
209 : int data_sent = 0;
210 :
211 16 : while (data_sent < message_size) {
212 8 : ssize_t ret = send(sock, (const uint8_t*)data_buffer + data_sent, (size_t)(message_size - data_sent), 0);
213 :
214 8 : if (ret < 0) {
215 0 : dlt_vlog(LOG_WARNING, "%s: socket send failed [errno: %d]!\n", __func__, errno);
216 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
217 : /* notify systemd here that we are still alive
218 : * otherwise we might miss notifying the watchdog when
219 : * the watchdog interval is small and multiple timeouts occur back to back
220 : */
221 : if (sd_notify(0, "WATCHDOG=1") < 0)
222 : dlt_vlog(LOG_WARNING, "%s: Could not reset systemd watchdog\n", __func__);
223 : #endif
224 0 : return DLT_DAEMON_ERROR_SEND_FAILED;
225 : } else {
226 8 : data_sent += ret;
227 : }
228 : }
229 :
230 : return DLT_DAEMON_ERROR_OK;
231 : }
|