blob: 258afd8594caa498e3bed31fb518bcb297751104 [file] [log] [blame]
Brian Silverman771b4b82013-04-12 16:36:56 -07001#include <stdio.h>
2#include <sys/types.h>
3#include <sys/socket.h>
4#include <netinet/in.h>
5#include <arpa/inet.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <pthread.h>
9#include <sys/stat.h>
10#include <assert.h>
11
12#include "aos/common/logging/logging_impl.h"
Brian Silverman66f079a2013-08-26 16:24:30 -070013#include "aos/common/util.h"
14#include "aos/atom_code/configuration.h"
Brian Silverman771b4b82013-04-12 16:36:56 -070015
16namespace aos {
17namespace {
18
19struct FDsToCopy {
20 const int input;
21 const int output;
Brian Silvermane1514fc2013-04-13 14:57:35 -070022
23 const struct sockaddr_in *const interface_address;
Brian Silverman771b4b82013-04-12 16:36:56 -070024};
25
26void *FDCopyThread(void *to_copy_in) {
27 FDsToCopy *to_copy = static_cast<FDsToCopy *>(to_copy_in);
28
29 char buffer[32768];
30 ssize_t position = 0;
31 while (true) {
32 assert(position >= 0);
33 assert(position <= static_cast<ssize_t>(sizeof(buffer)));
34 if (position != sizeof(buffer)) {
Brian Silvermane1514fc2013-04-13 14:57:35 -070035 ssize_t read_bytes;
36 bool good_data = true;
37 if (to_copy->interface_address != NULL) {
38 char control_buffer[0x100];
39 struct msghdr header;
40 memset(static_cast<void *>(&header), 0, sizeof(header));
41 header.msg_control = control_buffer;
42 header.msg_controllen = sizeof(control_buffer);
43 struct iovec iovecs[1];
44 iovecs[0].iov_base = buffer + position;
45 iovecs[0].iov_len = position - sizeof(buffer);
46 header.msg_iov = iovecs;
47 header.msg_iovlen = sizeof(iovecs) / sizeof(iovecs[0]);
48 read_bytes = recvmsg(to_copy->input, &header, 0);
49 if (read_bytes != -1) {
50 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&header);
51 cmsg != NULL;
52 cmsg = CMSG_NXTHDR(&header, cmsg)) {
53 if (cmsg->cmsg_level == IPPROTO_IP &&
54 cmsg->cmsg_type == IP_PKTINFO) {
Brian Silverman1c8670d2013-04-13 18:59:13 -070055 unsigned char *data = CMSG_DATA(cmsg);
56 struct in_pktinfo *pktinfo;
57 memcpy(&pktinfo, &data, sizeof(void *));
Brian Silvermane1514fc2013-04-13 14:57:35 -070058 good_data = pktinfo->ipi_spec_dst.s_addr ==
59 to_copy->interface_address->sin_addr.s_addr;
60 }
61 }
62 }
63 } else {
64 read_bytes = read(to_copy->input,
65 buffer + position, position - sizeof(buffer));
66 }
Brian Silverman771b4b82013-04-12 16:36:56 -070067 if (read_bytes == -1) {
68 if (errno != EINTR) {
69 LOG(FATAL, "read(%d, %p, %zd) failed with %d: %s\n",
70 to_copy->input, buffer + position, position - sizeof(buffer),
71 errno, strerror(errno));
72 }
Brian Silvermane1514fc2013-04-13 14:57:35 -070073 } else if (read_bytes == 0 && to_copy->interface_address == NULL) {
Brian Silverman771b4b82013-04-12 16:36:56 -070074 // read(2) says that this means EOF
75 return NULL;
76 }
Brian Silvermane1514fc2013-04-13 14:57:35 -070077 if (good_data) {
78 position += read_bytes;
79 }
Brian Silverman771b4b82013-04-12 16:36:56 -070080 }
81
82 assert(position >= 0);
83 assert(position <= static_cast<ssize_t>(sizeof(buffer)));
84 if (position > 0) {
85 ssize_t sent_bytes = write(to_copy->output, buffer, position);
86 if (sent_bytes == -1) {
87 if (errno != EINTR) {
88 LOG(FATAL, "write(%d, %p, %zd) failed with %d: %s\n",
89 to_copy->output, buffer, position, errno, strerror(errno));
90 }
91 } else if (sent_bytes != 0) {
Brian Silverman1c8670d2013-04-13 18:59:13 -070092 if (sent_bytes == position) {
93 position = 0;
94 } else {
95 memmove(buffer, buffer + sent_bytes, position - sent_bytes);
96 position -= sent_bytes;
97 }
Brian Silverman771b4b82013-04-12 16:36:56 -070098 }
99 }
100 }
101}
102
103int NetconsoleMain(int argc, char **argv) {
104 logging::Init();
105
Brian Silvermancb9637c2013-04-13 22:19:43 -0700106 int input, output;
Brian Silverman771b4b82013-04-12 16:36:56 -0700107 if (argc > 1) {
Brian Silvermancb9637c2013-04-13 22:19:43 -0700108 output = open(argv[1], O_APPEND | O_CREAT | O_WRONLY | O_TRUNC, 0666);
Brian Silverman771b4b82013-04-12 16:36:56 -0700109 if (output == -1) {
110 if (errno == EACCES || errno == ELOOP || errno == ENOSPC ||
111 errno == ENOTDIR || errno == EROFS || errno == ETXTBSY) {
112 fprintf(stderr, "Opening output file '%s' failed because of %s.\n",
113 argv[1], strerror(errno));
114 exit(EXIT_FAILURE);
115 }
116 LOG(FATAL, "open('%s', stuff, 0644) failed with %d: %s\n", argv[1],
117 errno, strerror(errno));
118 }
119 fprintf(stderr, "Writing output to '%s'.\n", argv[1]);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700120 input = -1;
121 fprintf(stderr, "Not taking any input.\n");
Brian Silverman771b4b82013-04-12 16:36:56 -0700122 } else {
123 output = STDOUT_FILENO;
124 fprintf(stderr, "Writing output to stdout.\n");
Brian Silvermancb9637c2013-04-13 22:19:43 -0700125 input = STDIN_FILENO;
126 fprintf(stderr, "Reading stdin.\n");
Brian Silverman771b4b82013-04-12 16:36:56 -0700127 }
128
Brian Silverman771b4b82013-04-12 16:36:56 -0700129 int on = 1;
130
131 int from_crio = socket(AF_INET, SOCK_DGRAM, 0);
132 if (from_crio == -1) {
133 LOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed with %d: %s\n",
134 errno, strerror(errno));
135 }
136 if (setsockopt(from_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
137 LOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed with %d: %s\n",
138 on, from_crio, errno, strerror(errno));
139 }
140 if (setsockopt(from_crio, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
141 LOG(FATAL, "SOL_SOCKET::SO_BROADCAST=%d(%d) failed with %d: %s\n",
142 on, from_crio, errno, strerror(errno));
143 }
Brian Silvermane1514fc2013-04-13 14:57:35 -0700144 if (setsockopt(from_crio, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) == -1) {
145 LOG(FATAL, "IPROTO_IP::IP_PKTINFO=%d(%d) failed with %d: %s\n",
146 on, from_crio, errno, strerror(errno));
147 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700148 union {
149 struct sockaddr_in in;
150 struct sockaddr addr;
151 } address;
152 address.in.sin_family = AF_INET;
153 address.in.sin_port = htons(6666);
154 address.in.sin_addr.s_addr = INADDR_ANY;
155 if (bind(from_crio, &address.addr, sizeof(address)) == -1) {
156 LOG(FATAL, "bind(%d, %p, %zu) failed with %d: %s\n",
157 from_crio, &address.addr, sizeof(address), errno, strerror(errno));
158 }
159
Brian Silvermancb9637c2013-04-13 22:19:43 -0700160 pthread_t input_thread, output_thread;
161
Brian Silverman66f079a2013-08-26 16:24:30 -0700162 address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
163 ::aos::util::SetLastSegment(&address.in.sin_addr, NetworkAddress::kCRIO);
164 fprintf(stderr, "Using cRIO IP %s.\n",
165 inet_ntoa(address.in.sin_addr));
166
Brian Silvermancb9637c2013-04-13 22:19:43 -0700167 if (input != -1) {
168 int to_crio = socket(AF_INET, SOCK_DGRAM, 0);
169 if (to_crio == -1) {
170 LOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed with %d: %s\n",
171 errno, strerror(errno));
172 }
173 if (setsockopt(to_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
174 LOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed with %d: %s\n",
175 on, to_crio, errno, strerror(errno));
176 }
177 address.in.sin_port = htons(6668);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700178 if (connect(to_crio, &address.addr, sizeof(address)) == -1) {
179 LOG(FATAL, "connect(%d, %p, %zu) failed with %d: %s\n",
180 to_crio, &address.addr, sizeof(address), errno, strerror(errno));
181 }
182 FDsToCopy input_fds{input, to_crio, NULL};
183 if (pthread_create(&input_thread, NULL, FDCopyThread, &input_fds) == -1) {
184 LOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed with %d: %s\n",
185 &input_thread, FDCopyThread, &input_fds, errno, strerror(errno));
186 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700187 }
188
Brian Silverman66f079a2013-08-26 16:24:30 -0700189 address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
Brian Silvermane1514fc2013-04-13 14:57:35 -0700190 FDsToCopy output_fds{from_crio, output, &address.in};
Brian Silverman771b4b82013-04-12 16:36:56 -0700191 if (pthread_create(&output_thread, NULL, FDCopyThread, &output_fds) == -1) {
192 LOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed with %d: %s\n",
193 &output_thread, FDCopyThread, &output_fds, errno, strerror(errno));
194 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700195
196 // input_thread will finish when stdin gets an EOF
Brian Silvermancb9637c2013-04-13 22:19:43 -0700197 if (pthread_join((input == -1) ? output_thread : input_thread, NULL) == -1) {
198 LOG(FATAL, "pthread_join(a_thread, NULL) failed with %d: %s\n",
Brian Silverman771b4b82013-04-12 16:36:56 -0700199 errno, strerror(errno));
200 }
201 exit(EXIT_SUCCESS);
202}
203
204} // namespace
205} // namespace aos
206
207int main(int argc, char **argv) {
208 return ::aos::NetconsoleMain(argc, argv);
209}