1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #define _POSIX_C_SOURCE 200809L
6
7 // for SO_REUSEPORT
8 #ifdef __APPLE__
9 #define _DARWIN_C_SOURCE
10 #endif
11
12 #include <arpa/inet.h>
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <errno.h>
23 #include <stdint.h>
24
25 #include <zircon/boot/netboot.h>
26
27 #ifdef _DARWIN_C_SOURCE
28 #define REUSEPORT SO_REUSEPORT
29 #else
30 #define REUSEPORT SO_REUSEADDR
31 #endif
32
33 static const char* appname;
34 static const char* nodename = "*";
35
main(int argc,char ** argv)36 int main(int argc, char** argv) {
37 struct sockaddr_in6 addr;
38 char tmp[INET6_ADDRSTRLEN];
39 int r, s, n = 1;
40 uint32_t last_seqno = 0;
41
42 // Make stdout line buffered.
43 setvbuf(stdout, NULL, _IOLBF, 0);
44
45 appname = argv[0];
46
47 if ((argc > 1) && (argv[1][0])) {
48 nodename = argv[1];
49 } else {
50 char* envname = getenv("ZIRCON_NODENAME");
51 if (envname) {
52 nodename = envname;
53 }
54 }
55
56 memset(&addr, 0, sizeof(addr));
57 addr.sin6_family = AF_INET6;
58 addr.sin6_port = htons(33337);
59
60 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
61 if (s < 0) {
62 fprintf(stderr, "%s: cannot create socket %d\n", appname, s);
63 return -1;
64 }
65 setsockopt(s, SOL_SOCKET, REUSEPORT, &n, sizeof(n));
66 if ((r = bind(s, (void*)&addr, sizeof(addr))) < 0) {
67 fprintf(stderr, "%s: cannot bind to [%s]%d: %d: %s\n", appname,
68 inet_ntop(AF_INET6, &addr.sin6_addr, tmp, sizeof(tmp)),
69 ntohs(addr.sin6_port), errno, strerror(errno));
70 if (errno == 98) {
71 fprintf(stderr, "%s: another process is already using udp port %d. "
72 "Try running `lsof -i udp:%d`.\n",
73 appname,
74 ntohs(addr.sin6_port), ntohs(addr.sin6_port));
75 }
76 return -1;
77 }
78
79 fprintf(stderr, "%s: listening on [%s]%d for device %s\n", appname,
80 inet_ntop(AF_INET6, &addr.sin6_addr, tmp, sizeof(tmp)),
81 ntohs(addr.sin6_port), nodename);
82 for (;;) {
83 struct sockaddr_in6 ra;
84 socklen_t rlen;
85 char buf[4096 + 1];
86 logpacket_t* pkt = (void*)buf;
87 rlen = sizeof(ra);
88 r = recvfrom(s, buf, 4096, 0, (void*)&ra, &rlen);
89 if (r < 0) {
90 fprintf(stderr, "%s: socket read error %d\n", appname, r);
91 break;
92 }
93 if (r < 8)
94 continue;
95 if ((ra.sin6_addr.s6_addr[0] != 0xFE) || (ra.sin6_addr.s6_addr[1] != 0x80)) {
96 fprintf(stderr, "ignoring non-link-local message\n");
97 continue;
98 }
99 if (pkt->magic != NB_DEBUGLOG_MAGIC)
100 continue;
101 if (strncmp(nodename, "*", 1) && strncmp(pkt->nodename, nodename, sizeof(pkt->nodename)))
102 continue;
103 if (pkt->seqno != last_seqno) {
104 buf[r] = 0;
105 printf("%s", pkt->data);
106 last_seqno = pkt->seqno;
107 }
108 sendto(s, buf, 8, 0, (struct sockaddr*)&ra, rlen);
109 }
110
111 return 0;
112 }
113