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 931 : 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 1 : dlt_vlog(LOG_WARNING,
231 1 : "%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 1 : return DLT_DAEMON_ERROR_SEND_FAILED;
241 : } else {
242 465 : data_sent += ret;
243 : }
244 : }
245 :
246 : return DLT_DAEMON_ERROR_OK;
247 : }
|