1 /*
2 * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <net/dns_sd.h>
9 #include <net/socket.h>
10 #include <posix/netinet/in.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <zephyr.h>
15
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(mdns_echo_service, LOG_LEVEL_DBG);
18
19 /* A default port of 0 causes bind(2) to request an ephemeral port */
20 #define DEFAULT_PORT 0
21
welcome(int fd)22 static int welcome(int fd)
23 {
24 static const char msg[] = "Bonjour, Zephyr world!\n";
25
26 return send(fd, msg, sizeof(msg), 0);
27 }
28
29 /* This is mainly here to bind to a port to get service advertisement
30 * to work.. but since we're already here we might as well do something
31 * useful.
32 */
service(void)33 void service(void)
34 {
35 int r;
36 int server_fd;
37 int client_fd;
38 socklen_t len;
39 void *addrp;
40 uint16_t *portp;
41 struct sockaddr client_addr;
42 char addrstr[INET6_ADDRSTRLEN];
43 uint8_t line[64];
44
45 static struct sockaddr server_addr;
46
47 #if DEFAULT_PORT == 0
48 /* The advanced use case: ephemeral port */
49 #if defined(CONFIG_NET_IPV6)
50 DNS_SD_REGISTER_SERVICE(zephyr, CONFIG_NET_HOSTNAME,
51 "_zephyr", "_tcp", "local", DNS_SD_EMPTY_TXT,
52 &((struct sockaddr_in6 *)&server_addr)->sin6_port);
53 #elif defined(CONFIG_NET_IPV4)
54 DNS_SD_REGISTER_SERVICE(zephyr, CONFIG_NET_HOSTNAME,
55 "_zephyr", "_tcp", "local", DNS_SD_EMPTY_TXT,
56 &((struct sockaddr_in *)&server_addr)->sin_port);
57 #endif
58 #else
59 /* The simple use case: fixed port */
60 DNS_SD_REGISTER_TCP_SERVICE(zephyr, CONFIG_NET_HOSTNAME,
61 "_zephyr", "local", DNS_SD_EMPTY_TXT, DEFAULT_PORT);
62 #endif
63
64 if (IS_ENABLED(CONFIG_NET_IPV6)) {
65 net_sin6(&server_addr)->sin6_family = AF_INET6;
66 net_sin6(&server_addr)->sin6_addr = in6addr_any;
67 net_sin6(&server_addr)->sin6_port = sys_cpu_to_be16(DEFAULT_PORT);
68 } else if (IS_ENABLED(CONFIG_NET_IPV4)) {
69 net_sin(&server_addr)->sin_family = AF_INET;
70 net_sin(&server_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
71 net_sin(&server_addr)->sin_port = sys_cpu_to_be16(DEFAULT_PORT);
72 } else {
73 __ASSERT(false, "Neither IPv6 nor IPv4 are enabled");
74 }
75
76 r = socket(server_addr.sa_family, SOCK_STREAM, 0);
77 if (r == -1) {
78 NET_DBG("socket() failed (%d)", errno);
79 return;
80 }
81
82 server_fd = r;
83 NET_DBG("server_fd is %d", server_fd);
84
85 r = bind(server_fd, &server_addr, sizeof(server_addr));
86 if (r == -1) {
87 NET_DBG("bind() failed (%d)", errno);
88 close(server_fd);
89 return;
90 }
91
92 if (server_addr.sa_family == AF_INET6) {
93 addrp = &net_sin6(&server_addr)->sin6_addr;
94 portp = &net_sin6(&server_addr)->sin6_port;
95 } else {
96 addrp = &net_sin(&server_addr)->sin_addr;
97 portp = &net_sin(&server_addr)->sin_port;
98 }
99
100 inet_ntop(server_addr.sa_family, addrp, addrstr, sizeof(addrstr));
101 NET_DBG("bound to [%s]:%u",
102 log_strdup(addrstr), ntohs(*portp));
103
104 r = listen(server_fd, 1);
105 if (r == -1) {
106 NET_DBG("listen() failed (%d)", errno);
107 close(server_fd);
108 return;
109 }
110
111 for (;;) {
112 len = sizeof(client_addr);
113 r = accept(server_fd, (struct sockaddr *)&client_addr, &len);
114 if (r == -1) {
115 NET_DBG("accept() failed (%d)", errno);
116 continue;
117 }
118
119 client_fd = r;
120
121 inet_ntop(server_addr.sa_family, addrp, addrstr, sizeof(addrstr));
122 NET_DBG("accepted connection from [%s]:%u",
123 log_strdup(addrstr), ntohs(*portp));
124
125 /* send a banner */
126 r = welcome(client_fd);
127 if (r == -1) {
128 NET_DBG("send() failed (%d)", errno);
129 close(client_fd);
130 return;
131 }
132
133 for (;;) {
134 /* echo 1 line at a time */
135 r = recv(client_fd, line, sizeof(line), 0);
136 if (r == -1) {
137 NET_DBG("recv() failed (%d)", errno);
138 close(client_fd);
139 break;
140 }
141 len = r;
142
143 r = send(client_fd, line, len, 0);
144 if (r == -1) {
145 NET_DBG("send() failed (%d)", errno);
146 close(client_fd);
147 break;
148 }
149 }
150 }
151 }
152