blob: c4ca5b94b54f8f686b1b996fd1a0b3f266c14bf5 [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>
Brian Silverman771b4b82013-04-12 16:36:56 -070010
11#include "aos/common/logging/logging_impl.h"
Brianc1dc7d22014-04-02 12:21:08 -070012#include "aos/common/util/inet_addr.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080013#include "aos/linux_code/configuration.h"
Brian Silvermanfe1ef172014-04-12 17:12:45 -070014#include "aos/common/network_port.h"
15#include "aos/linux_code/init.h"
Brian Silvermanf02c3982014-04-21 22:04:41 -070016#include "aos/common/byteorder.h"
Brian Silverman771b4b82013-04-12 16:36:56 -070017
18namespace aos {
19namespace {
20
21struct FDsToCopy {
22 const int input;
23 const int output;
Brian Silvermane1514fc2013-04-13 14:57:35 -070024
25 const struct sockaddr_in *const interface_address;
Brian Silvermanfe1ef172014-04-12 17:12:45 -070026 const struct sockaddr_in *const source_address;
Brian Silverman771b4b82013-04-12 16:36:56 -070027};
28
29void *FDCopyThread(void *to_copy_in) {
30 FDsToCopy *to_copy = static_cast<FDsToCopy *>(to_copy_in);
31
32 char buffer[32768];
33 ssize_t position = 0;
34 while (true) {
Brian Silvermanfe457de2014-05-26 22:04:08 -070035 CHECK_GE(position, 0);
36 CHECK_LE(position, static_cast<ssize_t>(sizeof(buffer)));
Brian Silverman771b4b82013-04-12 16:36:56 -070037 if (position != sizeof(buffer)) {
Brian Silvermane1514fc2013-04-13 14:57:35 -070038 ssize_t read_bytes;
39 bool good_data = true;
Brian Silvermanfe1ef172014-04-12 17:12:45 -070040 if (to_copy->interface_address != nullptr ||
41 to_copy->source_address != nullptr) {
Brian Silvermane1514fc2013-04-13 14:57:35 -070042 char control_buffer[0x100];
43 struct msghdr header;
44 memset(static_cast<void *>(&header), 0, sizeof(header));
45 header.msg_control = control_buffer;
46 header.msg_controllen = sizeof(control_buffer);
47 struct iovec iovecs[1];
48 iovecs[0].iov_base = buffer + position;
Brian Silvermanfe1ef172014-04-12 17:12:45 -070049 iovecs[0].iov_len = sizeof(buffer) - position;
Brian Silvermane1514fc2013-04-13 14:57:35 -070050 header.msg_iov = iovecs;
51 header.msg_iovlen = sizeof(iovecs) / sizeof(iovecs[0]);
Brian Silvermanfe1ef172014-04-12 17:12:45 -070052 struct sockaddr_in sender_address;
53 header.msg_name = &sender_address;
54 header.msg_namelen = sizeof(sender_address);
55
Brian Silvermane1514fc2013-04-13 14:57:35 -070056 read_bytes = recvmsg(to_copy->input, &header, 0);
57 if (read_bytes != -1) {
Brian Silvermanfe1ef172014-04-12 17:12:45 -070058 if (to_copy->interface_address != nullptr) {
59 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&header);
60 cmsg != NULL;
61 cmsg = CMSG_NXTHDR(&header, cmsg)) {
62 if (cmsg->cmsg_level == IPPROTO_IP &&
63 cmsg->cmsg_type == IP_PKTINFO) {
64 unsigned char *data = CMSG_DATA(cmsg);
65 struct in_pktinfo *pktinfo;
66 memcpy(&pktinfo, &data, sizeof(void *));
67 if (pktinfo->ipi_spec_dst.s_addr !=
68 to_copy->interface_address->sin_addr.s_addr) {
69 good_data = false;
70 }
71 }
72 }
73 }
74 if (to_copy->source_address != nullptr) {
Brian Silvermanfe457de2014-05-26 22:04:08 -070075 CHECK_GE(header.msg_namelen, sizeof(struct sockaddr_in));
Brian Silvermanf02c3982014-04-21 22:04:41 -070076 if (to_copy->source_address->sin_port != hton<uint16_t>(0)) {
Brian Silvermanfe1ef172014-04-12 17:12:45 -070077 if (sender_address.sin_port !=
78 to_copy->source_address->sin_port) {
79 good_data = false;
80 }
81 }
82 if (sender_address.sin_addr.s_addr !=
83 to_copy->source_address->sin_addr.s_addr) {
84 good_data = false;
Brian Silvermane1514fc2013-04-13 14:57:35 -070085 }
86 }
87 }
88 } else {
89 read_bytes = read(to_copy->input,
Brian Silvermanfe1ef172014-04-12 17:12:45 -070090 buffer + position, sizeof(buffer) - position);
Brian Silvermane1514fc2013-04-13 14:57:35 -070091 }
Brian Silverman771b4b82013-04-12 16:36:56 -070092 if (read_bytes == -1) {
93 if (errno != EINTR) {
Brian Silverman01be0002014-05-10 15:44:38 -070094 PLOG(FATAL, "read(%d, %p, %zd) failed",
95 to_copy->input, buffer + position, position - sizeof(buffer));
Brian Silverman771b4b82013-04-12 16:36:56 -070096 }
Brian Silvermane1514fc2013-04-13 14:57:35 -070097 } else if (read_bytes == 0 && to_copy->interface_address == NULL) {
Brian Silverman771b4b82013-04-12 16:36:56 -070098 // read(2) says that this means EOF
99 return NULL;
100 }
Brian Silvermane1514fc2013-04-13 14:57:35 -0700101 if (good_data) {
102 position += read_bytes;
103 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700104 }
105
Brian Silvermanfe457de2014-05-26 22:04:08 -0700106 CHECK_GE(position, 0);
107 CHECK_LE(position, static_cast<ssize_t>(sizeof(buffer)));
Brian Silverman771b4b82013-04-12 16:36:56 -0700108 if (position > 0) {
109 ssize_t sent_bytes = write(to_copy->output, buffer, position);
110 if (sent_bytes == -1) {
111 if (errno != EINTR) {
Brian Silverman01be0002014-05-10 15:44:38 -0700112 PLOG(FATAL, "write(%d, %p, %zd) failed",
113 to_copy->output, buffer, position);
Brian Silverman771b4b82013-04-12 16:36:56 -0700114 }
115 } else if (sent_bytes != 0) {
Brian Silverman1c8670d2013-04-13 18:59:13 -0700116 if (sent_bytes == position) {
117 position = 0;
118 } else {
119 memmove(buffer, buffer + sent_bytes, position - sent_bytes);
120 position -= sent_bytes;
121 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700122 }
123 }
124 }
125}
126
127int NetconsoleMain(int argc, char **argv) {
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700128 WriteCoreDumps();
Brian Silverman771b4b82013-04-12 16:36:56 -0700129 logging::Init();
Brian Silverman01be0002014-05-10 15:44:38 -0700130 logging::AddImplementation(new logging::StreamLogImplementation(stdout));
Brian Silverman771b4b82013-04-12 16:36:56 -0700131
Brian Silvermancb9637c2013-04-13 22:19:43 -0700132 int input, output;
Brian Silverman771b4b82013-04-12 16:36:56 -0700133 if (argc > 1) {
Brian Silvermancb9637c2013-04-13 22:19:43 -0700134 output = open(argv[1], O_APPEND | O_CREAT | O_WRONLY | O_TRUNC, 0666);
Brian Silverman771b4b82013-04-12 16:36:56 -0700135 if (output == -1) {
136 if (errno == EACCES || errno == ELOOP || errno == ENOSPC ||
137 errno == ENOTDIR || errno == EROFS || errno == ETXTBSY) {
Brian Silverman01be0002014-05-10 15:44:38 -0700138 PLOG(FATAL, "opening output file '%s' failed", argv[1]);
Brian Silverman771b4b82013-04-12 16:36:56 -0700139 }
Brian Silverman01be0002014-05-10 15:44:38 -0700140 PLOG(FATAL, "open('%s', stuff, 0644) failed", argv[1]);
Brian Silverman771b4b82013-04-12 16:36:56 -0700141 }
142 fprintf(stderr, "Writing output to '%s'.\n", argv[1]);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700143 input = -1;
144 fprintf(stderr, "Not taking any input.\n");
Brian Silverman771b4b82013-04-12 16:36:56 -0700145 } else {
146 output = STDOUT_FILENO;
147 fprintf(stderr, "Writing output to stdout.\n");
Brian Silvermancb9637c2013-04-13 22:19:43 -0700148 input = STDIN_FILENO;
149 fprintf(stderr, "Reading stdin.\n");
Brian Silverman771b4b82013-04-12 16:36:56 -0700150 }
151
Brian Silverman771b4b82013-04-12 16:36:56 -0700152 int on = 1;
153
154 int from_crio = socket(AF_INET, SOCK_DGRAM, 0);
155 if (from_crio == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700156 PLOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed");
Brian Silverman771b4b82013-04-12 16:36:56 -0700157 }
158 if (setsockopt(from_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700159 PLOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed", on, from_crio);
Brian Silverman771b4b82013-04-12 16:36:56 -0700160 }
161 if (setsockopt(from_crio, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700162 PLOG(FATAL, "SOL_SOCKET::SO_BROADCAST=%d(%d) failed", on, from_crio);
Brian Silverman771b4b82013-04-12 16:36:56 -0700163 }
Brian Silvermane1514fc2013-04-13 14:57:35 -0700164 if (setsockopt(from_crio, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700165 PLOG(FATAL, "IPROTO_IP::IP_PKTINFO=%d(%d) failed", on, from_crio);
Brian Silvermane1514fc2013-04-13 14:57:35 -0700166 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700167 union {
168 struct sockaddr_in in;
169 struct sockaddr addr;
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700170 } address, crio_address;
171
Brian Silverman771b4b82013-04-12 16:36:56 -0700172 address.in.sin_family = AF_INET;
Brian Silvermanf02c3982014-04-21 22:04:41 -0700173 address.in.sin_port = hton<uint16_t>(6666);
Brian Silverman771b4b82013-04-12 16:36:56 -0700174 address.in.sin_addr.s_addr = INADDR_ANY;
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700175
176 crio_address.in.sin_family = AF_INET;
Brian Silvermanf02c3982014-04-21 22:04:41 -0700177 crio_address.in.sin_port = hton<uint16_t>(0);
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700178 crio_address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
179 ::aos::util::SetLastSegment(&crio_address.in.sin_addr,
180 ::aos::NetworkAddress::kCRIO);
181
Brian Silverman771b4b82013-04-12 16:36:56 -0700182 if (bind(from_crio, &address.addr, sizeof(address)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700183 PLOG(FATAL, "bind(%d, %p, %zu) failed",
184 from_crio, &address.addr, sizeof(address));
Brian Silverman771b4b82013-04-12 16:36:56 -0700185 }
186
Brian Silvermancb9637c2013-04-13 22:19:43 -0700187 pthread_t input_thread, output_thread;
188
Brian Silverman66f079a2013-08-26 16:24:30 -0700189 address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
190 ::aos::util::SetLastSegment(&address.in.sin_addr, NetworkAddress::kCRIO);
191 fprintf(stderr, "Using cRIO IP %s.\n",
192 inet_ntoa(address.in.sin_addr));
193
Brian Silvermancb9637c2013-04-13 22:19:43 -0700194 if (input != -1) {
195 int to_crio = socket(AF_INET, SOCK_DGRAM, 0);
196 if (to_crio == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700197 PLOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed");
Brian Silvermancb9637c2013-04-13 22:19:43 -0700198 }
199 if (setsockopt(to_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700200 PLOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed", on, to_crio);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700201 }
Brian Silvermanf02c3982014-04-21 22:04:41 -0700202 address.in.sin_port = hton<uint16_t>(6668);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700203 if (connect(to_crio, &address.addr, sizeof(address)) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700204 PLOG(FATAL, "connect(%d, %p, %zu) failed",
205 to_crio, &address.addr, sizeof(address));
Brian Silvermancb9637c2013-04-13 22:19:43 -0700206 }
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700207 FDsToCopy input_fds{input, to_crio, nullptr, nullptr};
Brian Silvermancb9637c2013-04-13 22:19:43 -0700208 if (pthread_create(&input_thread, NULL, FDCopyThread, &input_fds) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700209 PLOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed",
210 &input_thread, FDCopyThread, &input_fds);
Brian Silvermancb9637c2013-04-13 22:19:43 -0700211 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700212 }
213
Brian Silverman66f079a2013-08-26 16:24:30 -0700214 address.in.sin_addr = ::aos::configuration::GetOwnIPAddress();
Brian Silvermanfe1ef172014-04-12 17:12:45 -0700215 FDsToCopy output_fds{from_crio, output, &address.in, &crio_address.in};
Brian Silverman771b4b82013-04-12 16:36:56 -0700216 if (pthread_create(&output_thread, NULL, FDCopyThread, &output_fds) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700217 PLOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed",
218 &output_thread, FDCopyThread, &output_fds);
Brian Silverman771b4b82013-04-12 16:36:56 -0700219 }
Brian Silverman771b4b82013-04-12 16:36:56 -0700220
221 // input_thread will finish when stdin gets an EOF
Brian Silvermancb9637c2013-04-13 22:19:43 -0700222 if (pthread_join((input == -1) ? output_thread : input_thread, NULL) == -1) {
Brian Silverman01be0002014-05-10 15:44:38 -0700223 PLOG(FATAL, "pthread_join(a_thread, NULL) failed");
Brian Silverman771b4b82013-04-12 16:36:56 -0700224 }
225 exit(EXIT_SUCCESS);
226}
227
228} // namespace
229} // namespace aos
230
231int main(int argc, char **argv) {
232 return ::aos::NetconsoleMain(argc, argv);
233}