blob: 22c3a80a7be5e174f6d04a432855fad89af05559 [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"
13#include "aos/common/Configuration.h"
14
15namespace aos {
16namespace {
17
18struct FDsToCopy {
19 const int input;
20 const int output;
21};
22
23void *FDCopyThread(void *to_copy_in) {
24 FDsToCopy *to_copy = static_cast<FDsToCopy *>(to_copy_in);
25
26 char buffer[32768];
27 ssize_t position = 0;
28 while (true) {
29 assert(position >= 0);
30 assert(position <= static_cast<ssize_t>(sizeof(buffer)));
31 if (position != sizeof(buffer)) {
32 ssize_t read_bytes = read(to_copy->input,
33 buffer + position, position - sizeof(buffer));
34 if (read_bytes == -1) {
35 if (errno != EINTR) {
36 LOG(FATAL, "read(%d, %p, %zd) failed with %d: %s\n",
37 to_copy->input, buffer + position, position - sizeof(buffer),
38 errno, strerror(errno));
39 }
40 } else if (read_bytes == 0) {
41 // read(2) says that this means EOF
42 return NULL;
43 }
44 position += read_bytes;
45 }
46
47 assert(position >= 0);
48 assert(position <= static_cast<ssize_t>(sizeof(buffer)));
49 if (position > 0) {
50 ssize_t sent_bytes = write(to_copy->output, buffer, position);
51 if (sent_bytes == -1) {
52 if (errno != EINTR) {
53 LOG(FATAL, "write(%d, %p, %zd) failed with %d: %s\n",
54 to_copy->output, buffer, position, errno, strerror(errno));
55 }
56 } else if (sent_bytes != 0) {
57 memmove(buffer, buffer + sent_bytes, position - sent_bytes);
58 position -= sent_bytes;
59 }
60 }
61 }
62}
63
64int NetconsoleMain(int argc, char **argv) {
65 logging::Init();
66
67 int output;
68 if (argc > 1) {
69 output = open(argv[1], O_APPEND | O_CREAT | O_WRONLY | O_TRUNC, 0644);
70 if (output == -1) {
71 if (errno == EACCES || errno == ELOOP || errno == ENOSPC ||
72 errno == ENOTDIR || errno == EROFS || errno == ETXTBSY) {
73 fprintf(stderr, "Opening output file '%s' failed because of %s.\n",
74 argv[1], strerror(errno));
75 exit(EXIT_FAILURE);
76 }
77 LOG(FATAL, "open('%s', stuff, 0644) failed with %d: %s\n", argv[1],
78 errno, strerror(errno));
79 }
80 fprintf(stderr, "Writing output to '%s'.\n", argv[1]);
81 } else {
82 output = STDOUT_FILENO;
83 fprintf(stderr, "Writing output to stdout.\n");
84 }
85
86 const int input = STDIN_FILENO;
87
88 int on = 1;
89
90 int from_crio = socket(AF_INET, SOCK_DGRAM, 0);
91 if (from_crio == -1) {
92 LOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed with %d: %s\n",
93 errno, strerror(errno));
94 }
95 if (setsockopt(from_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
96 LOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed with %d: %s\n",
97 on, from_crio, errno, strerror(errno));
98 }
99 if (setsockopt(from_crio, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
100 LOG(FATAL, "SOL_SOCKET::SO_BROADCAST=%d(%d) failed with %d: %s\n",
101 on, from_crio, errno, strerror(errno));
102 }
103 union {
104 struct sockaddr_in in;
105 struct sockaddr addr;
106 } address;
107 address.in.sin_family = AF_INET;
108 address.in.sin_port = htons(6666);
109 address.in.sin_addr.s_addr = INADDR_ANY;
110 if (bind(from_crio, &address.addr, sizeof(address)) == -1) {
111 LOG(FATAL, "bind(%d, %p, %zu) failed with %d: %s\n",
112 from_crio, &address.addr, sizeof(address), errno, strerror(errno));
113 }
114
115 int to_crio = socket(AF_INET, SOCK_DGRAM, 0);
116 if (to_crio == -1) {
117 LOG(FATAL, "socket(AF_INET, SOCK_DGRAM, 0) failed with %d: %s\n",
118 errno, strerror(errno));
119 }
120 if (setsockopt(to_crio, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
121 LOG(FATAL, "SOL_SOCKET::SO_REUSEADDR=%d(%d) failed with %d: %s\n",
122 on, to_crio, errno, strerror(errno));
123 }
124 address.in.sin_port = htons(6668);
125 if (inet_aton(
126 configuration::GetIPAddress(configuration::NetworkDevice::kCRIO),
127 &address.in.sin_addr) == 0) {
128 LOG(FATAL, "inet_aton(%s, %p) failed with %d: %s\n",
129 configuration::GetIPAddress(configuration::NetworkDevice::kCRIO),
130 &address.in.sin_addr, errno, strerror(errno));
131 }
132 if (connect(to_crio, &address.addr, sizeof(address)) == -1) {
133 LOG(FATAL, "connect(%d, %p, %zu) failed with %d: %s\n",
134 to_crio, &address.addr, sizeof(address), errno, strerror(errno));
135 }
136
137 fprintf(stderr, "Using cRIO IP %s.\n",
138 configuration::GetIPAddress(configuration::NetworkDevice::kCRIO));
139
140 FDsToCopy output_fds{from_crio, output};
141 pthread_t output_thread;
142 if (pthread_create(&output_thread, NULL, FDCopyThread, &output_fds) == -1) {
143 LOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed with %d: %s\n",
144 &output_thread, FDCopyThread, &output_fds, errno, strerror(errno));
145 }
146 FDsToCopy input_fds{input, to_crio};
147 pthread_t input_thread;
148 if (pthread_create(&input_thread, NULL, FDCopyThread, &input_fds) == -1) {
149 LOG(FATAL, "pthread_create(%p, NULL, %p, %p) failed with %d: %s\n",
150 &input_thread, FDCopyThread, &input_fds, errno, strerror(errno));
151 }
152
153 // input_thread will finish when stdin gets an EOF
154 if (pthread_join(input_thread, NULL) == -1) {
155 LOG(FATAL, "pthread_join(input_thread, NULL) failed with %d: %s\n",
156 errno, strerror(errno));
157 }
158 exit(EXIT_SUCCESS);
159}
160
161} // namespace
162} // namespace aos
163
164int main(int argc, char **argv) {
165 return ::aos::NetconsoleMain(argc, argv);
166}