1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(log_backend_net, CONFIG_LOG_DEFAULT_LEVEL);
9
10 #include <zephyr/sys/util_macro.h>
11 #include <zephyr/logging/log_backend.h>
12 #include <zephyr/logging/log_core.h>
13 #include <zephyr/logging/log_output.h>
14 #include <zephyr/logging/log_backend_net.h>
15 #include <zephyr/net/hostname.h>
16 #include <zephyr/net/net_if.h>
17 #include <zephyr/net/socket.h>
18
19 /* Set this to 1 if you want to see what is being sent to server */
20 #define DEBUG_PRINTING 0
21
22 #define DBG(fmt, ...) IF_ENABLED(DEBUG_PRINTING, (printk(fmt, ##__VA_ARGS__)))
23
24 #if defined(CONFIG_NET_IPV6) || CONFIG_NET_HOSTNAME_ENABLE
25 #define MAX_HOSTNAME_LEN NET_IPV6_ADDR_LEN
26 #else
27 #define MAX_HOSTNAME_LEN NET_IPV4_ADDR_LEN
28 #endif
29
30 static char dev_hostname[MAX_HOSTNAME_LEN + 1];
31
32 static uint8_t output_buf[CONFIG_LOG_BACKEND_NET_MAX_BUF_SIZE];
33 static bool net_init_done;
34 struct sockaddr server_addr;
35 static bool panic_mode;
36 static uint32_t log_format_current = CONFIG_LOG_BACKEND_NET_OUTPUT_DEFAULT;
37
38 static struct log_backend_net_ctx {
39 int sock;
40 bool is_tcp;
41 } ctx = {
42 .sock = -1,
43 };
44
line_out(uint8_t * data,size_t length,void * output_ctx)45 static int line_out(uint8_t *data, size_t length, void *output_ctx)
46 {
47 struct log_backend_net_ctx *ctx = (struct log_backend_net_ctx *)output_ctx;
48 int ret = -ENOMEM;
49 struct msghdr msg = { 0 };
50 struct iovec io_vector[2];
51 int pos = 0;
52
53 if (ctx == NULL) {
54 return length;
55 }
56
57 #if defined(CONFIG_NET_TCP)
58 char len[sizeof("123456789")];
59
60 if (ctx->is_tcp) {
61 (void)snprintk(len, sizeof(len), "%zu ", length);
62 io_vector[pos].iov_base = (void *)len;
63 io_vector[pos].iov_len = strlen(len);
64 pos++;
65 }
66 #else
67 if (ctx->is_tcp) {
68 return -ENOTSUP;
69 }
70 #endif
71
72 io_vector[pos].iov_base = (void *)data;
73 io_vector[pos].iov_len = length;
74 pos++;
75
76 msg.msg_iov = io_vector;
77 msg.msg_iovlen = pos;
78
79 ret = zsock_sendmsg(ctx->sock, &msg, ctx->is_tcp ? 0 : ZSOCK_MSG_DONTWAIT);
80 if (ret < 0) {
81 goto fail;
82 }
83
84 DBG(data);
85 fail:
86 return length;
87 }
88
89 LOG_OUTPUT_DEFINE(log_output_net, line_out, output_buf, sizeof(output_buf));
90
do_net_init(struct log_backend_net_ctx * ctx)91 static int do_net_init(struct log_backend_net_ctx *ctx)
92 {
93 struct sockaddr *local_addr = NULL;
94 struct sockaddr_in6 local_addr6 = {0};
95 struct sockaddr_in local_addr4 = {0};
96 socklen_t server_addr_len;
97 int ret, proto = IPPROTO_UDP, type = SOCK_DGRAM;
98
99 if (IS_ENABLED(CONFIG_NET_IPV4) && server_addr.sa_family == AF_INET) {
100 local_addr = (struct sockaddr *)&local_addr4;
101 server_addr_len = sizeof(struct sockaddr_in);
102 local_addr4.sin_port = 0U;
103 }
104
105 if (IS_ENABLED(CONFIG_NET_IPV6) && server_addr.sa_family == AF_INET6) {
106 local_addr = (struct sockaddr *)&local_addr6;
107 server_addr_len = sizeof(struct sockaddr_in6);
108 local_addr6.sin6_port = 0U;
109 }
110
111 if (local_addr == NULL) {
112 DBG("Server address unknown\n");
113 return -EINVAL;
114 }
115
116 local_addr->sa_family = server_addr.sa_family;
117
118 if (ctx->is_tcp) {
119 proto = IPPROTO_TCP;
120 type = SOCK_STREAM;
121 }
122
123 ret = zsock_socket(server_addr.sa_family, type, proto);
124 if (ret < 0) {
125 ret = -errno;
126 DBG("Cannot get socket (%d)\n", ret);
127 return ret;
128 }
129
130 ctx->sock = ret;
131
132 if (IS_ENABLED(CONFIG_NET_HOSTNAME_ENABLE)) {
133 (void)strncpy(dev_hostname, net_hostname_get(), MAX_HOSTNAME_LEN);
134
135 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
136 server_addr.sa_family == AF_INET6) {
137 const struct in6_addr *src;
138
139 src = net_if_ipv6_select_src_addr(
140 NULL, &net_sin6(&server_addr)->sin6_addr);
141 if (src) {
142 net_addr_ntop(AF_INET6, src, dev_hostname,
143 MAX_HOSTNAME_LEN);
144
145 net_ipaddr_copy(&local_addr6.sin6_addr, src);
146 } else {
147 goto unknown;
148 }
149
150 } else if (IS_ENABLED(CONFIG_NET_IPV4) &&
151 server_addr.sa_family == AF_INET) {
152 const struct in_addr *src;
153
154 src = net_if_ipv4_select_src_addr(
155 NULL, &net_sin(&server_addr)->sin_addr);
156
157 if (src) {
158 net_addr_ntop(AF_INET, src, dev_hostname,
159 MAX_HOSTNAME_LEN);
160
161 net_ipaddr_copy(&local_addr4.sin_addr, src);
162 } else {
163 goto unknown;
164 }
165
166 } else {
167 unknown:
168 DBG("Cannot setup local socket\n");
169 ret = -EINVAL;
170 goto err;
171 }
172
173 ret = zsock_bind(ctx->sock, local_addr, server_addr_len);
174 if (ret < 0) {
175 ret = -errno;
176 DBG("Cannot bind socket (%d)\n", ret);
177 goto err;
178 }
179
180 ret = zsock_connect(ctx->sock, &server_addr, server_addr_len);
181 if (ret < 0) {
182 ret = -errno;
183 DBG("Cannot connect socket (%d)\n", ret);
184 goto err;
185 }
186
187 log_output_ctx_set(&log_output_net, ctx);
188 log_output_hostname_set(&log_output_net, dev_hostname);
189
190 return 0;
191
192 err:
193 (void)zsock_close(ctx->sock);
194 ctx->sock = -1;
195
196 return ret;
197 }
198
process(const struct log_backend * const backend,union log_msg_generic * msg)199 static void process(const struct log_backend *const backend,
200 union log_msg_generic *msg)
201 {
202 uint32_t flags = LOG_OUTPUT_FLAG_FORMAT_SYSLOG |
203 LOG_OUTPUT_FLAG_TIMESTAMP |
204 LOG_OUTPUT_FLAG_THREAD;
205
206 if (panic_mode) {
207 return;
208 }
209
210 if (!net_init_done && do_net_init(&ctx) == 0) {
211 net_init_done = true;
212 }
213
214 log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
215
216 log_output_func(&log_output_net, &msg->log, flags);
217 }
218
format_set(const struct log_backend * const backend,uint32_t log_type)219 static int format_set(const struct log_backend *const backend, uint32_t log_type)
220 {
221 log_format_current = log_type;
222 return 0;
223 }
224
check_net_init_done(void)225 static bool check_net_init_done(void)
226 {
227 bool ret = false;
228
229 if (net_init_done) {
230 /* Release context so it can be recreated with the specified ip address
231 * next time process() is called
232 */
233 struct log_backend_net_ctx *ctx = log_output_net.control_block->ctx;
234 int released;
235
236 released = zsock_close(ctx->sock);
237 if (released < 0) {
238 LOG_ERR("Cannot release socket (%d)", ret);
239 ret = false;
240 } else {
241 /* The socket is successfully closed so we flag it
242 * to be recreated with the new ip address
243 */
244 net_init_done = false;
245 ret = true;
246 }
247
248 ctx->sock = -1;
249
250 return ret;
251 }
252
253 return true;
254 }
255
log_backend_net_set_addr(const char * addr)256 bool log_backend_net_set_addr(const char *addr)
257 {
258 bool ret = check_net_init_done();
259
260 if (!ret) {
261 return ret;
262 }
263
264 net_sin(&server_addr)->sin_port = htons(514);
265
266 ret = net_ipaddr_parse(addr, strlen(addr), &server_addr);
267 if (!ret) {
268 LOG_ERR("Cannot parse syslog server address");
269 return ret;
270 }
271
272 return ret;
273 }
274
log_backend_net_set_ip(const struct sockaddr * addr)275 bool log_backend_net_set_ip(const struct sockaddr *addr)
276 {
277 bool ret = check_net_init_done();
278
279 if (!ret) {
280 return ret;
281 }
282
283 if ((IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) ||
284 (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6)) {
285 memcpy(&server_addr, addr, sizeof(server_addr));
286
287 net_port_set_default(&server_addr, 514);
288 } else {
289 LOG_ERR("Unknown address family");
290 return false;
291 }
292
293 return ret;
294 }
295
296 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
log_backend_net_hostname_set(char * hostname,size_t len)297 void log_backend_net_hostname_set(char *hostname, size_t len)
298 {
299 (void)strncpy(dev_hostname, hostname, MIN(len, MAX_HOSTNAME_LEN));
300 log_output_hostname_set(&log_output_net, dev_hostname);
301 }
302 #endif
303
log_backend_net_start(void)304 void log_backend_net_start(void)
305 {
306 const struct log_backend *backend = log_backend_net_get();
307
308 if (!log_backend_is_active(backend)) {
309 log_backend_activate(backend, backend->cb->ctx);
310 }
311 }
312
init_net(struct log_backend const * const backend)313 static void init_net(struct log_backend const *const backend)
314 {
315 ARG_UNUSED(backend);
316
317 if (strlen(CONFIG_LOG_BACKEND_NET_SERVER) != 0) {
318 const char *server = CONFIG_LOG_BACKEND_NET_SERVER;
319 bool ret;
320
321 if (memcmp(server, "tcp://", sizeof("tcp://") - 1) == 0) {
322 server += sizeof("tcp://") - 1;
323 ctx.is_tcp = true;
324 }
325
326 ret = log_backend_net_set_addr(server);
327 if (!ret) {
328 return;
329 }
330 }
331
332 log_backend_deactivate(log_backend_net_get());
333 }
334
panic(struct log_backend const * const backend)335 static void panic(struct log_backend const *const backend)
336 {
337 panic_mode = true;
338 }
339
340 const struct log_backend_api log_backend_net_api = {
341 .panic = panic,
342 .init = init_net,
343 .process = process,
344 .format_set = format_set,
345 };
346
347 /* Note that the backend can be activated only after we have networking
348 * subsystem ready so we must not start it immediately.
349 */
350 LOG_BACKEND_DEFINE(log_backend_net, log_backend_net_api,
351 IS_ENABLED(CONFIG_LOG_BACKEND_NET_AUTOSTART));
352
log_backend_net_get(void)353 const struct log_backend *log_backend_net_get(void)
354 {
355 return &log_backend_net;
356 }
357