Mercurial > repos > blastem
diff 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 |
line wrap: on
line diff
--- a/megawifi.c Sun Apr 19 00:59:49 2020 -0700 +++ b/megawifi.c Sat May 09 23:39:44 2020 -0700 @@ -6,15 +6,28 @@ #define WINVER 0x501 #include <winsock2.h> #include <ws2tcpip.h> +#include <sys/param.h> #else #include <sys/socket.h> +#include <arpa/inet.h> #include <unistd.h> #include <netinet/in.h> +#include <netdb.h> #endif #include <errno.h> #include <fcntl.h> +#include <time.h> #include "genesis.h" #include "net.h" +#include "util.h" + +#ifdef _WIN32 +# if BYTE_ORDER == LITTLE_ENDIAN +#define htobe64(val) ((((uint64_t)htonl((val)&0xFFFFFFFF))<<32) | htonl((val)>>32)) +# else +#define htobe64(val) (val) +# endif +#endif enum { TX_IDLE, @@ -25,7 +38,7 @@ }; #define STX 0x7E #define ETX 0x7E -#define MAX_RECV_SIZE 1440 +#define MAX_RECV_SIZE 1460 #define E(N) N enum { @@ -43,7 +56,7 @@ #define MSG_NOSIGNAL 0 #endif -enum { +enum mw_state { STATE_IDLE=1, STATE_AP_JOIN, STATE_SCAN, @@ -51,6 +64,21 @@ STATE_TRANSPARENT }; +enum { + SOCKST_NONE = 0, + SOCKST_TCP_LISTEN, + SOCKST_TCP_EST, + SOCKST_UDP_READY +}; + +// TCP/UDP address message +struct mw_addr_msg { + char dst_port[6]; + char src_port[6]; + uint8_t channel; + char host[]; +}; + #define FLAG_ONLINE typedef struct { @@ -68,6 +96,7 @@ uint8_t flags; uint8_t transmit_buffer[4096]; uint8_t receive_buffer[4096]; + struct sockaddr_in remote_addr[15]; // Needed for UDP sockets } megawifi; static megawifi *get_megawifi(void *context) @@ -75,11 +104,12 @@ m68k_context *m68k = context; genesis_context *gen = m68k->system; if (!gen->extra) { + socket_init(); gen->extra = calloc(1, sizeof(megawifi)); megawifi *mw = gen->extra; mw->module_state = STATE_IDLE; - for (int i = 0; i < 15; i++) - { + mw->flags = 0xE0; // cfg_ok, dt_ok, online + for (int i = 0; i < 15; i++) { mw->sock_fds[i] = -1; } } @@ -112,14 +142,88 @@ mw->receive_bytes += count; } -static void mw_puts(megawifi *mw, char *s) +static void mw_puts(megawifi *mw, const char *s) +{ + size_t len = strlen(s); + mw_copy(mw, (uint8_t*)s, len); +} + +static void udp_recv(megawifi *mw, uint8_t idx) { - uint32_t len = strlen(s); - if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { - return; + ssize_t recvd; + int s = mw->sock_fds[idx]; + struct sockaddr_in remote; + socklen_t addr_len = sizeof(struct sockaddr_in); + + if (mw->remote_addr[idx].sin_addr.s_addr != htonl(INADDR_ANY)) { + // Receive only from specified address + recvd = recvfrom(s, (char*)mw->receive_buffer + 3, MAX_RECV_SIZE, 0, + (struct sockaddr*)&remote, &addr_len); + if (recvd > 0) { + if (remote.sin_addr.s_addr != mw->remote_addr[idx].sin_addr.s_addr) { + printf("Discarding UDP packet from unknown addr %s:%d\n", + inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); + recvd = 0; + } + } + } else { + // Reuse mode, data is preceded by remote IPv4 and port + recvd = recvfrom(s, (char*)mw->receive_buffer + 9, MAX_RECV_SIZE - 6, + 0, (struct sockaddr*)&remote, &addr_len); + if (recvd > 0) { + mw->receive_buffer[3] = remote.sin_addr.s_addr; + mw->receive_buffer[4] = remote.sin_addr.s_addr>>8; + mw->receive_buffer[5] = remote.sin_addr.s_addr>>16; + mw->receive_buffer[6] = remote.sin_addr.s_addr>>24; + mw->receive_buffer[7] = remote.sin_port; + mw->receive_buffer[8] = remote.sin_port>>8; + recvd += 6; + } } - memcpy(mw->receive_buffer + mw->receive_bytes, s, len); - mw->receive_bytes += len; + + if (recvd > 0) { + mw_putc(mw, STX); + mw_putc(mw, (recvd >> 8) | ((idx+1) << 4)); + mw_putc(mw, recvd); + mw->receive_bytes += recvd; + mw_putc(mw, ETX); + //should this set the channel flag? + } else if (recvd < 0 && !socket_error_is_wouldblock()) { + socket_close(mw->sock_fds[idx]); + mw->channel_state[idx] = SOCKST_NONE; + mw->channel_flags |= 1 << (idx + 1); + } +} + +static void udp_send(megawifi *mw, uint8_t idx) +{ + struct sockaddr_in remote; + int s = mw->sock_fds[idx]; + int sent; + char *data = (char*)mw->transmit_buffer; + + if (mw->remote_addr[idx].sin_addr.s_addr != htonl(INADDR_ANY)) { + sent = sendto(s, data, mw->transmit_bytes, 0, (struct sockaddr*)&mw->remote_addr[idx], + sizeof(struct sockaddr_in)); + } else { + // Reuse mode, extract address from leading bytes + // NOTE: mw->remote_addr[idx].sin_addr.s_addr == INADDR_ANY + remote.sin_addr.s_addr = *((int32_t*)data); + remote.sin_port = *((int16_t*)(data + 4)); + remote.sin_family = AF_INET; + memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); + sent = sendto(s, data + 6, mw->transmit_bytes - 6, 0, (struct sockaddr*)&remote, + sizeof(struct sockaddr_in)) + 6; + } + if (sent < 0 && !socket_error_is_wouldblock()) { + socket_close(s); + mw->sock_fds[idx] = -1; + mw->channel_state[idx] = SOCKST_NONE; + mw->channel_flags |= 1 << (idx + 1); + } else if (sent < mw->transmit_bytes) { + //TODO: save this data somewhere so it can be sent in poll_socket + printf("Sent %d bytes on channel %d, but %d were requested\n", sent, idx + 1, mw->transmit_bytes); + } } static void poll_socket(megawifi *mw, uint8_t channel) @@ -127,28 +231,25 @@ if (mw->sock_fds[channel] < 0) { return; } - if (mw->channel_state[channel] == 1) { + if (mw->channel_state[channel] == SOCKST_TCP_LISTEN) { int res = accept(mw->sock_fds[channel], NULL, NULL); if (res >= 0) { - close(mw->sock_fds[channel]); -#ifndef _WIN32 -//FIXME: Set nonblocking on Windows too - fcntl(res, F_SETFL, O_NONBLOCK); -#endif + socket_close(mw->sock_fds[channel]); + socket_blocking(res, 0); mw->sock_fds[channel] = res; - mw->channel_state[channel] = 2; + mw->channel_state[channel] = SOCKST_TCP_EST; mw->channel_flags |= 1 << (channel + 1); } else if (errno != EAGAIN && errno != EWOULDBLOCK) { - close(mw->sock_fds[channel]); - mw->channel_state[channel] = 0; + socket_close(mw->sock_fds[channel]); + mw->channel_state[channel] = SOCKST_NONE; mw->channel_flags |= 1 << (channel + 1); } - } else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) { + } else if (mw->channel_state[channel] == SOCKST_TCP_EST && mw->receive_bytes < (sizeof(mw->receive_buffer) - 4)) { size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes; if (max > MAX_RECV_SIZE) { max = MAX_RECV_SIZE; } - int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0); + int bytes = recv(mw->sock_fds[channel], (char*)(mw->receive_buffer + mw->receive_bytes + 3), max, 0); if (bytes > 0) { mw_putc(mw, STX); mw_putc(mw, bytes >> 8 | (channel+1) << 4); @@ -156,11 +257,13 @@ mw->receive_bytes += bytes; mw_putc(mw, ETX); //should this set the channel flag? - } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - close(mw->sock_fds[channel]); - mw->channel_state[channel] = 0; + } else if (bytes < 0 && !socket_error_is_wouldblock()) { + socket_close(mw->sock_fds[channel]); + mw->channel_state[channel] = SOCKST_NONE; mw->channel_flags |= 1 << (channel + 1); } + } else if (mw->channel_state[channel] == SOCKST_UDP_READY && !mw->receive_bytes) { + udp_recv(mw, channel); } } @@ -172,6 +275,7 @@ } } + static void start_reply(megawifi *mw, uint8_t cmd) { mw_putc(mw, STX); @@ -197,152 +301,443 @@ mw_putc(mw, ETX); } -static void process_packet(megawifi *mw) +static void cmd_ap_cfg_get(megawifi *mw) +{ + char ssid[32] = {0}; + char pass[64] = {0}; + uint8_t slot = mw->transmit_buffer[4]; + + sprintf(ssid, "BLASTEM! SSID %d", slot + 1); + sprintf(pass, "BLASTEM! PASS %d", slot + 1); + start_reply(mw, CMD_OK); + mw_putc(mw, slot); + mw_putc(mw, 7); /// 11bgn + mw_copy(mw, (uint8_t*)ssid, 32); + mw_copy(mw, (uint8_t*)pass, 64); + end_reply(mw); +} + +static void cmd_ip_cfg_get(megawifi *mw) +{ + uint32_t ipv4s[5] = {0}; + + start_reply(mw, CMD_OK); + mw_putc(mw, mw->transmit_buffer[4]); + mw_putc(mw, 0); + mw_putc(mw, 0); + mw_putc(mw, 0); + mw_copy(mw, (uint8_t*)ipv4s, sizeof(ipv4s)); + end_reply(mw); +} + +static void cmd_tcp_con(megawifi *mw, uint32_t size) +{ + struct mw_addr_msg *addr = (struct mw_addr_msg*)(mw->transmit_buffer + 4); + struct addrinfo hints; + struct addrinfo *res = NULL; + int s; + int err; + + uint8_t channel = addr->channel; + if (!channel || channel > 15 || mw->sock_fds[channel - 1] >= 0) { + start_reply(mw, CMD_ERROR); + end_reply(mw); + return; + } + channel--; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; +#ifndef _WIN32 + hints.ai_flags = AI_NUMERICSERV; +#endif + hints.ai_socktype = SOCK_STREAM; + + if ((err = getaddrinfo(addr->host, addr->dst_port, &hints, &res)) != 0) { + printf("getaddrinfo failed: %s\n", gai_strerror(err)); + start_reply(mw, CMD_ERROR); + end_reply(mw); + return; + } + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + goto err; + } + + // Should this be handled in a separate thread to avoid blocking emulation? + if (connect(s, res->ai_addr, res->ai_addrlen) != 0) { + goto err; + } + + socket_blocking(s, 0); + mw->sock_fds[channel] = s; + mw->channel_state[channel] = SOCKST_TCP_EST; + mw->channel_flags |= 1 << (channel + 1); + printf("Connection established on ch %d with %s:%s\n", channel + 1, + addr->host, addr->dst_port); + + if (res) { + freeaddrinfo(res); + } + start_reply(mw, CMD_OK); + end_reply(mw); + return; + +err: + freeaddrinfo(res); + printf("Connection to %s:%s failed, %s\n", addr->host, addr->dst_port, strerror(errno)); + start_reply(mw, CMD_ERROR); + end_reply(mw); +} + +static void cmd_close(megawifi *mw) +{ + int channel = mw->transmit_buffer[4] - 1; + + if (channel >= 15 || mw->sock_fds[channel] < 0) { + start_reply(mw, CMD_ERROR); + end_reply(mw); + return; + } + + socket_close(mw->sock_fds[channel]); + mw->sock_fds[channel] = -1; + mw->channel_state[channel] = SOCKST_NONE; + mw->channel_flags |= 1 << (channel + 1); + start_reply(mw, CMD_OK); + end_reply(mw); +} + +static void cmd_udp_set(megawifi *mw) { - if (mw->transmit_channel == 0) { - uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; - uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; - if (size > mw->transmit_bytes - 4) { - size = mw->transmit_bytes - 4; + struct mw_addr_msg *addr = (struct mw_addr_msg*)(mw->transmit_buffer + 4); + unsigned int local_port, remote_port; + int s; + struct addrinfo *raddr; + struct addrinfo hints; + struct sockaddr_in local; + int err; + + uint8_t channel = addr->channel; + if (!channel || channel > 15 || mw->sock_fds[channel - 1] >= 0) { + goto err; + } + channel--; + local_port = atoi(addr->src_port); + remote_port = atoi(addr->dst_port); + + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + printf("Datagram socket creation failed\n"); + goto err; + } + + memset(local.sin_zero, 0, sizeof(local.sin_zero)); + local.sin_family = AF_INET; + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_port = htons(local_port); + if (remote_port && addr->host[0]) { + // Communication with remote peer + printf("Set UDP ch %d, port %d to addr %s:%d\n", addr->channel, + local_port, addr->host, remote_port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; +#ifndef _WIN32 + hints.ai_flags = AI_NUMERICSERV; +#endif + hints.ai_socktype = SOCK_DGRAM; + + if ((err = getaddrinfo(addr->host, addr->dst_port, &hints, &raddr)) != 0) { + printf("getaddrinfo failed: %s\n", gai_strerror(err)); + goto err; } - int orig_receive_bytes = mw->receive_bytes; - switch (command) - { - case CMD_VERSION: + mw->remote_addr[channel] = *((struct sockaddr_in*)raddr->ai_addr); + freeaddrinfo(raddr); + } else if (local_port) { + // Server in reuse mode + printf("Set UDP ch %d, src port %d\n", addr->channel, local_port); + mw->remote_addr[channel] = local; + } else { + printf("Invalid UDP socket data\n"); + goto err; + } + + if (bind(s, (struct sockaddr*)&local, sizeof(struct sockaddr_in)) < 0) { + printf("bind to port %d failed\n", local_port); + goto err; + } + + socket_blocking(s, 0); + mw->sock_fds[channel] = s; + mw->channel_state[channel] = SOCKST_UDP_READY; + mw->channel_flags |= 1 << (channel + 1); + + start_reply(mw, CMD_OK); + end_reply(mw); + + return; + +err: + start_reply(mw, CMD_ERROR); + end_reply(mw); +} + +#define AVATAR_BYTES (32 * 48 / 2) +static void cmd_gamertag_get(megawifi *mw) +{ + uint32_t id = htonl(1); + char buf[AVATAR_BYTES]; + + start_reply(mw, CMD_OK); + // TODO Get items from config file + mw_copy(mw, (uint8_t*)&id, 4); + strncpy(buf, "doragasu on Blastem!", 32); + mw_copy(mw, (uint8_t*)buf, 32); + strncpy(buf, "My cool password", 32); + mw_copy(mw, (uint8_t*)buf, 32); + strncpy(buf, "All your WiFi are belong to me!", 32); + mw_copy(mw, (uint8_t*)buf, 32); + memset(buf, 0, 64); // Telegram token + mw_copy(mw, (uint8_t*)buf, 64); + mw_copy(mw, (uint8_t*)buf, AVATAR_BYTES); // Avatar tiles + mw_copy(mw, (uint8_t*)buf, 32); // Avatar palette + end_reply(mw); +} + +static void cmd_hrng_get(megawifi *mw) +{ + uint16_t len = (mw->transmit_buffer[4]<<8) + mw->transmit_buffer[5]; + if (len > (MAX_RECV_SIZE - 4)) { + start_reply(mw, CMD_ERROR); + end_reply(mw); + return; + } + // Pseudo-random, but who cares + start_reply(mw, CMD_OK); + srand(time(NULL)); + for (uint16_t i = 0; i < len; i++) { + mw_putc(mw, rand()); + } + end_reply(mw); +} + +static void cmd_datetime(megawifi *mw) +{ + start_reply(mw, CMD_OK); +#ifdef _WIN32 + __time64_t t = _time64(NULL); + int64_t t_be = htobe64(t); + mw_copy(mw, (uint8_t*)&t_be, sizeof(int64_t)); + mw_puts(mw, _ctime64(&t)); +#else + time_t t = time(NULL); + int64_t t_be = htobe64(t); + mw_copy(mw, (uint8_t*)&t_be, sizeof(int64_t)); + mw_puts(mw, ctime(&t)); +#endif + + mw_putc(mw, '\0'); + end_reply(mw); +} + +static void process_command(megawifi *mw) +{ + uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; + uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; + if (size > mw->transmit_bytes - 4) { + size = mw->transmit_bytes - 4; + } + int orig_receive_bytes = mw->receive_bytes; + switch (command) + { + case CMD_VERSION: + start_reply(mw, CMD_OK); + mw_putc(mw, 1); + mw_putc(mw, 3); + mw_putc(mw, 0); + mw_puts(mw, "blastem"); + mw_putc(mw, '\0'); + end_reply(mw); + break; + case CMD_ECHO: + mw->receive_bytes = mw->transmit_bytes; + memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); + break; + case CMD_AP_CFG_GET: + cmd_ap_cfg_get(mw); + break; + case CMD_IP_CURRENT: { + iface_info i; + if (get_host_address(&i)) { start_reply(mw, CMD_OK); - mw_putc(mw, 1); - mw_putc(mw, 0); - mw_puts(mw, "blastem"); - end_reply(mw); - break; - case CMD_ECHO: - mw->receive_bytes = mw->transmit_bytes; - memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); - break; - case CMD_IP_CURRENT: { - iface_info i; - if (get_host_address(&i)) { - start_reply(mw, CMD_OK); - //config number and reserved bytes - mw_set(mw, 0, 4); - //ip - mw_copy(mw, i.ip, sizeof(i.ip)); - //net mask - mw_copy(mw, i.net_mask, sizeof(i.net_mask)); - //gateway guess - mw_putc(mw, i.ip[0] & i.net_mask[0]); - mw_putc(mw, i.ip[1] & i.net_mask[1]); - mw_putc(mw, i.ip[2] & i.net_mask[2]); - mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1); - //dns - static const uint8_t localhost[] = {127,0,0,1}; - mw_copy(mw, localhost, sizeof(localhost)); - mw_copy(mw, localhost, sizeof(localhost)); - - } else { - start_reply(mw, CMD_ERROR); - } + //config number and reserved bytes + mw_set(mw, 0, 4); + //ip + mw_copy(mw, i.ip, sizeof(i.ip)); + //net mask + mw_copy(mw, i.net_mask, sizeof(i.net_mask)); + //gateway guess + mw_putc(mw, i.ip[0] & i.net_mask[0]); + mw_putc(mw, i.ip[1] & i.net_mask[1]); + mw_putc(mw, i.ip[2] & i.net_mask[2]); + mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1); + //dns + static const uint8_t localhost[] = {127,0,0,1}; + mw_copy(mw, localhost, sizeof(localhost)); + mw_copy(mw, localhost, sizeof(localhost)); + + } else { + start_reply(mw, CMD_ERROR); + } + end_reply(mw); + break; + } + case CMD_IP_CFG_GET: + cmd_ip_cfg_get(mw); + break; + case CMD_DEF_AP_CFG_GET: + start_reply(mw, CMD_OK); + mw_putc(mw, 0); + end_reply(mw); + break; + case CMD_AP_JOIN: + mw->module_state = STATE_READY; + start_reply(mw, CMD_OK); + end_reply(mw); + break; + case CMD_TCP_CON: + cmd_tcp_con(mw, size); + break; + case CMD_TCP_BIND:{ + if (size < 7){ + start_reply(mw, CMD_ERROR); end_reply(mw); break; } - case CMD_AP_JOIN: - mw->module_state = STATE_READY; - start_reply(mw, CMD_OK); + uint8_t channel = mw->transmit_buffer[10]; + if (!channel || channel > 15) { + start_reply(mw, CMD_ERROR); + end_reply(mw); + break; + } + channel--; + if (mw->sock_fds[channel] >= 0) { + socket_close(mw->sock_fds[channel]); + } + mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); + if (mw->sock_fds[channel] < 0) { + start_reply(mw, CMD_ERROR); end_reply(mw); break; - case CMD_TCP_BIND:{ - if (size < 7){ - start_reply(mw, CMD_ERROR); - end_reply(mw); - break; - } - uint8_t channel = mw->transmit_buffer[10]; - if (!channel || channel > 15) { - start_reply(mw, CMD_ERROR); - end_reply(mw); - break; - } - channel--; - if (mw->sock_fds[channel] >= 0) { - close(mw->sock_fds[channel]); - } - mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); - if (mw->sock_fds[channel] < 0) { - start_reply(mw, CMD_ERROR); - end_reply(mw); - break; - } - int value = 1; - setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); - struct sockaddr_in bind_addr; - memset(&bind_addr, 0, sizeof(bind_addr)); - bind_addr.sin_family = AF_INET; - bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); - if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { - close(mw->sock_fds[channel]); - mw->sock_fds[channel] = -1; - start_reply(mw, CMD_ERROR); - end_reply(mw); - break; - } - int res = listen(mw->sock_fds[channel], 2); - start_reply(mw, res ? CMD_ERROR : CMD_OK); - if (res) { - close(mw->sock_fds[channel]); - mw->sock_fds[channel] = -1; - } else { - mw->channel_flags |= 1 << (channel + 1); - mw->channel_state[channel] = 1; -#ifndef _WIN32 -//FIXME: Set nonblocking on Windows too - fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK); -#endif - } + } + int value = 1; + setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value)); + struct sockaddr_in bind_addr; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.sin_family = AF_INET; + bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); + if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { + socket_close(mw->sock_fds[channel]); + mw->sock_fds[channel] = -1; + start_reply(mw, CMD_ERROR); + end_reply(mw); + break; + } + int res = listen(mw->sock_fds[channel], 2); + start_reply(mw, res ? CMD_ERROR : CMD_OK); + if (res) { + socket_close(mw->sock_fds[channel]); + mw->sock_fds[channel] = -1; + } else { + mw->channel_flags |= 1 << (channel + 1); + mw->channel_state[channel] = SOCKST_TCP_LISTEN; + socket_blocking(mw->sock_fds[channel], 0); + } + end_reply(mw); + break; + } + case CMD_CLOSE: + cmd_close(mw); + break; + case CMD_UDP_SET: + cmd_udp_set(mw); + break; + case CMD_SOCK_STAT: { + uint8_t channel = mw->transmit_buffer[4]; + if (!channel || channel > 15) { + start_reply(mw, CMD_ERROR); end_reply(mw); break; } - case CMD_SOCK_STAT: { - uint8_t channel = mw->transmit_buffer[4]; - if (!channel || channel > 15) { - start_reply(mw, CMD_ERROR); - end_reply(mw); - break; + mw->channel_flags &= ~(1 << channel); + channel--; + poll_socket(mw, channel); + start_reply(mw, CMD_OK); + mw_putc(mw, mw->channel_state[channel]); + end_reply(mw); + break; + } + case CMD_DATETIME: + cmd_datetime(mw); + break; + case CMD_SYS_STAT: + poll_all_sockets(mw); + start_reply(mw, CMD_OK); + mw_putc(mw, mw->module_state); + mw_putc(mw, mw->flags); + mw_putc(mw, mw->channel_flags >> 8); + mw_putc(mw, mw->channel_flags); + end_reply(mw); + break; + case CMD_GAMERTAG_GET: + cmd_gamertag_get(mw); + break; + case CMD_LOG: + start_reply(mw, CMD_OK); + puts((char*)&mw->transmit_buffer[4]); + end_reply(mw); + break; + case CMD_HRNG_GET: + cmd_hrng_get(mw); + break; + case CMD_SERVER_URL_GET: + start_reply(mw, CMD_OK); + // FIXME: This should be get from config file + mw_puts(mw, "doragasu.com"); + mw_putc(mw,'\0'); + end_reply(mw); + break; + default: + printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); + break; + } +} + +static void process_packet(megawifi *mw) +{ + if (mw->transmit_channel == 0) { + process_command(mw); + } else { + uint8_t channel = mw->transmit_channel - 1; + int channel_state = mw->channel_state[channel]; + int sock_fd = mw->sock_fds[channel]; + if (sock_fd >= 0 && channel_state == SOCKST_TCP_EST) { + int sent = send(sock_fd, (char*)mw->transmit_buffer, mw->transmit_bytes, 0); + if (sent < 0 && !socket_error_is_wouldblock()) { + socket_close(sock_fd); + mw->sock_fds[channel] = -1; + mw->channel_state[channel] = SOCKST_NONE; + mw->channel_flags |= 1 << mw->transmit_channel; + } else if (sent < mw->transmit_bytes) { + //TODO: save this data somewhere so it can be sent in poll_socket + printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); } - mw->channel_flags &= ~(1 << channel); - channel--; - poll_socket(mw, channel); - start_reply(mw, CMD_OK); - mw_putc(mw, mw->channel_state[channel]); - end_reply(mw); - break; + } else if (sock_fd >= 0 && channel_state == SOCKST_UDP_READY) { + udp_send(mw, channel); + } else { + printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); } - case CMD_SYS_STAT: - poll_all_sockets(mw); - start_reply(mw, CMD_OK); - mw_putc(mw, mw->module_state); - mw_putc(mw, mw->flags); - mw_putc(mw, mw->channel_flags >> 8); - mw_putc(mw, mw->channel_flags); - end_reply(mw); - break; - default: - printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); - break; - } - } else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) { - uint8_t channel = mw->transmit_channel - 1; - int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, MSG_NOSIGNAL); - if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { - close(mw->sock_fds[channel]); - mw->sock_fds[channel] = -1; - mw->channel_state[channel] = 0; - mw->channel_flags |= 1 << mw->transmit_channel; - } else if (sent < mw->transmit_bytes) { - //TODO: save this data somewhere so it can be sent in poll_socket - printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); - } - } else { - printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); } mw->transmit_bytes = mw->expected_bytes = 0; }