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