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 9 : int dlt_daemon_socket_open(int *sock, unsigned int servPort, char *ip)
69 : {
70 9 : int yes = 1;
71 : int ret_inet_pton = 1;
72 : int lastErrno = 0;
73 :
74 : #ifdef DLT_USE_IPv6
75 :
76 : /* create socket */
77 9 : 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,
80 : strerror(lastErrno));
81 0 : return -1;
82 : }
83 :
84 : #else
85 :
86 : if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
87 : lastErrno = errno;
88 : dlt_vlog(LOG_ERR, "dlt_daemon_socket_open: socket() error %d: %s\n", lastErrno,
89 : strerror(lastErrno));
90 : return -1;
91 : }
92 :
93 : #endif
94 :
95 9 : dlt_vlog(LOG_INFO, "%s: Socket created\n", __func__);
96 :
97 : /* setsockpt SO_REUSEADDR */
98 9 : if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
99 0 : lastErrno = errno;
100 0 : dlt_vlog(
101 : LOG_ERR,
102 : "dlt_daemon_socket_open: Setsockopt error %d in dlt_daemon_local_connection_init: %s\n",
103 : lastErrno,
104 : strerror(lastErrno));
105 0 : return -1;
106 : }
107 :
108 : /* bind */
109 : #ifdef DLT_USE_IPv6
110 : struct sockaddr_in6 forced_addr;
111 : memset(&forced_addr, 0, sizeof(forced_addr));
112 9 : forced_addr.sin6_family = AF_INET6;
113 9 : forced_addr.sin6_port = htons(servPort);
114 :
115 9 : if (0 == strcmp(ip, "0.0.0.0")) {
116 9 : forced_addr.sin6_addr = in6addr_any;
117 : } else {
118 0 : ret_inet_pton = inet_pton(AF_INET6, ip, &forced_addr.sin6_addr);
119 : }
120 :
121 : #else
122 : struct sockaddr_in forced_addr;
123 : memset(&forced_addr, 0, sizeof(forced_addr));
124 : forced_addr.sin_family = AF_INET;
125 : forced_addr.sin_port = htons(servPort);
126 : ret_inet_pton = inet_pton(AF_INET, ip, &forced_addr.sin_addr);
127 : #endif
128 :
129 : /* inet_pton returns 1 on success */
130 0 : if (ret_inet_pton != 1) {
131 0 : lastErrno = errno;
132 0 : dlt_vlog(
133 : LOG_WARNING,
134 : "dlt_daemon_socket_open: inet_pton() error %d: %s. Cannot convert IP address: %s\n",
135 : lastErrno,
136 : strerror(lastErrno),
137 : ip);
138 0 : return -1;
139 : }
140 :
141 9 : if (bind(*sock, (struct sockaddr *)&forced_addr, sizeof(forced_addr)) == -1) {
142 0 : lastErrno = errno; /*close() may set errno too */
143 0 : close(*sock);
144 0 : dlt_vlog(LOG_WARNING, "dlt_daemon_socket_open: bind() error %d: %s\n", lastErrno,
145 : strerror(lastErrno));
146 0 : return -1;
147 : }
148 :
149 : /*listen */
150 9 : dlt_vlog(LOG_INFO, "%s: Listening on ip %s and port: %u\n", __func__, ip, servPort);
151 :
152 : /* get socket buffer size */
153 9 : dlt_vlog(LOG_INFO, "dlt_daemon_socket_open: Socket send queue size: %d\n",
154 : dlt_daemon_socket_get_send_qeue_max_size(*sock));
155 :
156 9 : if (listen(*sock, 3) < 0) {
157 0 : lastErrno = errno;
158 0 : dlt_vlog(LOG_WARNING,
159 : "dlt_daemon_socket_open: listen() failed with error %d: %s\n",
160 : lastErrno,
161 : strerror(lastErrno));
162 0 : return -1;
163 : }
164 :
165 : return 0; /* OK */
166 : }
167 :
168 0 : int dlt_daemon_socket_close(int sock)
169 : {
170 0 : close(sock);
171 :
172 0 : return 0;
173 : }
174 :
175 16 : int dlt_daemon_socket_send(int sock,
176 : void *data1,
177 : int size1,
178 : void *data2,
179 : int size2,
180 : char serialheader)
181 : {
182 : int ret = DLT_RETURN_OK;
183 :
184 : /* Optional: Send serial header, if requested */
185 16 : if (serialheader) {
186 0 : ret = dlt_daemon_socket_sendreliable(sock,
187 : dltSerialHeader,
188 : sizeof(dltSerialHeader));
189 :
190 0 : if (ret != DLT_RETURN_OK) {
191 : return ret;
192 : }
193 : }
194 :
195 : /* Send data */
196 16 : if ((data1 != NULL) && (size1 > 0)) {
197 16 : ret = dlt_daemon_socket_sendreliable(sock, data1, size1);
198 :
199 16 : if (ret != DLT_RETURN_OK) {
200 : return ret;
201 : }
202 : }
203 :
204 16 : if ((data2 != NULL) && (size2 > 0)) {
205 16 : ret = dlt_daemon_socket_sendreliable(sock, data2, size2);
206 : }
207 :
208 : return ret;
209 : }
210 :
211 9 : int dlt_daemon_socket_get_send_qeue_max_size(int sock)
212 : {
213 9 : int n = 0;
214 9 : socklen_t m = sizeof(n);
215 9 : if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&n, &m) < 0) {
216 0 : dlt_vlog(LOG_ERR,
217 : "%s: socket get failed!\n", __func__);
218 0 : return -errno;
219 : }
220 :
221 9 : return n;
222 : }
223 :
224 466 : int dlt_daemon_socket_sendreliable(int sock, const void *data_buffer, int message_size)
225 : {
226 : int data_sent = 0;
227 :
228 932 : while (data_sent < message_size) {
229 466 : ssize_t ret = send(sock,
230 : (const uint8_t *)data_buffer + data_sent,
231 466 : (size_t)(message_size - data_sent),
232 : 0);
233 :
234 466 : if (ret < 0) {
235 0 : dlt_vlog(LOG_WARNING,
236 0 : "%s: socket send failed [errno: %d]!\n", __func__, errno);
237 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
238 : /* notify systemd here that we are still alive
239 : * otherwise we might miss notifying the watchdog when
240 : * the watchdog interval is small and multiple timeouts occur back to back
241 : */
242 : if (sd_notify(0, "WATCHDOG=1") < 0)
243 : dlt_vlog(LOG_WARNING, "%s: Could not reset systemd watchdog\n", __func__);
244 : #endif
245 0 : return DLT_DAEMON_ERROR_SEND_FAILED;
246 : } else {
247 466 : data_sent += ret;
248 : }
249 : }
250 :
251 : return DLT_DAEMON_ERROR_OK;
252 : }
|