Mercurial > repos > blastem
comparison megawifi.c @ 1959:6d99bdbf1e3e
megawifi: refactor and update commands
author | doragasu <doragasu@hotmail.com> |
---|---|
date | Sun, 03 May 2020 12:38:28 -0700 |
parents | 1a09422b87a5 |
children | f79e16d8baa4 |
comparison
equal
deleted
inserted
replaced
1958:9c01945b5d20 | 1959:6d99bdbf1e3e |
---|---|
23 TX_PAYLOAD, | 23 TX_PAYLOAD, |
24 TX_WAIT_ETX | 24 TX_WAIT_ETX |
25 }; | 25 }; |
26 #define STX 0x7E | 26 #define STX 0x7E |
27 #define ETX 0x7E | 27 #define ETX 0x7E |
28 #define MAX_RECV_SIZE 1440 | 28 #define MAX_RECV_SIZE 1460 |
29 | 29 |
30 #define E(N) N | 30 #define E(N) N |
31 enum { | 31 enum { |
32 #include "mw_commands.c" | 32 #include "mw_commands.c" |
33 CMD_ERROR = 255 | 33 CMD_ERROR = 255 |
48 STATE_AP_JOIN, | 48 STATE_AP_JOIN, |
49 STATE_SCAN, | 49 STATE_SCAN, |
50 STATE_READY, | 50 STATE_READY, |
51 STATE_TRANSPARENT | 51 STATE_TRANSPARENT |
52 }; | 52 }; |
53 | |
54 enum { | |
55 SOCKST_NONE = 0, | |
56 SOCKST_TCP_LISTEN, | |
57 SOCKST_TCP_EST, | |
58 SOCKST_UDP_READY | |
59 }; | |
60 | |
53 | 61 |
54 #define FLAG_ONLINE | 62 #define FLAG_ONLINE |
55 | 63 |
56 typedef struct { | 64 typedef struct { |
57 uint32_t transmit_bytes; | 65 uint32_t transmit_bytes; |
110 } | 118 } |
111 memcpy(mw->receive_buffer + mw->receive_bytes, src, count); | 119 memcpy(mw->receive_buffer + mw->receive_bytes, src, count); |
112 mw->receive_bytes += count; | 120 mw->receive_bytes += count; |
113 } | 121 } |
114 | 122 |
115 static void mw_puts(megawifi *mw, char *s) | 123 static void mw_putraw(megawifi *mw, const char *data, size_t len) |
116 { | 124 { |
117 uint32_t len = strlen(s); | |
118 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { | 125 if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) { |
119 return; | 126 return; |
120 } | 127 } |
121 memcpy(mw->receive_buffer + mw->receive_bytes, s, len); | 128 memcpy(mw->receive_buffer + mw->receive_bytes, data, len); |
122 mw->receive_bytes += len; | 129 mw->receive_bytes += len; |
130 } | |
131 | |
132 static void mw_puts(megawifi *mw, const char *s) | |
133 { | |
134 size_t len = strlen(s); | |
135 mw_putraw(mw, s, len); | |
123 } | 136 } |
124 | 137 |
125 static void poll_socket(megawifi *mw, uint8_t channel) | 138 static void poll_socket(megawifi *mw, uint8_t channel) |
126 { | 139 { |
127 if (mw->sock_fds[channel] < 0) { | 140 if (mw->sock_fds[channel] < 0) { |
128 return; | 141 return; |
129 } | 142 } |
130 if (mw->channel_state[channel] == 1) { | 143 if (mw->channel_state[channel] == SOCKST_TCP_LISTEN) { |
131 int res = accept(mw->sock_fds[channel], NULL, NULL); | 144 int res = accept(mw->sock_fds[channel], NULL, NULL); |
132 if (res >= 0) { | 145 if (res >= 0) { |
133 close(mw->sock_fds[channel]); | 146 close(mw->sock_fds[channel]); |
134 #ifndef _WIN32 | 147 #ifndef _WIN32 |
135 //FIXME: Set nonblocking on Windows too | 148 //FIXME: Set nonblocking on Windows too |
136 fcntl(res, F_SETFL, O_NONBLOCK); | 149 fcntl(res, F_SETFL, O_NONBLOCK); |
137 #endif | 150 #endif |
138 mw->sock_fds[channel] = res; | 151 mw->sock_fds[channel] = res; |
139 mw->channel_state[channel] = 2; | 152 mw->channel_state[channel] = SOCKST_TCP_EST; |
140 mw->channel_flags |= 1 << (channel + 1); | 153 mw->channel_flags |= 1 << (channel + 1); |
141 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { | 154 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { |
142 close(mw->sock_fds[channel]); | 155 close(mw->sock_fds[channel]); |
143 mw->channel_state[channel] = 0; | 156 mw->channel_state[channel] = SOCKST_NONE; |
144 mw->channel_flags |= 1 << (channel + 1); | 157 mw->channel_flags |= 1 << (channel + 1); |
145 } | 158 } |
146 } else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) { | 159 } 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; | 160 size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes; |
148 if (max > MAX_RECV_SIZE) { | 161 if (max > MAX_RECV_SIZE) { |
149 max = MAX_RECV_SIZE; | 162 max = MAX_RECV_SIZE; |
150 } | 163 } |
151 int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0); | 164 int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0); |
156 mw->receive_bytes += bytes; | 169 mw->receive_bytes += bytes; |
157 mw_putc(mw, ETX); | 170 mw_putc(mw, ETX); |
158 //should this set the channel flag? | 171 //should this set the channel flag? |
159 } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | 172 } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { |
160 close(mw->sock_fds[channel]); | 173 close(mw->sock_fds[channel]); |
161 mw->channel_state[channel] = 0; | 174 mw->channel_state[channel] = SOCKST_NONE; |
162 mw->channel_flags |= 1 << (channel + 1); | 175 mw->channel_flags |= 1 << (channel + 1); |
163 } | 176 } |
164 } | 177 } |
165 } | 178 } |
166 | 179 |
195 mw->receive_buffer[5] = len >> 8; | 208 mw->receive_buffer[5] = len >> 8; |
196 mw->receive_buffer[6] = len; | 209 mw->receive_buffer[6] = len; |
197 mw_putc(mw, ETX); | 210 mw_putc(mw, ETX); |
198 } | 211 } |
199 | 212 |
200 static void process_packet(megawifi *mw) | 213 static void process_command(megawifi *mw) |
201 { | 214 { |
202 if (mw->transmit_channel == 0) { | 215 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; |
203 uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1]; | 216 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; |
204 uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3]; | 217 if (size > mw->transmit_bytes - 4) { |
205 if (size > mw->transmit_bytes - 4) { | 218 size = mw->transmit_bytes - 4; |
206 size = mw->transmit_bytes - 4; | 219 } |
207 } | 220 int orig_receive_bytes = mw->receive_bytes; |
208 int orig_receive_bytes = mw->receive_bytes; | 221 switch (command) |
209 switch (command) | 222 { |
210 { | 223 case CMD_VERSION: |
211 case CMD_VERSION: | 224 start_reply(mw, CMD_OK); |
225 mw_putc(mw, 1); | |
226 mw_putc(mw, 3); | |
227 mw_putc(mw, 0); | |
228 mw_puts(mw, "blastem"); | |
229 end_reply(mw); | |
230 break; | |
231 case CMD_ECHO: | |
232 mw->receive_bytes = mw->transmit_bytes; | |
233 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); | |
234 break; | |
235 case CMD_IP_CURRENT: { | |
236 iface_info i; | |
237 if (get_host_address(&i)) { | |
212 start_reply(mw, CMD_OK); | 238 start_reply(mw, CMD_OK); |
213 mw_putc(mw, 1); | 239 //config number and reserved bytes |
214 mw_putc(mw, 0); | 240 mw_set(mw, 0, 4); |
215 mw_puts(mw, "blastem"); | 241 //ip |
242 mw_copy(mw, i.ip, sizeof(i.ip)); | |
243 //net mask | |
244 mw_copy(mw, i.net_mask, sizeof(i.net_mask)); | |
245 //gateway guess | |
246 mw_putc(mw, i.ip[0] & i.net_mask[0]); | |
247 mw_putc(mw, i.ip[1] & i.net_mask[1]); | |
248 mw_putc(mw, i.ip[2] & i.net_mask[2]); | |
249 mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1); | |
250 //dns | |
251 static const uint8_t localhost[] = {127,0,0,1}; | |
252 mw_copy(mw, localhost, sizeof(localhost)); | |
253 mw_copy(mw, localhost, sizeof(localhost)); | |
254 | |
255 } else { | |
256 start_reply(mw, CMD_ERROR); | |
257 } | |
258 end_reply(mw); | |
259 break; | |
260 } | |
261 case CMD_AP_JOIN: | |
262 mw->module_state = STATE_READY; | |
263 start_reply(mw, CMD_OK); | |
264 end_reply(mw); | |
265 break; | |
266 case CMD_TCP_BIND:{ | |
267 if (size < 7){ | |
268 start_reply(mw, CMD_ERROR); | |
216 end_reply(mw); | 269 end_reply(mw); |
217 break; | 270 break; |
218 case CMD_ECHO: | 271 } |
219 mw->receive_bytes = mw->transmit_bytes; | 272 uint8_t channel = mw->transmit_buffer[10]; |
220 memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes); | 273 if (!channel || channel > 15) { |
221 break; | 274 start_reply(mw, CMD_ERROR); |
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 } | |
245 end_reply(mw); | 275 end_reply(mw); |
246 break; | 276 break; |
247 } | 277 } |
248 case CMD_AP_JOIN: | 278 channel--; |
249 mw->module_state = STATE_READY; | 279 if (mw->sock_fds[channel] >= 0) { |
250 start_reply(mw, CMD_OK); | 280 close(mw->sock_fds[channel]); |
281 } | |
282 mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); | |
283 if (mw->sock_fds[channel] < 0) { | |
284 start_reply(mw, CMD_ERROR); | |
251 end_reply(mw); | 285 end_reply(mw); |
252 break; | 286 break; |
253 case CMD_TCP_BIND:{ | 287 } |
254 if (size < 7){ | 288 int value = 1; |
255 start_reply(mw, CMD_ERROR); | 289 setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); |
256 end_reply(mw); | 290 struct sockaddr_in bind_addr; |
257 break; | 291 memset(&bind_addr, 0, sizeof(bind_addr)); |
258 } | 292 bind_addr.sin_family = AF_INET; |
259 uint8_t channel = mw->transmit_buffer[10]; | 293 bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]); |
260 if (!channel || channel > 15) { | 294 if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) { |
261 start_reply(mw, CMD_ERROR); | 295 close(mw->sock_fds[channel]); |
262 end_reply(mw); | 296 mw->sock_fds[channel] = -1; |
263 break; | 297 start_reply(mw, CMD_ERROR); |
264 } | 298 end_reply(mw); |
265 channel--; | 299 break; |
266 if (mw->sock_fds[channel] >= 0) { | 300 } |
267 close(mw->sock_fds[channel]); | 301 int res = listen(mw->sock_fds[channel], 2); |
268 } | 302 start_reply(mw, res ? CMD_ERROR : CMD_OK); |
269 mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0); | 303 if (res) { |
270 if (mw->sock_fds[channel] < 0) { | 304 close(mw->sock_fds[channel]); |
271 start_reply(mw, CMD_ERROR); | 305 mw->sock_fds[channel] = -1; |
272 end_reply(mw); | 306 } else { |
273 break; | 307 mw->channel_flags |= 1 << (channel + 1); |
274 } | 308 mw->channel_state[channel] = SOCKST_TCP_LISTEN; |
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 | 309 #ifndef _WIN32 |
297 //FIXME: Set nonblocking on Windows too | 310 //FIXME: Set nonblocking on Windows too |
298 fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK); | 311 fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK); |
299 #endif | 312 #endif |
313 } | |
314 end_reply(mw); | |
315 break; | |
316 } | |
317 case CMD_SOCK_STAT: { | |
318 uint8_t channel = mw->transmit_buffer[4]; | |
319 if (!channel || channel > 15) { | |
320 start_reply(mw, CMD_ERROR); | |
321 end_reply(mw); | |
322 break; | |
323 } | |
324 mw->channel_flags &= ~(1 << channel); | |
325 channel--; | |
326 poll_socket(mw, channel); | |
327 start_reply(mw, CMD_OK); | |
328 mw_putc(mw, mw->channel_state[channel]); | |
329 end_reply(mw); | |
330 break; | |
331 } | |
332 case CMD_SYS_STAT: | |
333 poll_all_sockets(mw); | |
334 start_reply(mw, CMD_OK); | |
335 mw_putc(mw, mw->module_state); | |
336 mw_putc(mw, mw->flags); | |
337 mw_putc(mw, mw->channel_flags >> 8); | |
338 mw_putc(mw, mw->channel_flags); | |
339 end_reply(mw); | |
340 break; | |
341 default: | |
342 printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size); | |
343 break; | |
344 } | |
345 } | |
346 | |
347 static void process_packet(megawifi *mw) | |
348 { | |
349 if (mw->transmit_channel == 0) { | |
350 process_command(mw); | |
351 } else { | |
352 uint8_t channel = mw->transmit_channel - 1; | |
353 int channel_state = mw->channel_state[channel]; | |
354 int sock_fd = mw->sock_fds[channel]; | |
355 // TODO Handle UDP type sockets | |
356 if (sock_fd >= 0 && channel_state == SOCKST_TCP_EST) { | |
357 int sent = send(sock_fd, mw->transmit_buffer, mw->transmit_bytes, MSG_NOSIGNAL); | |
358 if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
359 close(sock_fd); | |
360 mw->sock_fds[channel] = -1; | |
361 mw->channel_state[channel] = SOCKST_NONE; | |
362 mw->channel_flags |= 1 << mw->transmit_channel; | |
363 } else if (sent < mw->transmit_bytes) { | |
364 //TODO: save this data somewhere so it can be sent in poll_socket | |
365 printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes); | |
300 } | 366 } |
301 end_reply(mw); | 367 } else { |
302 break; | 368 printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel); |
303 } | 369 } |
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 } | 370 } |
347 mw->transmit_bytes = mw->expected_bytes = 0; | 371 mw->transmit_bytes = mw->expected_bytes = 0; |
348 } | 372 } |
349 | 373 |
350 void *megawifi_write_b(uint32_t address, void *context, uint8_t value) | 374 void *megawifi_write_b(uint32_t address, void *context, uint8_t value) |