Mercurial > repos > blastem
comparison megawifi.c @ 1983:a7b753e260a2 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 09 May 2020 23:39:44 -0700 |
parents | 41b9509ede38 |
children | a8e3e816a50d |
comparison
equal
deleted
inserted
replaced
1937:cafde1255ad3 | 1983:a7b753e260a2 |
---|---|
4 #include <sys/types.h> | 4 #include <sys/types.h> |
5 #ifdef _WIN32 | 5 #ifdef _WIN32 |
6 #define WINVER 0x501 | 6 #define WINVER 0x501 |
7 #include <winsock2.h> | 7 #include <winsock2.h> |
8 #include <ws2tcpip.h> | 8 #include <ws2tcpip.h> |
9 #include <sys/param.h> | |
9 #else | 10 #else |
10 #include <sys/socket.h> | 11 #include <sys/socket.h> |
12 #include <arpa/inet.h> | |
11 #include <unistd.h> | 13 #include <unistd.h> |
12 #include <netinet/in.h> | 14 #include <netinet/in.h> |
15 #include <netdb.h> | |
13 #endif | 16 #endif |
14 #include <errno.h> | 17 #include <errno.h> |
15 #include <fcntl.h> | 18 #include <fcntl.h> |
19 #include <time.h> | |
16 #include "genesis.h" | 20 #include "genesis.h" |
17 #include "net.h" | 21 #include "net.h" |
22 #include "util.h" | |
23 | |
24 #ifdef _WIN32 | |
25 # if BYTE_ORDER == LITTLE_ENDIAN | |
26 #define htobe64(val) ((((uint64_t)htonl((val)&0xFFFFFFFF))<<32) | htonl((val)>>32)) | |
27 # else | |
28 #define htobe64(val) (val) | |
29 # endif | |
30 #endif | |
18 | 31 |
19 enum { | 32 enum { |
20 TX_IDLE, | 33 TX_IDLE, |
21 TX_LEN1, | 34 TX_LEN1, |
22 TX_LEN2, | 35 TX_LEN2, |
23 TX_PAYLOAD, | 36 TX_PAYLOAD, |
24 TX_WAIT_ETX | 37 TX_WAIT_ETX |
25 }; | 38 }; |
26 #define STX 0x7E | 39 #define STX 0x7E |
27 #define ETX 0x7E | 40 #define ETX 0x7E |
28 #define MAX_RECV_SIZE 1440 | 41 #define MAX_RECV_SIZE 1460 |
29 | 42 |
30 #define E(N) N | 43 #define E(N) N |
31 enum { | 44 enum { |
32 #include "mw_commands.c" | 45 #include "mw_commands.c" |
33 CMD_ERROR = 255 | 46 CMD_ERROR = 255 |
41 | 54 |
42 #ifndef MSG_NOSIGNAL | 55 #ifndef MSG_NOSIGNAL |
43 #define MSG_NOSIGNAL 0 | 56 #define MSG_NOSIGNAL 0 |
44 #endif | 57 #endif |
45 | 58 |
46 enum { | 59 enum mw_state { |
47 STATE_IDLE=1, | 60 STATE_IDLE=1, |
48 STATE_AP_JOIN, | 61 STATE_AP_JOIN, |
49 STATE_SCAN, | 62 STATE_SCAN, |
50 STATE_READY, | 63 STATE_READY, |
51 STATE_TRANSPARENT | 64 STATE_TRANSPARENT |
65 }; | |
66 | |
67 enum { | |
68 SOCKST_NONE = 0, | |
69 SOCKST_TCP_LISTEN, | |
70 SOCKST_TCP_EST, | |
71 SOCKST_UDP_READY | |
72 }; | |
73 | |
74 // TCP/UDP address message | |
75 struct mw_addr_msg { | |
76 char dst_port[6]; | |
77 char src_port[6]; | |
78 uint8_t channel; | |
79 char host[]; | |
52 }; | 80 }; |
53 | 81 |
54 #define FLAG_ONLINE | 82 #define FLAG_ONLINE |
55 | 83 |
56 typedef struct { | 84 typedef struct { |
66 uint8_t transmit_state; | 94 uint8_t transmit_state; |
67 uint8_t module_state; | 95 uint8_t module_state; |
68 uint8_t flags; | 96 uint8_t flags; |
69 uint8_t transmit_buffer[4096]; | 97 uint8_t transmit_buffer[4096]; |
70 uint8_t receive_buffer[4096]; | 98 uint8_t receive_buffer[4096]; |
99 struct sockaddr_in remote_addr[15]; // Needed for UDP sockets | |
71 } megawifi; | 100 } megawifi; |
72 | 101 |
73 static megawifi *get_megawifi(void *context) | 102 static megawifi *get_megawifi(void *context) |
74 { | 103 { |
75 m68k_context *m68k = context; | 104 m68k_context *m68k = context; |
76 genesis_context *gen = m68k->system; | 105 genesis_context *gen = m68k->system; |
77 if (!gen->extra) { | 106 if (!gen->extra) { |
107 socket_init(); | |
78 gen->extra = calloc(1, sizeof(megawifi)); | 108 gen->extra = calloc(1, sizeof(megawifi)); |
79 megawifi *mw = gen->extra; | 109 megawifi *mw = gen->extra; |
80 mw->module_state = STATE_IDLE; | 110 mw->module_state = STATE_IDLE; |
81 for (int i = 0; i < 15; i++) | 111 mw->flags = 0xE0; // cfg_ok, dt_ok, online |
82 { | 112 for (int i = 0; i < 15; i++) { |
83 mw->sock_fds[i] = -1; | 113 mw->sock_fds[i] = -1; |
84 } | 114 } |
85 } | 115 } |
86 return gen->extra; | 116 return gen->extra; |
87 } | 117 } |
110 } | 140 } |
111 memcpy(mw->receive_buffer + mw->receive_bytes, src, count); | 141 memcpy(mw->receive_buffer + mw->receive_bytes, src, count); |
112 mw->receive_bytes += count; | 142 mw->receive_bytes += count; |
113 } | 143 } |
114 | 144 |
115 static void mw_puts(megawifi *mw, char *s) | 145 static void mw_puts(megawifi *mw, const char *s) |
116 { | 146 { |
117 uint32_t len = strlen(s); | 147 size_t len = strlen(s); |
118 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { | 148 mw_copy(mw, (uint8_t*)s, len); |
119 return; | 149 } |
120 } | 150 |
121 memcpy(mw->receive_buffer + mw->receive_bytes, s, len); | 151 static void udp_recv(megawifi *mw, uint8_t idx) |
122 mw->receive_bytes += len; | 152 { |
153 ssize_t recvd; | |
154 int s = mw->sock_fds[idx]; | |
155 struct sockaddr_in remote; | |
156 socklen_t addr_len = sizeof(struct sockaddr_in); | |
157 | |
158 if (mw->remote_addr[idx].sin_addr.s_addr != htonl(INADDR_ANY)) { | |
159 // Receive only from specified address | |
160 recvd = recvfrom(s, (char*)mw->receive_buffer + 3, MAX_RECV_SIZE, 0, | |
161 (struct sockaddr*)&remote, &addr_len); | |
162 if (recvd > 0) { | |
163 if (remote.sin_addr.s_addr != mw->remote_addr[idx].sin_addr.s_addr) { | |
164 printf("Discarding UDP packet from unknown addr %s:%d\n", | |
165 inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); | |
166 recvd = 0; | |
167 } | |
168 } | |
169 } else { | |
170 // Reuse mode, data is preceded by remote IPv4 and port | |
171 recvd = recvfrom(s, (char*)mw->receive_buffer + 9, MAX_RECV_SIZE - 6, | |
172 0, (struct sockaddr*)&remote, &addr_len); | |
173 if (recvd > 0) { | |
174 mw->receive_buffer[3] = remote.sin_addr.s_addr; | |
175 mw->receive_buffer[4] = remote.sin_addr.s_addr>>8; | |
176 mw->receive_buffer[5] = remote.sin_addr.s_addr>>16; | |
177 mw->receive_buffer[6] = remote.sin_addr.s_addr>>24; | |
178 mw->receive_buffer[7] = remote.sin_port; | |
179 mw->receive_buffer[8] = remote.sin_port>>8; | |
180 recvd += 6; | |
181 } | |
182 } | |
183 | |
184 if (recvd > 0) { | |
185 mw_putc(mw, STX); | |
186 mw_putc(mw, (recvd >> 8) | ((idx+1) << 4)); | |
187 mw_putc(mw, recvd); | |
188 mw->receive_bytes += recvd; | |
189 mw_putc(mw, ETX); | |
190 //should this set the channel flag? | |
191 } else if (recvd < 0 && !socket_error_is_wouldblock()) { | |
192 socket_close(mw->sock_fds[idx]); | |
193 mw->channel_state[idx] = SOCKST_NONE; | |
194 mw->channel_flags |= 1 << (idx + 1); | |
195 } | |
196 } | |
197 | |
198 static void udp_send(megawifi *mw, uint8_t idx) | |
199 { | |
200 struct sockaddr_in remote; | |
201 int s = mw->sock_fds[idx]; | |
202 int sent; | |
203 char *data = (char*)mw->transmit_buffer; | |
204 | |
205 if (mw->remote_addr[idx].sin_addr.s_addr != htonl(INADDR_ANY)) { | |
206 sent = sendto(s, data, mw->transmit_bytes, 0, (struct sockaddr*)&mw->remote_addr[idx], | |
207 sizeof(struct sockaddr_in)); | |
208 } else { | |
209 // Reuse mode, extract address from leading bytes | |
210 // NOTE: mw->remote_addr[idx].sin_addr.s_addr == INADDR_ANY | |
211 remote.sin_addr.s_addr = *((int32_t*)data); | |
212 remote.sin_port = *((int16_t*)(data + 4)); | |
213 remote.sin_family = AF_INET; | |
214 memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); | |
215 sent = sendto(s, data + 6, mw->transmit_bytes - 6, 0, (struct sockaddr*)&remote, | |
216 sizeof(struct sockaddr_in)) + 6; | |
217 } | |
218 if (sent < 0 && !socket_error_is_wouldblock()) { | |
219 socket_close(s); | |
220 mw->sock_fds[idx] = -1; | |
221 mw->channel_state[idx] = SOCKST_NONE; | |
222 mw->channel_flags |= 1 << (idx + 1); | |
223 } else if (sent < mw->transmit_bytes) { | |
224 //TODO: save this data somewhere so it can be sent in poll_socket | |
225 printf("Sent %d bytes on channel %d, but %d were requested\n", sent, idx + 1, mw->transmit_bytes); | |
226 } | |
123 } | 227 } |
124 | 228 |
125 static void poll_socket(megawifi *mw, uint8_t channel) | 229 static void poll_socket(megawifi *mw, uint8_t channel) |
126 { | 230 { |
127 if (mw->sock_fds[channel] < 0) { | 231 if (mw->sock_fds[channel] < 0) { |
128 return; | 232 return; |
129 } | 233 } |
130 if (mw->channel_state[channel] == 1) { | 234 if (mw->channel_state[channel] == SOCKST_TCP_LISTEN) { |
131 int res = accept(mw->sock_fds[channel], NULL, NULL); | 235 int res = accept(mw->sock_fds[channel], NULL, NULL); |
132 if (res >= 0) { | 236 if (res >= 0) { |
133 close(mw->sock_fds[channel]); | 237 socket_close(mw->sock_fds[channel]); |
134 #ifndef _WIN32 | 238 socket_blocking(res, 0); |
135 //FIXME: Set nonblocking on Windows too | |
136 fcntl(res, F_SETFL, O_NONBLOCK); | |
137 #endif | |
138 mw->sock_fds[channel] = res; | 239 mw->sock_fds[channel] = res; |
139 mw->channel_state[channel] = 2; | 240 mw->channel_state[channel] = SOCKST_TCP_EST; |
140 mw->channel_flags |= 1 << (channel + 1); | 241 mw->channel_flags |= 1 << (channel + 1); |
141 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { | 242 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { |
142 close(mw->sock_fds[channel]); | 243 socket_close(mw->sock_fds[channel]); |
143 mw->channel_state[channel] = 0; | 244 mw->channel_state[channel] = SOCKST_NONE; |
144 mw->channel_flags |= 1 << (channel + 1); | 245 mw->channel_flags |= 1 << (channel + 1); |
145 } | 246 } |
146 } else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) { | 247 } else if (mw->channel_state[channel] == SOCKST_TCP_EST && mw->receive_bytes < (sizeof(mw->receive_buffer) - 4)) { |
147 size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes; | 248 size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes; |
148 if (max > MAX_RECV_SIZE) { | 249 if (max > MAX_RECV_SIZE) { |
149 max = MAX_RECV_SIZE; | 250 max = MAX_RECV_SIZE; |
150 } | 251 } |
151 int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0); | 252 int bytes = recv(mw->sock_fds[channel], (char*)(mw->receive_buffer + mw->receive_bytes + 3), max, 0); |
152 if (bytes > 0) { | 253 if (bytes > 0) { |
153 mw_putc(mw, STX); | 254 mw_putc(mw, STX); |
154 mw_putc(mw, bytes >> 8 | (channel+1) << 4); | 255 mw_putc(mw, bytes >> 8 | (channel+1) << 4); |
155 mw_putc(mw, bytes); | 256 mw_putc(mw, bytes); |
156 mw->receive_bytes += bytes; | 257 mw->receive_bytes += bytes; |
157 mw_putc(mw, ETX); | 258 mw_putc(mw, ETX); |
158 //should this set the channel flag? | 259 //should this set the channel flag? |
159 } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | 260 } else if (bytes < 0 && !socket_error_is_wouldblock()) { |
160 close(mw->sock_fds[channel]); | 261 socket_close(mw->sock_fds[channel]); |
161 mw->channel_state[channel] = 0; | 262 mw->channel_state[channel] = SOCKST_NONE; |
162 mw->channel_flags |= 1 << (channel + 1); | 263 mw->channel_flags |= 1 << (channel + 1); |
163 } | 264 } |
265 } else if (mw->channel_state[channel] == SOCKST_UDP_READY && !mw->receive_bytes) { | |
266 udp_recv(mw, channel); | |
164 } | 267 } |
165 } | 268 } |
166 | 269 |
167 static void poll_all_sockets(megawifi *mw) | 270 static void poll_all_sockets(megawifi *mw) |
168 { | 271 { |
169 for (int i = 0; i < 15; i++) | 272 for (int i = 0; i < 15; i++) |
170 { | 273 { |
171 poll_socket(mw, i); | 274 poll_socket(mw, i); |
172 } | 275 } |
173 } | 276 } |
277 | |
174 | 278 |
175 static void start_reply(megawifi *mw, uint8_t cmd) | 279 static void start_reply(megawifi *mw, uint8_t cmd) |
176 { | 280 { |
177 mw_putc(mw, STX); | 281 mw_putc(mw, STX); |
178 //reserve space for length | 282 //reserve space for length |
195 mw->receive_buffer[5] = len >> 8; | 299 mw->receive_buffer[5] = len >> 8; |
196 mw->receive_buffer[6] = len; | 300 mw->receive_buffer[6] = len; |
197 mw_putc(mw, ETX); | 301 mw_putc(mw, ETX); |
198 } | 302 } |
199 | 303 |
304 static void cmd_ap_cfg_get(megawifi *mw) | |
305 { | |
306 char ssid[32] = {0}; | |
307 char pass[64] = {0}; | |
308 uint8_t slot = mw->transmit_buffer[4]; | |
309 | |
310 sprintf(ssid, "BLASTEM! SSID %d", slot + 1); | |
311 sprintf(pass, "BLASTEM! PASS %d", slot + 1); | |
312 start_reply(mw, CMD_OK); | |
313 mw_putc(mw, slot); | |
314 mw_putc(mw, 7); /// 11bgn | |
315 mw_copy(mw, (uint8_t*)ssid, 32); | |
316 mw_copy(mw, (uint8_t*)pass, 64); | |
317 end_reply(mw); | |
318 } | |
319 | |
320 static void cmd_ip_cfg_get(megawifi *mw) | |
321 { | |
322 uint32_t ipv4s[5] = {0}; | |
323 | |
324 start_reply(mw, CMD_OK); | |
325 mw_putc(mw, mw->transmit_buffer[4]); | |
326 mw_putc(mw, 0); | |
327 mw_putc(mw, 0); | |
328 mw_putc(mw, 0); | |
329 mw_copy(mw, (uint8_t*)ipv4s, sizeof(ipv4s)); | |
330 end_reply(mw); | |
331 } | |
332 | |
333 static void cmd_tcp_con(megawifi *mw, uint32_t size) | |
334 { | |
335 struct mw_addr_msg *addr = (struct mw_addr_msg*)(mw->transmit_buffer + 4); | |
336 struct addrinfo hints; | |
337 struct addrinfo *res = NULL; | |
338 int s; | |
339 int err; | |
340 | |
341 uint8_t channel = addr->channel; | |
342 if (!channel || channel > 15 || mw->sock_fds[channel - 1] >= 0) { | |
343 start_reply(mw, CMD_ERROR); | |
344 end_reply(mw); | |
345 return; | |
346 } | |
347 channel--; | |
348 | |
349 memset(&hints, 0, sizeof(hints)); | |
350 hints.ai_family = AF_INET; | |
351 #ifndef _WIN32 | |
352 hints.ai_flags = AI_NUMERICSERV; | |
353 #endif | |
354 hints.ai_socktype = SOCK_STREAM; | |
355 | |
356 if ((err = getaddrinfo(addr->host, addr->dst_port, &hints, &res)) != 0) { | |
357 printf("getaddrinfo failed: %s\n", gai_strerror(err)); | |
358 start_reply(mw, CMD_ERROR); | |
359 end_reply(mw); | |
360 return; | |
361 } | |
362 | |
363 s = socket(AF_INET, SOCK_STREAM, 0); | |
364 if (s < 0) { | |
365 goto err; | |
366 } | |
367 | |
368 // Should this be handled in a separate thread to avoid blocking emulation? | |
369 if (connect(s, res->ai_addr, res->ai_addrlen) != 0) { | |
370 goto err; | |
371 } | |
372 | |
373 socket_blocking(s, 0); | |
374 mw->sock_fds[channel] = s; | |
375 mw->channel_state[channel] = SOCKST_TCP_EST; | |
376 mw->channel_flags |= 1 << (channel + 1); | |
377 printf("Connection established on ch %d with %s:%s\n", channel + 1, | |
378 addr->host, addr->dst_port); | |
379 | |
380 if (res) { | |
381 freeaddrinfo(res); | |
382 } | |
383 start_reply(mw, CMD_OK); | |
384 end_reply(mw); | |
385 return; | |
386 | |
387 err: | |
388 freeaddrinfo(res); | |
389 printf("Connection to %s:%s failed, %s\n", addr->host, addr->dst_port, strerror(errno)); | |
390 start_reply(mw, CMD_ERROR); | |
391 end_reply(mw); | |
392 } | |
393 | |
394 static void cmd_close(megawifi *mw) | |
395 { | |
396 int channel = mw->transmit_buffer[4] - 1; | |
397 | |
398 if (channel >= 15 || mw->sock_fds[channel] < 0) { | |
399 start_reply(mw, CMD_ERROR); | |
400 end_reply(mw); | |
401 return; | |
402 } | |
403 | |
404 socket_close(mw->sock_fds[channel]); | |
405 mw->sock_fds[channel] = -1; | |
406 mw->channel_state[channel] = SOCKST_NONE; | |
407 mw->channel_flags |= 1 << (channel + 1); | |
408 start_reply(mw, CMD_OK); | |
409 end_reply(mw); | |
410 } | |
411 | |
412 static void cmd_udp_set(megawifi *mw) | |
413 { | |
414 struct mw_addr_msg *addr = (struct mw_addr_msg*)(mw->transmit_buffer + 4); | |
415 unsigned int local_port, remote_port; | |
416 int s; | |
417 struct addrinfo *raddr; | |
418 struct addrinfo hints; | |
419 struct sockaddr_in local; | |
420 int err; | |
421 | |
422 uint8_t channel = addr->channel; | |
423 if (!channel || channel > 15 || mw->sock_fds[channel - 1] >= 0) { | |
424 goto err; | |
425 } | |
426 channel--; | |
427 local_port = atoi(addr->src_port); | |
428 remote_port = atoi(addr->dst_port); | |
429 | |
430 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { | |
431 printf("Datagram socket creation failed\n"); | |
432 goto err; | |
433 } | |
434 | |
435 memset(local.sin_zero, 0, sizeof(local.sin_zero)); | |
436 local.sin_family = AF_INET; | |
437 local.sin_addr.s_addr = htonl(INADDR_ANY); | |
438 local.sin_port = htons(local_port); | |
439 if (remote_port && addr->host[0]) { | |
440 // Communication with remote peer | |
441 printf("Set UDP ch %d, port %d to addr %s:%d\n", addr->channel, | |
442 local_port, addr->host, remote_port); | |
443 | |
444 memset(&hints, 0, sizeof(hints)); | |
445 hints.ai_family = AF_INET; | |
446 #ifndef _WIN32 | |
447 hints.ai_flags = AI_NUMERICSERV; | |
448 #endif | |
449 hints.ai_socktype = SOCK_DGRAM; | |
450 | |
451 if ((err = getaddrinfo(addr->host, addr->dst_port, &hints, &raddr)) != 0) { | |
452 printf("getaddrinfo failed: %s\n", gai_strerror(err)); | |
453 goto err; | |
454 } | |
455 mw->remote_addr[channel] = *((struct sockaddr_in*)raddr->ai_addr); | |
456 freeaddrinfo(raddr); | |
457 } else if (local_port) { | |
458 // Server in reuse mode | |
459 printf("Set UDP ch %d, src port %d\n", addr->channel, local_port); | |
460 mw->remote_addr[channel] = local; | |
461 } else { | |
462 printf("Invalid UDP socket data\n"); | |
463 goto err; | |
464 } | |
465 | |
466 if (bind(s, (struct sockaddr*)&local, sizeof(struct sockaddr_in)) < 0) { | |
467 printf("bind to port %d failed\n", local_port); | |
468 goto err; | |
469 } | |
470 | |
471 socket_blocking(s, 0); | |
472 mw->sock_fds[channel] = s; | |
473 mw->channel_state[channel] = SOCKST_UDP_READY; | |
474 mw->channel_flags |= 1 << (channel + 1); | |
475 | |
476 start_reply(mw, CMD_OK); | |
477 end_reply(mw); | |
478 | |
479 return; | |
480 | |
481 err: | |
482 start_reply(mw, CMD_ERROR); | |
483 end_reply(mw); | |
484 } | |
485 | |
486 #define AVATAR_BYTES (32 * 48 / 2) | |
487 static void cmd_gamertag_get(megawifi *mw) | |
488 { | |
489 uint32_t id = htonl(1); | |
490 char buf[AVATAR_BYTES]; | |
491 | |
492 start_reply(mw, CMD_OK); | |
493 // TODO Get items from config file | |
494 mw_copy(mw, (uint8_t*)&id, 4); | |
495 strncpy(buf, "doragasu on Blastem!", 32); | |
496 mw_copy(mw, (uint8_t*)buf, 32); | |
497 strncpy(buf, "My cool password", 32); | |
498 mw_copy(mw, (uint8_t*)buf, 32); | |
499 strncpy(buf, "All your WiFi are belong to me!", 32); | |
500 mw_copy(mw, (uint8_t*)buf, 32); | |
501 memset(buf, 0, 64); // Telegram token | |
502 mw_copy(mw, (uint8_t*)buf, 64); | |
503 mw_copy(mw, (uint8_t*)buf, AVATAR_BYTES); // Avatar tiles | |
504 mw_copy(mw, (uint8_t*)buf, 32); // Avatar palette | |
505 end_reply(mw); | |
506 } | |
507 | |
508 static void cmd_hrng_get(megawifi *mw) | |
509 { | |
510 uint16_t len = (mw->transmit_buffer[4]<<8) + mw->transmit_buffer[5]; | |
511 if (len > (MAX_RECV_SIZE - 4)) { | |
512 start_reply(mw, CMD_ERROR); | |
513 end_reply(mw); | |
514 return; | |
515 } | |
516 // Pseudo-random, but who cares | |
517 start_reply(mw, CMD_OK); | |
518 srand(time(NULL)); | |
519 for (uint16_t i = 0; i < len; i++) { | |
520 mw_putc(mw, rand()); | |
521 } | |
522 end_reply(mw); | |
523 } | |
524 | |
525 static void cmd_datetime(megawifi *mw) | |
526 { | |
527 start_reply(mw, CMD_OK); | |
528 #ifdef _WIN32 | |
529 __time64_t t = _time64(NULL); | |
530 int64_t t_be = htobe64(t); | |
531 mw_copy(mw, (uint8_t*)&t_be, sizeof(int64_t)); | |
532 mw_puts(mw, _ctime64(&t)); | |
533 #else | |
534 time_t t = time(NULL); | |
535 int64_t t_be = htobe64(t); | |
536 mw_copy(mw, (uint8_t*)&t_be, sizeof(int64_t)); | |
537 mw_puts(mw, ctime(&t)); | |
538 #endif | |
539 | |
540 mw_putc(mw, '\0'); | |
541 end_reply(mw); | |
542 } | |
543 | |
544 static void process_command(megawifi *mw) | |
545 { | |
546 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; | |
547 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; | |
548 if (size > mw->transmit_bytes - 4) { | |
549 size = mw->transmit_bytes - 4; | |
550 } | |
551 int orig_receive_bytes = mw->receive_bytes; | |
552 switch (command) | |
553 { | |
554 case CMD_VERSION: | |
555 start_reply(mw, CMD_OK); | |
556 mw_putc(mw, 1); | |
557 mw_putc(mw, 3); | |
558 mw_putc(mw, 0); | |
559 mw_puts(mw, "blastem"); | |
560 mw_putc(mw, '\0'); | |
561 end_reply(mw); | |
562 break; | |
563 case CMD_ECHO: | |
564 mw->receive_bytes = mw->transmit_bytes; | |
565 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); | |
566 break; | |
567 case CMD_AP_CFG_GET: | |
568 cmd_ap_cfg_get(mw); | |
569 break; | |
570 case CMD_IP_CURRENT: { | |
571 iface_info i; | |
572 if (get_host_address(&i)) { | |
573 start_reply(mw, CMD_OK); | |
574 //config number and reserved bytes | |
575 mw_set(mw, 0, 4); | |
576 //ip | |
577 mw_copy(mw, i.ip, sizeof(i.ip)); | |
578 //net mask | |
579 mw_copy(mw, i.net_mask, sizeof(i.net_mask)); | |
580 //gateway guess | |
581 mw_putc(mw, i.ip[0] & i.net_mask[0]); | |
582 mw_putc(mw, i.ip[1] & i.net_mask[1]); | |
583 mw_putc(mw, i.ip[2] & i.net_mask[2]); | |
584 mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1); | |
585 //dns | |
586 static const uint8_t localhost[] = {127,0,0,1}; | |
587 mw_copy(mw, localhost, sizeof(localhost)); | |
588 mw_copy(mw, localhost, sizeof(localhost)); | |
589 | |
590 } else { | |
591 start_reply(mw, CMD_ERROR); | |
592 } | |
593 end_reply(mw); | |
594 break; | |
595 } | |
596 case CMD_IP_CFG_GET: | |
597 cmd_ip_cfg_get(mw); | |
598 break; | |
599 case CMD_DEF_AP_CFG_GET: | |
600 start_reply(mw, CMD_OK); | |
601 mw_putc(mw, 0); | |
602 end_reply(mw); | |
603 break; | |
604 case CMD_AP_JOIN: | |
605 mw->module_state = STATE_READY; | |
606 start_reply(mw, CMD_OK); | |
607 end_reply(mw); | |
608 break; | |
609 case CMD_TCP_CON: | |
610 cmd_tcp_con(mw, size); | |
611 break; | |
612 case CMD_TCP_BIND:{ | |
613 if (size < 7){ | |
614 start_reply(mw, CMD_ERROR); | |
615 end_reply(mw); | |
616 break; | |
617 } | |
618 uint8_t channel = mw->transmit_buffer[10]; | |
619 if (!channel || channel > 15) { | |
620 start_reply(mw, CMD_ERROR); | |
621 end_reply(mw); | |
622 break; | |
623 } | |
624 channel--; | |
625 if (mw->sock_fds[channel] >= 0) { | |
626 socket_close(mw->sock_fds[channel]); | |
627 } | |
628 mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); | |
629 if (mw->sock_fds[channel] < 0) { | |
630 start_reply(mw, CMD_ERROR); | |
631 end_reply(mw); | |
632 break; | |
633 } | |
634 int value = 1; | |
635 setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value)); | |
636 struct sockaddr_in bind_addr; | |
637 memset(&bind_addr, 0, sizeof(bind_addr)); | |
638 bind_addr.sin_family = AF_INET; | |
639 bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); | |
640 if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { | |
641 socket_close(mw->sock_fds[channel]); | |
642 mw->sock_fds[channel] = -1; | |
643 start_reply(mw, CMD_ERROR); | |
644 end_reply(mw); | |
645 break; | |
646 } | |
647 int res = listen(mw->sock_fds[channel], 2); | |
648 start_reply(mw, res ? CMD_ERROR : CMD_OK); | |
649 if (res) { | |
650 socket_close(mw->sock_fds[channel]); | |
651 mw->sock_fds[channel] = -1; | |
652 } else { | |
653 mw->channel_flags |= 1 << (channel + 1); | |
654 mw->channel_state[channel] = SOCKST_TCP_LISTEN; | |
655 socket_blocking(mw->sock_fds[channel], 0); | |
656 } | |
657 end_reply(mw); | |
658 break; | |
659 } | |
660 case CMD_CLOSE: | |
661 cmd_close(mw); | |
662 break; | |
663 case CMD_UDP_SET: | |
664 cmd_udp_set(mw); | |
665 break; | |
666 case CMD_SOCK_STAT: { | |
667 uint8_t channel = mw->transmit_buffer[4]; | |
668 if (!channel || channel > 15) { | |
669 start_reply(mw, CMD_ERROR); | |
670 end_reply(mw); | |
671 break; | |
672 } | |
673 mw->channel_flags &= ~(1 << channel); | |
674 channel--; | |
675 poll_socket(mw, channel); | |
676 start_reply(mw, CMD_OK); | |
677 mw_putc(mw, mw->channel_state[channel]); | |
678 end_reply(mw); | |
679 break; | |
680 } | |
681 case CMD_DATETIME: | |
682 cmd_datetime(mw); | |
683 break; | |
684 case CMD_SYS_STAT: | |
685 poll_all_sockets(mw); | |
686 start_reply(mw, CMD_OK); | |
687 mw_putc(mw, mw->module_state); | |
688 mw_putc(mw, mw->flags); | |
689 mw_putc(mw, mw->channel_flags >> 8); | |
690 mw_putc(mw, mw->channel_flags); | |
691 end_reply(mw); | |
692 break; | |
693 case CMD_GAMERTAG_GET: | |
694 cmd_gamertag_get(mw); | |
695 break; | |
696 case CMD_LOG: | |
697 start_reply(mw, CMD_OK); | |
698 puts((char*)&mw->transmit_buffer[4]); | |
699 end_reply(mw); | |
700 break; | |
701 case CMD_HRNG_GET: | |
702 cmd_hrng_get(mw); | |
703 break; | |
704 case CMD_SERVER_URL_GET: | |
705 start_reply(mw, CMD_OK); | |
706 // FIXME: This should be get from config file | |
707 mw_puts(mw, "doragasu.com"); | |
708 mw_putc(mw,'\0'); | |
709 end_reply(mw); | |
710 break; | |
711 default: | |
712 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); | |
713 break; | |
714 } | |
715 } | |
716 | |
200 static void process_packet(megawifi *mw) | 717 static void process_packet(megawifi *mw) |
201 { | 718 { |
202 if (mw->transmit_channel == 0) { | 719 if (mw->transmit_channel == 0) { |
203 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; | 720 process_command(mw); |
204 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; | 721 } else { |
205 if (size > mw->transmit_bytes - 4) { | 722 uint8_t channel = mw->transmit_channel - 1; |
206 size = mw->transmit_bytes - 4; | 723 int channel_state = mw->channel_state[channel]; |
207 } | 724 int sock_fd = mw->sock_fds[channel]; |
208 int orig_receive_bytes = mw->receive_bytes; | 725 if (sock_fd >= 0 && channel_state == SOCKST_TCP_EST) { |
209 switch (command) | 726 int sent = send(sock_fd, (char*)mw->transmit_buffer, mw->transmit_bytes, 0); |
210 { | 727 if (sent < 0 && !socket_error_is_wouldblock()) { |
211 case CMD_VERSION: | 728 socket_close(sock_fd); |
212 start_reply(mw, CMD_OK); | 729 mw->sock_fds[channel] = -1; |
213 mw_putc(mw, 1); | 730 mw->channel_state[channel] = SOCKST_NONE; |
214 mw_putc(mw, 0); | 731 mw->channel_flags |= 1 << mw->transmit_channel; |
215 mw_puts(mw, "blastem"); | 732 } else if (sent < mw->transmit_bytes) { |
216 end_reply(mw); | 733 //TODO: save this data somewhere so it can be sent in poll_socket |
217 break; | 734 printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); |
218 case CMD_ECHO: | |
219 mw->receive_bytes = mw->transmit_bytes; | |
220 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); | |
221 break; | |
222 case CMD_IP_CURRENT: { | |
223 iface_info i; | |
224 if (get_host_address(&i)) { | |
225 start_reply(mw, CMD_OK); | |
226 //config number and reserved bytes | |
227 mw_set(mw, 0, 4); | |
228 //ip | |
229 mw_copy(mw, i.ip, sizeof(i.ip)); | |
230 //net mask | |
231 mw_copy(mw, i.net_mask, sizeof(i.net_mask)); | |
232 //gateway guess | |
233 mw_putc(mw, i.ip[0] & i.net_mask[0]); | |
234 mw_putc(mw, i.ip[1] & i.net_mask[1]); | |
235 mw_putc(mw, i.ip[2] & i.net_mask[2]); | |
236 mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1); | |
237 //dns | |
238 static const uint8_t localhost[] = {127,0,0,1}; | |
239 mw_copy(mw, localhost, sizeof(localhost)); | |
240 mw_copy(mw, localhost, sizeof(localhost)); | |
241 | |
242 } else { | |
243 start_reply(mw, CMD_ERROR); | |
244 } | 735 } |
245 end_reply(mw); | 736 } else if (sock_fd >= 0 && channel_state == SOCKST_UDP_READY) { |
246 break; | 737 udp_send(mw, channel); |
247 } | 738 } else { |
248 case CMD_AP_JOIN: | 739 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); |
249 mw->module_state = STATE_READY; | 740 } |
250 start_reply(mw, CMD_OK); | |
251 end_reply(mw); | |
252 break; | |
253 case CMD_TCP_BIND:{ | |
254 if (size < 7){ | |
255 start_reply(mw, CMD_ERROR); | |
256 end_reply(mw); | |
257 break; | |
258 } | |
259 uint8_t channel = mw->transmit_buffer[10]; | |
260 if (!channel || channel > 15) { | |
261 start_reply(mw, CMD_ERROR); | |
262 end_reply(mw); | |
263 break; | |
264 } | |
265 channel--; | |
266 if (mw->sock_fds[channel] >= 0) { | |
267 close(mw->sock_fds[channel]); | |
268 } | |
269 mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); | |
270 if (mw->sock_fds[channel] < 0) { | |
271 start_reply(mw, CMD_ERROR); | |
272 end_reply(mw); | |
273 break; | |
274 } | |
275 int value = 1; | |
276 setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); | |
277 struct sockaddr_in bind_addr; | |
278 memset(&bind_addr, 0, sizeof(bind_addr)); | |
279 bind_addr.sin_family = AF_INET; | |
280 bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); | |
281 if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { | |
282 close(mw->sock_fds[channel]); | |
283 mw->sock_fds[channel] = -1; | |
284 start_reply(mw, CMD_ERROR); | |
285 end_reply(mw); | |
286 break; | |
287 } | |
288 int res = listen(mw->sock_fds[channel], 2); | |
289 start_reply(mw, res ? CMD_ERROR : CMD_OK); | |
290 if (res) { | |
291 close(mw->sock_fds[channel]); | |
292 mw->sock_fds[channel] = -1; | |
293 } else { | |
294 mw->channel_flags |= 1 << (channel + 1); | |
295 mw->channel_state[channel] = 1; | |
296 #ifndef _WIN32 | |
297 //FIXME: Set nonblocking on Windows too | |
298 fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK); | |
299 #endif | |
300 } | |
301 end_reply(mw); | |
302 break; | |
303 } | |
304 case CMD_SOCK_STAT: { | |
305 uint8_t channel = mw->transmit_buffer[4]; | |
306 if (!channel || channel > 15) { | |
307 start_reply(mw, CMD_ERROR); | |
308 end_reply(mw); | |
309 break; | |
310 } | |
311 mw->channel_flags &= ~(1 << channel); | |
312 channel--; | |
313 poll_socket(mw, channel); | |
314 start_reply(mw, CMD_OK); | |
315 mw_putc(mw, mw->channel_state[channel]); | |
316 end_reply(mw); | |
317 break; | |
318 } | |
319 case CMD_SYS_STAT: | |
320 poll_all_sockets(mw); | |
321 start_reply(mw, CMD_OK); | |
322 mw_putc(mw, mw->module_state); | |
323 mw_putc(mw, mw->flags); | |
324 mw_putc(mw, mw->channel_flags >> 8); | |
325 mw_putc(mw, mw->channel_flags); | |
326 end_reply(mw); | |
327 break; | |
328 default: | |
329 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); | |
330 break; | |
331 } | |
332 } else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) { | |
333 uint8_t channel = mw->transmit_channel - 1; | |
334 int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, MSG_NOSIGNAL); | |
335 if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
336 close(mw->sock_fds[channel]); | |
337 mw->sock_fds[channel] = -1; | |
338 mw->channel_state[channel] = 0; | |
339 mw->channel_flags |= 1 << mw->transmit_channel; | |
340 } else if (sent < mw->transmit_bytes) { | |
341 //TODO: save this data somewhere so it can be sent in poll_socket | |
342 printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); | |
343 } | |
344 } else { | |
345 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); | |
346 } | 741 } |
347 mw->transmit_bytes = mw->expected_bytes = 0; | 742 mw->transmit_bytes = mw->expected_bytes = 0; |
348 } | 743 } |
349 | 744 |
350 void *megawifi_write_b(uint32_t address, void *context, uint8_t value) | 745 void *megawifi_write_b(uint32_t address, void *context, uint8_t value) |