1: /*
2: * Guitar-ZyX(tm)::MasterControlProgram - portable guitar F/X controller
3: * Copyright (C) 2009 Douglas McClendon
4: *
5: * This program is free software: you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation, version 3 of the License.
8: *
9: * This program is distributed in the hope that it will be useful,
10: * but WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: * GNU General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program. If not, see <http://www.gnu.org/licenses/>.
16: */
17: /*
18: #############################################################################
19: #############################################################################
20: ##
21: ## gzmcpc::network: network functions
22: ##
23: #############################################################################
24: ##
25: ## Copyright 2008-2009 Douglas McClendon <dmc AT filteredperception DOT org>
26: ##
27: #############################################################################
28: #############################################################################
29: #
30: */
31:
32:
33:
34:
35: #include <nds.h>
36:
37: #include <dswifi9.h>
38:
39: #include <sys/socket.h>
40:
41: #include <netinet/in.h>
42:
43: #include <netdb.h>
44:
45: #include <unistd.h>
46:
47: #include <fcntl.h>
48:
49: #include <stdio.h>
50:
51: #include <stdarg.h>
52:
53: #include <string.h>
54:
55: #include <errno.h>
56:
57:
58:
59: #include "mode__tpw__jam.h"
60:
61: #include "debug.h"
62:
63: #include "graphics.h"
64:
65: #include "network.h"
66:
67: #include "sound.h"
68:
69:
70: #include "sounds.h"
71:
72: #include "sounds_bin.h"
73:
74:
75:
76:
77: network_state_mode network_state = NSM_START;
78: network_state_mode last_network_state = NSM_START;
79: int nsm_init = 0;
80:
81: u8 network_event_rate = DEFAULT_NETWORK_EVENT_RATE;
82:
83: int zyx_ap_id = -1;
84:
85: Wifi_AccessPoint zyx_ap;
86:
87: short cmd_port_number = GZMPCD_CMD_PORTNUM;
88: short bcast_port_number = GZMPCD_BCAST_PORTNUM;
89:
90: unsigned char wepkeys[4][32];
91:
92: int wepkeyid;
93:
94: int wepmode;
95:
96: int dhcp;
97:
98: struct in_addr gzmcpc_ipaddr = {0,};
99: int gzmcpc_ipaddr_last_byte = {0,};
100: struct in_addr gzmcpc_subnet_mask = {0,};
101: struct in_addr gzmcpc_gateway = {0,};
102: struct in_addr gzmcpc_dns1 = {0,};
103: struct in_addr gzmcpc_dns2 = {0,};
104:
105: char ap_ssid[SSID_MAXLEN + 1];
106:
107: time_val next_sync_with_server = {0, 0};
108:
109:
110: int cstate_preset = CM_PRESET_X_NUM;
111: int cstate_wpx = 63;
112: int cstate_wpy = 63;
113:
114:
115: int server_socket_fd = 0;
116:
117:
118:
119:
120: struct sockaddr_in bind_address;
121:
122: struct sockaddr_in bcaster_address;
123:
124: int bcast_socket_fd = 0;
125: long bcast_socket_fd_opts = 0;
126:
127: int network_vanished = 0;
128:
129: gzmcp_cmd newcmd;
130:
131: long magic_cookie;
132:
133: gzmcp_cmd handshake_cmd;
134:
135: time_val net_nap = {0, 0};
136:
137: time_val nsm_timeout = {0, 0};
138:
139:
140: int sstate_preset = -1;
141: int sstate_wpx = -1;
142: int sstate_wpy = -1;
143:
144:
145:
146:
147:
148:
149: void gzmcpc_init_net(void) {
150:
151: // gratuitous (test) debug logging
152: debug_log("in gzmcpc_init_net...\n");
153:
154: // initialize system wireless networking capabilities
155: gzmcpc_init_wifi();
156:
157: // initialize server_socket_fd
158: server_socket_fd = 0;
159: // initialize bcast_socket_fd
160: bcast_socket_fd = 0;
161:
162: // initialize network status
163: textout(TLT_NETWORK_STATUS, "offline");
164:
165: //
166: // initialize handshake
167: //
168:
169: // put the handshake magic cookie where it can be sizeof()d
170: magic_cookie = (long)GZMCP_DEF_MAGIC_COOKIE;
171:
172: // create the handshake_cmd packet (aka the handshake)
173: handshake_cmd.type = GZMCP_CMD_HANDSHAKE;
174: memcpy((void *)handshake_cmd.data.handshake.string,
175: (void *)&magic_cookie,
176: sizeof(magic_cookie));
177:
178: // XXX: stackcorruption?
179: // this ugliness stays until I find out how the .type field
180: // is getting corrupted.
181: debug_log_more("handshake_cmd.type is %d\n",
182: handshake_cmd.type);
183: debug_log_more("GZMCP_CMD_HANDSHAKE (gch) is %d\n",
184: GZMCP_CMD_HANDSHAKE);
185: debug_log_more("sizeof magic_cookie is %d\n",
186: sizeof(magic_cookie));
187: debug_log_more("handshake created...\n");
188:
189: }
190:
191:
192:
193: void gzmcpc_init_wifi(void) {
194:
195: // gratuitous (test) debug logging
196: debug_log("in gzmcpc_init_wifi...\n");
197:
198: // XXX: document the parameter (replace this comment)
199: Wifi_InitDefault(false);
200:
201: // init/cleanup (?unknown if needed, vaguely recall recommended)
202: Wifi_DisconnectAP();
203:
204: // init/cleanup (?unknown if needed, vaguely recall recommended)
205: Wifi_DisableWifi();
206:
207: }
208:
209:
210: void socket_set_blocking(int socket_fd) {
211:
212: int val_arg = 0;
213:
214: retval = ioctl(socket_fd, FIONBIO, &val_arg);
215:
216: // effective assertion
217: if (retval < 0) {
218: textout(TLT_ERROR, "socket ioctl failed");
219: die();
220: }
221:
222: }
223:
224:
225: void socket_set_nonblocking(int socket_fd) {
226:
227: int val_arg = 1;
228:
229: retval = ioctl(socket_fd, FIONBIO, &val_arg);
230:
231: // effective assertion
232: if (retval < 0) {
233: textout(TLT_ERROR, "socket ioctl failed");
234: die();
235: }
236:
237: }
238:
239:
240:
241: void debug_dump_cmd(gzmcp_cmd cmd) {
242: debug_log_more("debug_dump_command: cmd.type: %08x\n",
243: cmd.type);
244: debug_log_more("debug_dump_command: cmd[1-4]: %08x\n",
245: ((long *)&cmd)[0]);
246: debug_log_more("debug_dump_command: cmd[5-8]: %08x\n",
247: ((long *)&cmd)[1]);
248: debug_log_more("debug_dump_command: cmd[9-12]: %08x\n",
249: ((long *)&cmd)[2]);
250: debug_log_more("debug_dump_command: cmd[13-16]: %08x\n",
251: ((long *)&cmd)[3]);
252: }
253:
254:
255:
256: int xmit_cmd(int socket_fd, gzmcp_cmd cmd) {
257:
258: // for read/write return values
259: int numbytes;
260:
261: // only do work if needed
262: if ((network_state != NSM_ONLINE) &&
263: (cmd.type != GZMCP_CMD_HANDSHAKE)) {
264: return 0;
265: }
266:
267: debug_dump_cmd(cmd);
268:
269: // write the test message to the socket
270: numbytes = send(socket_fd,
271: (void *)&cmd,
272: sizeof(gzmcp_cmd),
273: 0);
274:
275: // check for errors
276: // if (numbytes < 0) textout(TLT_ERROR, "xmit_cmd:send");
277: // or not since non-blocking (but still should check for other errors)
278:
279: return numbytes;
280:
281: }
282:
283:
284:
285: void sync_with_server(void) {
286:
287: if (cstate_preset != sstate_preset) {
288:
289: //
290: // create a command packet and transmit to server
291: //
292: newcmd.type = GZMCP_CMD_PRESET;
293: newcmd.data.preset.channel = 1;
294: newcmd.data.preset.preset = cstate_preset;
295: xmit_cmd(server_socket_fd, newcmd);
296:
297: // update state
298: sstate_preset = cstate_preset;
299: }
300:
301: if (touch_whammy_enabled) {
302:
303: // XXX add optional decaying logic, i.e. only half the difference each time
304:
305: if (cstate_wpx != sstate_wpx) {
306: //
307: // create a command packet and transmit to server
308: //
309: newcmd.type = GZMCP_CMD_PARAMETER;
310: newcmd.data.parameter.channel = 1;
311: newcmd.data.parameter.parameter = touch_whammy_x_midi_parm;
312: newcmd.data.parameter.value = cstate_wpx;
313: xmit_cmd(server_socket_fd,
314: newcmd);
315:
316: // update state
317: sstate_wpx = cstate_wpx;
318: }
319:
320: if (cstate_wpy != sstate_wpy) {
321: //
322: // create a command packet and transmit to server
323: //
324: newcmd.type = GZMCP_CMD_PARAMETER;
325: newcmd.data.parameter.channel = 1;
326: newcmd.data.parameter.parameter = touch_whammy_y_midi_parm;
327: newcmd.data.parameter.value = cstate_wpy;
328: xmit_cmd(server_socket_fd,
329: newcmd);
330:
331: // update state
332: sstate_wpy = cstate_wpy;
333: }
334:
335: }
336:
337: }
338:
339:
340:
341: void netmode_go_offline(void) {
342:
343: // may be nothing to shutdown, so ignore return value
344: shutdown(server_socket_fd, 0);
345: closesocket(server_socket_fd);
346: shutdown(bcast_socket_fd, 0);
347: closesocket(bcast_socket_fd);
348:
349: // disconnect from network/AP
350: Wifi_DisconnectAP();
351: Wifi_DisableWifi();
352:
353: // cursor rotating is online indicator
354: cursor_rotating = 0;
355:
356: // print meaningful data to top lcd
357: textout(TLT_MODE, "L+start to go online");
358: // leave STATUS alone, as it may have an error message
359: // textout(TLT_STATUS, "XXX");
360: textout(TLT_NETWORK_STATUS, "offline");
361: textout(TLT_FX_MODE, "N/A");
362: textout(TLT_TOUCH_VAL, "X=NA /\\/ Y=NA");
363:
364: if (!user_vstrobe_enabled) {
365: vstrobe_enabled = 0;
366: }
367:
368: // ooh, ahh, earcandy
369: mmEffectEx(&sounds[SFX_OFFLINE]);
370:
371: }
372:
373:
374:
375: void netmode_offline_init(void) {
376:
377: netmode_go_offline();
378:
379: }
380:
381:
382:
383: network_state_mode netmode_offline_handle(void) {
384: // nothing to do while OFFLINE
385: return NSM_OFFLINE;
386: }
387:
388:
389:
390: void netmode_wscanning_init(void) {
391:
392: // extra cleanslate attempt (is start button bypassing go_offline somehow?)
393: Wifi_DisconnectAP();
394: Wifi_DisableWifi();
395:
396: Wifi_EnableWifi();
397:
398: vstrobe_enabled = 1;
399:
400: // initialize text display
401: // TODO generate progrometer from start time
402: textout(TLT_MODE, "net::going online");
403: textout(TLT_STATUS, "net init...");
404: textout(TLT_NETWORK_STATUS, "scanning nets...");
405:
406: Wifi_ScanMode();
407:
408: // set the network mode timeout relative to now
409: nsm_timeout = time_val_add_ms(num_ticks,
410: 1000 * WSCANNING_TIMEOUT_S);
411:
412: }
413:
414:
415:
416: network_state_mode netmode_wscanning_handle(void) {
417:
418: // for storing data of ap's from scan
419: Wifi_AccessPoint ap;
420: // and the ssid thereof
421: char ssidbuf[SSID_MAXLEN + 1];
422:
423: int i;
424: int num_networks;
425:
426:
427: // check for timeout condition
428: if (time_val_compare(num_ticks, nsm_timeout) < 0) {
429: // timeout expired
430: textout(TLT_STATUS, "wifi ap search timeout");
431: return NSM_OFFLINE;
432: } // end if timeout expired
433:
434: // note: could add logic here to make sure the search code
435: // is only executed 10 times a second. Curious to
436: // see if it effects the UI.
437:
438: num_networks = Wifi_GetNumAP();
439:
440: textout(TLT_STATUS, "%d networks found", num_networks);
441:
442: zyx_ap_id = -1;
443:
444: for (i = 0 ; i < num_networks ; i++) {
445:
446: if (WIFI_RETURN_OK == Wifi_GetAPData(i,&ap)) {
447:
448: strncpy(ssidbuf, ap.ssid, ap.ssid_len);
449:
450: // assumption: Wifi_GetAPData's returned ap. will never
451: // have ap.ssid_len (and .ssid) of >32, as
452: // per wifi spec. ssidbuf is 64.
453: // null terminate
454: ssidbuf[(int)ap.ssid_len] = 0;
455:
456: if (! strncmp(ap_ssid, ssidbuf, strlen(ap_ssid))) {
457: zyx_ap_id = i;
458: }
459:
460: } // end got data for ap
461:
462: } // end iteration over networks
463:
464: if (zyx_ap_id != -1) {
465:
466: return NSM_WASSOCIATING;
467:
468: }
469:
470: // havent found a good wifi ap yet, keep trying
471: return NSM_WSCANNING;
472: }
473:
474:
475:
476: void netmode_wassociating_init(void) {
477:
478: unsigned long dns1, dns2;
479:
480: // found a Guitar-ZyX Access Point
481: textout(TLT_MODE, "net::going online");
482: textout(TLT_STATUS, "found mcpnet...");
483: textout(TLT_NETWORK_STATUS, "connecting to net...");
484:
485: // in this case, flag _handle to go offline with appropriate message
486: if (Wifi_GetAPData(zyx_ap_id, &zyx_ap) != WIFI_RETURN_OK) {
487: network_vanished = 1;
488: // don't try to do rest of init
489: return;
490: } else {
491: network_vanished = 0;
492: }
493:
494: //
495: // initialize wep config
496: //
497:
498: wepkeyid = 0;
499:
500: // initialize wepkeys to null terminated strings
501: wepkeys[0][0] = 0;
502: wepkeys[1][0] = 0;
503: wepkeys[2][0] = 0;
504: wepkeys[3][0] = 0;
505:
506: wepmode = 0;
507:
508: // dns1 = 192.168.1.1
509: // dns1 = 0x0101A8C0;
510: // dns1 = 0xC0A80101;
511: dns1 = 0;
512:
513: // dns2 = 0.0.0.0
514: dns2 = 0;
515:
516: // dhcp IP/not dns, because gzmcp does not use dns
517: Wifi_SetIP(0, 0, 0, dns1, dns2);
518:
519: if (strncmp(ap_ssid, "wfc", strlen(ap_ssid)) == 0) {
520: // use user's firmware WFC connection info
521: // (as configured by another wifi enabled game/app)
522: Wifi_AutoConnect();
523: } else {
524: // use the user supplied ap_ssid
525: Wifi_ConnectAP(&zyx_ap, wepmode, wepkeyid, wepkeys[0]);
526: }
527:
528: textout(TLT_STATUS, "connecting to ap...");
529:
530: // set the scan timeout relative to now
531: nsm_timeout = time_val_add_ms(num_ticks,
532: 1000 * WASSOCIATING_TIMEOUT_S);
533:
534: }
535:
536:
537:
538: network_state_mode netmode_wassociating_handle(void) {
539:
540: int associated;
541:
542: // check for timeout condition
543: if (time_val_compare(num_ticks, nsm_timeout) < 0) {
544: // timeout expired
545: textout(TLT_STATUS, "net assoc timeout");
546: return NSM_OFFLINE;
547: } // end if timeout expired
548:
549: if (network_vanished) {
550: textout(TLT_STATUS, "network vanished");
551: return NSM_OFFLINE;
552: }
553:
554: //
555: // check associating status
556: //
557: associated = Wifi_AssocStatus();
558:
559: if (associated == ASSOCSTATUS_ASSOCIATED) {
560:
561: // clear mode&status now that connection is done
562: textout(TLT_MODE, "");
563: textout(TLT_STATUS, "");
564:
565: // store gzmcpc's ip info
566: gzmcpc_ipaddr = Wifi_GetIPInfo(&gzmcpc_gateway,
567: &gzmcpc_subnet_mask,
568: &gzmcpc_dns1,
569: &gzmcpc_dns2);
570:
571: // transmogrify network byte order into host byte order
572: gzmcpc_ipaddr.s_addr = ntohl(gzmcpc_ipaddr.s_addr);
573: gzmcpc_gateway.s_addr = ntohl(gzmcpc_gateway.s_addr);
574: gzmcpc_subnet_mask.s_addr = ntohl(gzmcpc_subnet_mask.s_addr);
575: gzmcpc_dns1.s_addr = ntohl(gzmcpc_dns1.s_addr);
576: gzmcpc_dns2.s_addr = ntohl(gzmcpc_dns2.s_addr);
577:
578: // get the last byte of our ipaddr, for possible debug output
579: // gzmcpc_ipaddr_last_byte =
580: // (int)(gzmcpc_ipaddr.s_addr -
581: // (gzmcpc_ipaddr.s_addr & gzmcpc_subnet_mask.s_addr));
582:
583: return NSM_BCAST_LISTEN;
584:
585: } // end case of assoc status == associated
586:
587: if (associated == ASSOCSTATUS_CANNOTCONNECT) {
588:
589: textout(TLT_STATUS, "net assoc failed");
590:
591: return NSM_OFFLINE;
592:
593: }
594:
595: // not yet associated, keep on trying...
596: return NSM_WASSOCIATING;
597:
598: }
599:
600:
601:
602: void netmode_bcast_listen_init(void) {
603:
604: int optval;
605:
606:
607: textout(TLT_MODE, "net::going online");
608: textout(TLT_STATUS, "joined network");
609: textout(TLT_NETWORK_STATUS, "server discovery...");
610:
611: debug_log("listening for server broadcasts on udp port %d\n",
612: bcast_port_number);
613:
614: debug_log("listening for magic cookie - 0x%08x\n",
615: magic_cookie);
616:
617: // create the broadcast reception udp socket
618: // - AF_INET means ipv4, vs AF_INET6 vs AF_UNIX/AF_LOCAL
619: // - SOCK_DGRAM means udp, vs SOCK_STREAM for tcp
620: // - 0 means default protocol type for family
621: bcast_socket_fd = socket(AF_INET,
622: SOCK_DGRAM,
623: 0);
624: if (bcast_socket_fd < 0) {
625: perror("socket()");
626: textout(TLT_ERROR, "couldn't create broadcast socket");
627: die();
628: }
629:
630: // enable broadcast
631: // note: perhaps this is unnecessary, since we only receive
632: optval = 1;
633: if (setsockopt(bcast_socket_fd,
634: SOL_SOCKET,
635: SO_BROADCAST,
636: &optval, sizeof(optval)) < 0) {
637: perror("setsockopt()");
638: debug_log("failed to set broadcast socket options\n");
639: textout(TLT_ERROR, "failed to set broadcast socket options");
640: die();
641: }
642:
643: // create a destination address structure, initialize...
644: memset((void *)&bind_address, 0, sizeof(bind_address));
645:
646: // configure the address structure for our purposes
647: // INET, vs e.g. UNIX for local non network sockets
648: bind_address.sin_family = AF_INET;
649: bind_address.sin_port = htons(bcast_port_number);
650: // we're going to bind to all local interfaces
651: bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
652:
653: if (bind(bcast_socket_fd,
654: (struct sockaddr *)&bind_address,
655: sizeof(bind_address)) < 0) {
656: perror("bind()");
657: textout(TLT_ERROR, "failed to bind to broadcast socket");
658: die();
659: }
660:
661: debug_log("now setting bcast socket to nonblocking...\n");
662:
663: // set socket to non-blocking mode
664: socket_set_nonblocking(bcast_socket_fd);
665:
666: // set the scan timeout relative to now
667: nsm_timeout = time_val_add_ms(num_ticks,
668: 1000 * BCAST_LISTEN_TIMEOUT_S);
669:
670: }
671:
672:
673:
674: network_state_mode netmode_bcast_listen_handle(void) {
675:
676: // buffer to receive broadcast messages
677: char beacon_msg[GZMCP_BEACON_MSG_MAXLEN + 1];
678:
679: // size of returned address structure
680: unsigned int from_length;
681:
682: // size of broadcast message data received
683: int bytes_received;
684:
685:
686: // check for timeout condition
687: if (time_val_compare(num_ticks, nsm_timeout) < 0) {
688: // timeout expired
689: textout(TLT_STATUS, "server discovery timeout");
690: return NSM_OFFLINE;
691: } // end if timeout expired
692:
693:
694: // initialize the length of the address result
695: from_length = sizeof(bcaster_address);
696:
697: // note: cast (int *) is due to different nds devsuite impl??
698: bytes_received = recvfrom(bcast_socket_fd,
699: beacon_msg,
700: GZMCP_BEACON_MSG_MAXLEN,
701: 0,
702: (struct sockaddr*)&bcaster_address,
703: (int *)&from_length);
704:
705: debug_log("debug: bytes_received for beacon was %d\n",
706: bytes_received);
707:
708: // check for locally failed recv
709: if (bytes_received < 0) {
710: // udp makes no guarantees
711: // perror("sendto()");
712: debug_log_more("could not receive message\n");
713: return NSM_BCAST_LISTEN;
714: }
715:
716: // check if message is a gzmcp server broadcast message
717: if (bcmp((void *)beacon_msg,
718: (void *)&magic_cookie,
719: 4) == 0) {
720: // a correct magic cookie
721: debug_log("server at %s had the right magic cookie!\n",
722: inet_ntoa(bcaster_address.sin_addr));
723:
724: // throttle a bit?
725: net_nap = time_val_add_ms(num_ticks, 420);
726:
727: // success, target server is in bcaster_address
728: return NSM_UNCONNECTED;
729:
730: } else {
731: // not a correct magic cookie
732: debug_log("got an incorrect magic cookie! ignoring...\n");
733: }
734:
735: // keep listening...
736: return NSM_BCAST_LISTEN;
737: }
738:
739:
740:
741: void netmode_unconnected_init(void) {
742:
743: debug_log("server found at ip address -- %s\n",
744: inet_ntoa(bcaster_address.sin_addr));
745:
746: textout(TLT_MODE, "net::going online");
747: textout(TLT_STATUS,
748: "server found");
749: // textout(TLT_STATUS,
750: // "srv::%s",
751: // inet_ntoa(bcaster_address.sin_addr));
752: textout(TLT_NETWORK_STATUS, "connecting...");
753:
754: //
755: // open an internet stream socket for the client
756: //
757:
758: // pointless init
759: server_socket_fd = 0;
760:
761: // create socket
762: server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
763:
764: // error check socket()
765: if (server_socket_fd < 0) {
766:
767: // TODO: make something like this the assertion function
768: textout(TLT_ERROR, "socket open failed");
769:
770: // assertion: should not fail
771: die();
772:
773: }
774:
775: // connect to cmd_port_number on the found server
776: bcaster_address.sin_port = htons(cmd_port_number);
777:
778: // set socket to non-blocking mode
779: socket_set_nonblocking(server_socket_fd);
780:
781: // debug throttling
782: net_nap = time_val_add_ms(num_ticks, 420);
783:
784: }
785:
786:
787:
788: network_state_mode netmode_unconnected_handle(void) {
789:
790: // NOTE: I was confused a bit, and had const as part of the cast of
791: // arg 2, but then realized the confusion was because const
792: // wasn't a necessary (or sensical) part of the cast. Actually
793: // I'm still a bit confused. The const in the man 2 connect
794: // prototype confuses me... I.e. the below doesn't generate
795: // warnings, but theoretically the data in bcaster_address is
796: // not const. (could be modified by another thread?).
797:
798: retval = connect(server_socket_fd,
799: (struct sockaddr *)&bcaster_address,
800: sizeof(bcaster_address));
801:
802: debug_log_more("connect retval for server connect was - %d ...\n",
803: retval);
804:
805: // historic(?) note: bad things happened with a textout+delay of errno here
806: // that was a delay with the archaic wait_a_bit function which spun around
807: // vblank intr
808:
809: // XXX catch and check errno appropriately
810:
811: // network throttling (in other words, probably a network race condition)
812: // (or maybe closesocket fixed that)
813: net_nap = time_val_add_ms(num_ticks, 420);
814:
815: // nonblocking, nonfatal
816: if (retval < 0) {
817: // keep trying...
818: return NSM_UNCONNECTED;
819: }
820:
821: // throttle a bit?
822: net_nap = time_val_add_ms(num_ticks, 420);
823:
824: debug_log("server socket now connected...\n");
825:
826: return NSM_CONNECTED;
827:
828: }
829:
830:
831:
832: void netmode_connected_init(void) {
833:
834: }
835:
836:
837:
838: network_state_mode netmode_connected_handle(void) {
839:
840: //
841: // connected, time to send handshake
842: //
843: // MAYBETODO: add current datestamp as part of handshake (maybe hashed)
844: // - or app version hash, password from flash, ...
845:
846:
847: // XXX: this is a workaround to ?stackcorruption? I.e. should only
848: // need to set this once, but somehow the .type field is getting
849: // reset to 0???
850: // create the handshake_cmd packet (aka the handshake)
851: handshake_cmd.type = GZMCP_CMD_HANDSHAKE;
852: memcpy((void *)handshake_cmd.data.handshake.string,
853: (void *)&magic_cookie,
854: sizeof(magic_cookie));
855:
856: // XXX: stackcorruption? (see other XXX comments)
857: debug_log_more("dumping handshake_cmd before sending it\n");
858: debug_dump_cmd(handshake_cmd);
859:
860: //
861: // transmit handshake to server
862: //
863: retval = xmit_cmd(server_socket_fd,
864: handshake_cmd);
865:
866: debug_log_more("trying to send handshake, xmit_cmd retval is %d\n",
867: retval);
868:
869: // XXX: stackcorruption? (see other XXX comments)
870: debug_log_more("dumping handshake_cmd after sending it\n");
871: debug_dump_cmd(handshake_cmd);
872:
873: if (retval == sizeof(gzmcp_cmd)) {
874:
875: textout(TLT_STATUS, "sent handshake");
876:
877: //net_nap = time_val_add_ms(num_ticks, 42);
878:
879: return NSM_HANDSHAKE_SENT;
880:
881: } else {
882:
883: // this is acceptable nonblocking behavior
884:
885: } // end if/else handshake xmit_cmd-ed correctly
886:
887:
888: // keep trying...
889: return NSM_CONNECTED;
890:
891: }
892:
893:
894:
895: void netmode_handshake_sent_init(void) {
896:
897: // TODO: either init textouts here, or collapse this mode into unconnected
898:
899: }
900:
901:
902:
903: network_state_mode netmode_handshake_sent_handle(void) {
904:
905: int numbytes;
906: gzmcp_cmd reflected_handshake_cmd;
907:
908: //
909: // handshake sent, listen for reciprocation
910: //
911:
912: // XXX: stackcorruption? (see other XXX comments)
913: handshake_cmd.type = GZMCP_CMD_HANDSHAKE;
914:
915: // XXX: stackcorruption? (see other XXX comments)
916: debug_log_more("dumping handshake_cmd before receiving reflected\n");
917: debug_dump_cmd(handshake_cmd);
918:
919: ////
920: //// receive the reflected handshake
921: ////
922: numbytes = recv(server_socket_fd,
923: (void *)&reflected_handshake_cmd,
924: sizeof(gzmcp_cmd),
925: 0);
926: // nonblocking, nonfatal
927: // XXX catch errno and handle server disconnecting, etc... (prob elsewhere too)
928: if (numbytes < 0) {
929: // note, this (strerror) workes, but I'm getting "no more processes here"??
930: debug_log_more("perror...%s\n",
931: strerror(errno));
932: debug_log_more("failed to receive handshake -nb-%d\n",
933: numbytes);
934: // keep trying...
935: return NSM_HANDSHAKE_SENT;
936: }
937:
938: if (numbytes != sizeof(gzmcp_cmd)) {
939: debug_log_more("failed to receive handshake -nb-%d\n",
940: numbytes);
941: // textout(TLT_DEBUG,
942: // "hndshk_recv_sz:%d",
943: // numbytes);
944:
945: // keep trying...
946: return NSM_HANDSHAKE_SENT;
947: }
948:
949: // XXX: stackcorruption? (see other XXX comments)
950: debug_log_more("dumping handshake_cmd before memcmp\n");
951: debug_dump_cmd(handshake_cmd);
952:
953: // check reflected handshake against the original
954: if (memcmp((void*)&reflected_handshake_cmd,
955: (void*)&handshake_cmd,
956: sizeof(gzmcp_cmd)) != 0 ) {
957:
958: // XXX: stackcorruption? (see other XXX comments)
959: debug_log_more("dumping handshake_cmd after memcmp\n");
960: debug_dump_cmd(handshake_cmd);
961: debug_log_more("dumping reflected_handshake_cmd after memcmp\n");
962: debug_dump_cmd(reflected_handshake_cmd);
963:
964:
965: //
966: // incorrect handshake
967: //
968: textout(TLT_STATUS,
969: "bad handshake reply");
970: textout(TLT_DEBUG,
971: "bhsr:%s:",
972: reflected_handshake_cmd.data.handshake.string);
973:
974: debug_log("bad handshake received :: %s ::\n",
975: reflected_handshake_cmd.data.handshake.string);
976:
977: // keep trying as this is not a fatal error...
978: return NSM_HANDSHAKE_SENT;
979:
980: } else {
981: //
982: // correct handshake
983: //
984: textout(TLT_STATUS, "handshake received");
985:
986: return NSM_ONLINE;
987:
988: } // end if correct handshake
989:
990: }
991:
992:
993:
994: void netmode_online_init(void) {
995:
996: // clear mode now that we are connected
997: textout(TLT_MODE, "online! :)");
998:
999: // reset socket to blocking mode
1000: // TODO: investigate using nonblocking mode for user data
1001: // TODO: investigate using udp for user data
1002: socket_set_blocking(server_socket_fd);
1003:
1004: // send initial command
1005: // TODO this should be a function (duplication with other code, abstract button...)
1006:
1007: //
1008: // create and send the new command/packet
1009: //
1010: newcmd.type = GZMCP_CMD_PRESET;
1011: newcmd.data.preset.channel = 1;
1012: newcmd.data.preset.preset = button_b_preset_num;
1013: xmit_cmd(server_socket_fd, newcmd);
1014:
1015: current_preset = button_b_preset_num;
1016:
1017: // ooh, ahh, earcandy
1018: mmEffectEx(&sounds[SFX_ONLINE]);
1019:
1020: // initialize text display
1021: textout(TLT_MODE, "cloudsession live!");
1022: textout(TLT_STATUS, "jam on!!!!!!!");
1023: textout(TLT_NETWORK_STATUS, "online");
1024:
1025: if (!user_vstrobe_enabled) {
1026: vstrobe_enabled = 0;
1027: }
1028:
1029: }
1030:
1031:
1032:
1033: network_state_mode netmode_online_handle(void) {
1034: // nothing to do while ONLINE
1035: return NSM_ONLINE;
1036: }
1037:
1038:
1039: /* TEMPLATE NETWORK STATE MODE FUNCTION PAIR
1040:
1041: void netmode_xxx_init(void) {
1042:
1043:
1044: }
1045:
1046:
1047:
1048: network_state_mode netmode_xxx_handle(void) {
1049: // nothing to do while XXX
1050: return NSM_XXX;
1051: }
1052:
1053:
1054: END TEMPLATE NETWORK STATE MODE FUNCTION PAIR */
1055:
1056:
1057:
1058: network_state_mode gzmcpc_net_next_state(network_state_mode current) {
1059:
1060: network_state_mode next_state;
1061:
1062:
1063: debug_log_more("net_next_state: %d\n", current);
1064:
1065: // do nothing interesting by default
1066: next_state = current;
1067:
1068: // check for net_nap throttling
1069: // i.e. "if the current time is smaller than the nap marker, do nothing"
1070: if (time_val_compare(net_nap, num_ticks) < 0) {
1071: debug_log_more("net napping %d %d...\n",
1072: num_ticks.s, num_ticks.ms);
1073: return current;
1074: }
1075:
1076: debug_log_more("not net napping...\n");
1077:
1078: //
1079: // handle all possible present states
1080: //
1081: // TODO: could convert this to an array of funcpointers like I do for main mode
1082: // (i.e. no code redundancy)
1083: switch (current) {
1084:
1085: case NSM_START:
1086: // START is somewhat bogus
1087:
1088: // jump strait to WSCANNING
1089: return NSM_WSCANNING;
1090:
1091: break;
1092:
1093: case NSM_OFFLINE:
1094:
1095: if (!nsm_init) {
1096: netmode_offline_init();
1097: nsm_init = 1;
1098: }
1099:
1100: return netmode_offline_handle();
1101:
1102: break;
1103:
1104: case NSM_WSCANNING:
1105:
1106: if (!nsm_init) {
1107: netmode_wscanning_init();
1108: nsm_init = 1;
1109: }
1110:
1111: return netmode_wscanning_handle();
1112:
1113: break;
1114:
1115: case NSM_WASSOCIATING:
1116:
1117: if (!nsm_init) {
1118: netmode_wassociating_init();
1119: nsm_init = 1;
1120: }
1121:
1122: return netmode_wassociating_handle();
1123:
1124: break;
1125:
1126: case NSM_BCAST_LISTEN:
1127:
1128: if (!nsm_init) {
1129: netmode_bcast_listen_init();
1130: nsm_init = 1;
1131: }
1132:
1133: return netmode_bcast_listen_handle();
1134:
1135: break;
1136:
1137: case NSM_UNCONNECTED:
1138:
1139: if (!nsm_init) {
1140: netmode_unconnected_init();
1141: nsm_init = 1;
1142: }
1143:
1144: return netmode_unconnected_handle();
1145:
1146: break;
1147:
1148: case NSM_CONNECTED:
1149:
1150: if (!nsm_init) {
1151: netmode_connected_init();
1152: nsm_init = 1;
1153: }
1154:
1155: return netmode_connected_handle();
1156:
1157: break;
1158:
1159: case NSM_HANDSHAKE_SENT:
1160:
1161: if (!nsm_init) {
1162: netmode_handshake_sent_init();
1163: nsm_init = 1;
1164: }
1165:
1166: return netmode_handshake_sent_handle();
1167:
1168: break;
1169:
1170: case NSM_ONLINE:
1171:
1172: if (!nsm_init) {
1173: netmode_online_init();
1174: nsm_init = 1;
1175: }
1176:
1177: return netmode_online_handle();
1178:
1179: break;
1180:
1181: } // end switch (current) // current state
1182:
1183: // default to same state, though code should never reach here
1184: return next_state;
1185:
1186: } // end gzmcpc_net_next_state()
1187:
1188: