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: ##
22: ## gzmcpc: gzmcp daemon
23: ##
24: #############################################################################
25: ##
26: ## Copyright 2007-2009 Douglas McClendon <dmc AT filteredperception DOT org>
27: ##
28: #############################################################################
29: #############################################################################
30: #
31: #
32: #
33: # usage: gzmcpd
34: #
35: # The Guitar-ZyX Master Control Program Daemon listens on the localhost at
36: # the tcp port specified by XXX GZMCP_PORT or 24642 for a gzmcp-client to
37: # start sending a command stream which will be processed appropriately.
38: # A broadcast token is sent every 7 seconds on udp port 24642 to announce
39: # our presence to any locally attached networks.
40: #
41: */
42:
43:
44:
45: #include <unistd.h>
46:
47: #include <sys/types.h>
48:
49: #include <sys/stat.h>
50:
51: #include <sys/wait.h>
52:
53: #include <stdio.h>
54:
55: #include <stdlib.h>
56:
57: #include <stdarg.h>
58:
59: #include <errno.h>
60: #include <limits.h>
61:
62: #include <string.h>
63:
64: #include <sys/socket.h>
65:
66: #include <netinet/in.h>
67:
68: #include <arpa/inet.h>
69:
70: #include <netdb.h>
71:
72: #include <ifaddrs.h>
73:
74: #include <math.h>
75:
76: #include <alsa/asoundlib.h>
77:
78: #include <signal.h>
79:
80: #include "server.h"
81:
82:
83:
84:
85: char prog_name[PATH_MAXLEN + 1];
86: char prog_dir[PATH_MAXLEN + 1];
87:
88: int cmd_socket_fd;
89:
90: long bcast_portnum;
91: long cmd_portnum;
92:
93: snd_seq_t *mainport;
94:
95: int alsa_output_port;
96:
97: char port_name[256];
98:
99: int user_exit;
100:
101: int user_count = 0;
102:
103:
104:
105: int
106: main(int argc, char *argv[]) {
107:
108: //
109: // derived global 'constants'
110: //
111: dirname(prog_dir, argv[0]);
112: basename(prog_name, argv[0]);
113:
114: //
115: // Hello User
116: //
117: fprintf(stdout, "\n\n\n");
118: fprintf(stdout,
119: "========================================\n");
120: fprintf(stdout,
121: "Guitar-ZyX Master Control Program Server\n");
122: fprintf(stdout,
123: " - v2k9.dev - (c)2009 Douglas McClendon\n");
124: fprintf(stdout,
125: "========================================\n");
126: fprintf(stdout, "\n\n\n");
127:
128: //
129: // parse commandline
130: //
131: // TODO: add better getopt-ish, with --verbose...
132: if (argc > 2) {
133:
134: // too many args: tell the user how to use
135: usage();
136:
137: } else if (argc == 2) {
138:
139: // get the user specified port number from the command line arg
140: cmd_portnum = ec_strtol(argv[1]);
141: bcast_portnum = ec_strtol(argv[1]);
142:
143:
144: } else {
145:
146: // or use defaults
147: cmd_portnum = GZMCP_DEF_TCP_PORT;
148: bcast_portnum = GZMCP_DEF_UDP_PORT;
149:
150: }
151:
152: // start midi output port
153: midi_init();
154:
155: // start listening for and taking care of clients
156: network_init();
157:
158: // broadcast an availability message to locally attached networks
159: broadcast();
160:
161: // configure_reaper: set up child process signal handler
162: configure_reaper();
163:
164: // TODO: no supported exit method exists yet
165: user_exit = 0;
166:
167: while (!user_exit) {
168:
169: get_and_handle_a_connection();
170:
171: } // end main loop ending on as yet specd userexit
172:
173: // stop midi output port
174: midi_shutdown();
175:
176: // release network resources
177: network_shutdown();
178:
179: // be seeing you...
180: return(0);
181: }
182:
183:
184:
185:
186: void usage(void) {
187: fprintf(stderr, "\n\nusage: gzmcpd [<port number> default=24642]\n\n\n");
188: exit(1);
189: }
190:
191:
192:
193: long ec_strtol(char *str) {
194:
195: char *endptr;
196: long val;
197:
198: // error check strtol
199: // note: code verbatim from man strtol
200: // To distinguish success/failure after call
201: errno = 0;
202: val = strtol(str, &endptr, 10);
203:
204: // Check for various possible errors
205: if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
206: || (errno != 0 && val == 0)) {
207: perror("strtol");
208: exit(EXIT_FAILURE);
209: }
210:
211: if (endptr == str) {
212: fprintf(stderr, "No digits were found\n");
213: exit(EXIT_FAILURE);
214: }
215:
216: // If we got here, strtol() successfully parsed a number
217: return val;
218: }
219:
220:
221:
222: void basename(char *dest, char *path) {
223:
224: char *new_result;
225: char *last_result;
226:
227:
228: // look for the last '/'
229: last_result = path;
230: while ((new_result = strstr(last_result, "/")) != NULL) {
231: last_result = new_result + 1;
232: }
233:
234: // copy to dest, everything after the last '/'
235: strncpy(dest, last_result, PATH_MAXLEN);
236:
237: // guarantee null terminated destination string
238: dest[PATH_MAXLEN] = 0;
239:
240: return;
241: }
242:
243:
244:
245: void dirname(char *dest, char *path) {
246:
247: char *new_result;
248: char *last_result;
249: int dirname_length;
250:
251:
252: // look for the last '/'
253: last_result = path;
254: while ((new_result = strstr(last_result, "/")) != NULL) {
255: last_result = new_result + 1;
256: }
257:
258: // if no / found, dirname is
259: if (last_result == path) {
260: // edunote: normally I go with n of strlen(string), but this from the
261: // strncpy manpage worries me-
262: // "If there is no terminating null byte in the first n characters of
263: // src, strncpy() produces an unterminated string in dest."
264: strncpy(dest, ".", 2);
265: return;
266: }
267:
268: // calculdate the length of the result we want
269: dirname_length = strlen(path) - strlen(last_result) - 1;
270:
271: if (dirname_length > PATH_MAXLEN) {
272: die("dirname() result greater than PATH_MAXLEN - %d\n",
273: PATH_MAXLEN);
274: }
275:
276: // copy to dest, everything up to last '/'
277: strncpy(dest,
278: path,
279: dirname_length);
280:
281: // guarantee null terminated destination string
282: dest[PATH_MAXLEN] = 0;
283:
284: return;
285: }
286:
287:
288: void status(const char *msg_fmt, ...) {
289:
290: char print_msg[STATUS_MSG_MAXLEN + 1];
291:
292: va_list msg_arg;
293:
294:
295: va_start(msg_arg, msg_fmt);
296: vsnprintf(print_msg,
297: STATUS_MSG_MAXLEN,
298: msg_fmt,
299: msg_arg);
300: va_end(msg_arg);
301:
302: fprintf(stdout,
303: "%s: %s\n",
304: prog_name,
305: print_msg);
306: }
307:
308:
309:
310: void die(const char *msg_fmt, ...) {
311:
312: char print_msg[STATUS_MSG_MAXLEN + 1];
313:
314: va_list msg_arg;
315:
316:
317: va_start(msg_arg, msg_fmt);
318: vsnprintf(print_msg,
319: STATUS_MSG_MAXLEN,
320: msg_fmt,
321: msg_arg);
322: va_end(msg_arg);
323:
324: fprintf(stdout,
325: "%s: FATAL ERROR: %s\n",
326: prog_name,
327: print_msg);
328: exit(1);
329:
330: }
331:
332:
333:
334: void midi_init(void) {
335:
336: int retval;
337:
338: //
339: // alsa init
340: //
341: retval = snd_seq_open(&mainport,
342: "default",
343: SND_SEQ_OPEN_OUTPUT,
344: 0);
345:
346: if (retval < 0) {
347: printf("error starting alsa sequencer client\n");
348: }
349:
350: snd_seq_set_client_name (mainport, "gzmcp");
351:
352: snd_config_update_free_global();
353:
354: // create alsa sequencer client
355: sprintf(port_name, "gzmcp output");
356: alsa_output_port = \
357: snd_seq_create_simple_port(
358: mainport,
359: port_name,
360: SND_SEQ_PORT_CAP_READ |
361: SND_SEQ_PORT_CAP_SUBS_READ,
362: SND_SEQ_PORT_TYPE_APPLICATION
363: );
364:
365: //
366: // end alsa init
367: //
368: }
369:
370:
371: void midi_shutdown(void) {
372:
373: // alsa cleanup
374: snd_seq_close(mainport);
375: }
376:
377:
378:
379: void network_init(void) {
380:
381: // server net address
382: // for standard socket address structure
383: struct sockaddr_in server_address;
384:
385: // for setsockopt
386: int optval;
387:
388:
389: // open an internet stream socket for the server
390: cmd_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
391: if (cmd_socket_fd < 0) {
392: perror("socket()");
393: die("failed to open server socket");
394: }
395:
396: // I don't like waiting 3 minutes to restart if there is a crash
397: // (i.e. netstat -auntp | grep <PORTNUM> yields FIN_WAIT1),
398: // thus use SO_REUSEADDR
399: optval = 1;
400: if (setsockopt(cmd_socket_fd,
401: SOL_SOCKET,
402: SO_REUSEADDR,
403: &optval, sizeof(optval)) < 0) {
404: perror("setsockopt()");
405: die("failed to set socket options\n");
406: }
407:
408: // initialize/zero-out the server_address structure
409: memset((char *) &server_address, 0, sizeof(server_address));
410:
411: // configure the server_address structure for our purposes
412: // INET, vs e.g. UNIX for local non network sockets
413: server_address.sin_family = AF_INET;
414:
415: // INADDR_ANY here means to bind to any/all ip addresses of this host
416: server_address.sin_addr.s_addr = htonl(INADDR_ANY);
417:
418: // configure port using correct network(htons) format
419: server_address.sin_port = htons(cmd_portnum);
420:
421: // try to bind to the socket (this is the main gzmcpd test)
422: if (bind(cmd_socket_fd, (struct sockaddr *) &server_address,
423: sizeof(server_address)) < 0) {
424: perror("bind()");
425: die("failed to bind to server socket");
426: }
427:
428: // listen for connections
429: if (listen(cmd_socket_fd,1) < 0) {
430: perror("listen()");
431: die("failed to listen to server socket");
432: }
433: }
434:
435:
436:
437: void bcast_run_beacon(void) {
438:
439: // return values
440: int rv;
441:
442: // file descriptor for the server brodcast udp socket
443: int bcast_socket_fd;
444:
445: struct sockaddr_in broadcast_address;
446: int bytes_sent;
447: // for setsockopt
448: int optval;
449:
450: long magic_cookie;
451: char beacon_msg[GZMCP_BEACON_MSG_MAXLEN + 1];
452:
453: // for crafting broadcast udp packets for all local nets
454: struct ifaddrs *interface_addresses;
455: struct ifaddrs *ia_ptr;
456:
457:
458: // put the cookie where it can be sizeof()d
459: magic_cookie = (long)GZMCP_DEF_MAGIC_COOKIE;
460:
461: // create the broadcast udp socket
462: // - AF_INET means ipv4, vs AF_INET6 vs AF_UNIX/AF_LOCAL
463: // - SOCK_DGRAM means udp, vs SOCK_STREAM for tcp
464: // - 0 means default protocol type for family
465: bcast_socket_fd = socket(AF_INET,
466: SOCK_DGRAM,
467: 0);
468: if (bcast_socket_fd < 0) {
469: perror("socket()");
470: die("couldn't create broadcast socket");
471: }
472:
473: // enable broadcast
474: optval = 1;
475: if (setsockopt(bcast_socket_fd,
476: SOL_SOCKET,
477: SO_BROADCAST,
478: &optval, sizeof(optval)) < 0) {
479: perror("setsockopt()");
480: die("failed to set broadcast socket options\n");
481: }
482:
483:
484: // create a destination address structure, initialize...
485: memset(&broadcast_address, 0, sizeof(broadcast_address));
486:
487: // configure the broadcast_address structure for our purposes
488: // INET, vs e.g. UNIX for local non network sockets
489: broadcast_address.sin_family = AF_INET;
490: broadcast_address.sin_port = htons(bcast_portnum);
491: // note: saving the .sin_addr for just prior to sendto
492:
493: // note: For now I'm going on my interpretation of this-
494: // http://www.faqs.org/rfcs/rfc947.html
495: // which very strongly implies that broadcasting
496: // on the internet is restricted to the physical
497: // networks connected to by the host. I.e. that one
498: // can count on routers, even non-nat ones, not forwarding
499: // broadcast udp traffic.
500: //
501: // note additionally: This says that 255.255.255.255 used
502: // after enabling broadcast socket opt, is the local subnet,
503: // while e.g. 192.168.1.255 is a 'directed broadcast address',
504: // implying you can do directed broadcasts.
505:
506: //
507: // prepare beacon message, i.e. magic cookie + hostname
508: //
509: // the beacon message starts with the magic cookie
510: memcpy(beacon_msg,
511: &magic_cookie,
512: sizeof(magic_cookie));
513: // and ends with the hostname
514: rv = gethostname(beacon_msg + sizeof(GZMCP_DEF_MAGIC_COOKIE),
515: GZMCP_BEACON_MSG_MAXLEN - sizeof(GZMCP_DEF_MAGIC_COOKIE));
516: // ensure null termination
517: beacon_msg[GZMCP_BEACON_MSG_MAXLEN] = 0;
518:
519: if (rv < 0) {
520: perror("gethostname()");
521: die("could not create beacon message\n");
522: }
523:
524: // note: ctrl-c(KILL/BRK?) to the parent does get the broadcasting child killed
525: while(1) {
526:
527: // note: the below link combined with other example code I saw convinces
528: // me that this is indeed correct, i.e. the sock_addr* casting of
529: // a sock_addr_in*.
530: // http://www.linuxquestions.org/questions/programming-9 ---
531: // /sockaddrin-and-sockaddr-176787/
532: //
533:
534: // note: it is not this simple with multiple interfaces
535: // http://www.developerweb.net/forum/showthread.php?t=5085
536: /*
537: broadcast_address.sin_addr.s_addr = htonl(INADDR_BROADCAST);
538: bytes_sent = sendto(bcast_socket_fd,
539: beacon_msg,
540: strlen(beacon_msg),
541: 0,
542: (struct sockaddr *)&broadcast_address,
543: sizeof(broadcast_address));
544: if (bytes_sent < 0) {
545: // udp makes no guarantees
546: // perror("sendto()");
547: // status("could not send message\n");
548: }
549: */
550:
551: // send one broadcast packet for each locally connected interface
552: if (getifaddrs(&interface_addresses) == 0) {
553:
554: ia_ptr = interface_addresses;
555: while (ia_ptr) {
556:
557: if ((ia_ptr->ifa_addr)->sa_family == AF_INET) {
558:
559: // printf("sending to address ... %s\n",
560: // inet_ntoa(((struct sockaddr_in *)(ia_ptr->ifa_dstaddr))->sin_addr));
561:
562: broadcast_address.sin_addr.s_addr = ((struct sockaddr_in *)(ia_ptr->ifa_dstaddr))->sin_addr.s_addr;
563: bytes_sent = sendto(bcast_socket_fd,
564: beacon_msg,
565: strlen(beacon_msg),
566: 0,
567: (struct sockaddr *)&broadcast_address,
568: sizeof(broadcast_address));
569: if (bytes_sent < 0) {
570: // udp makes no guarantees
571: // perror("sendto()");
572: // status("could not send message\n");
573: }
574:
575: } // end if (ia_ptr->ifa_addr->a_family == AF_INET)
576:
577: ia_ptr = ia_ptr->ifa_next;
578:
579: } // end while (ia_ptr)
580:
581: freeifaddrs(interface_addresses);
582:
583: } // end if getifaddrs
584:
585: usleep(GZMCP_BEACON_PERIOD_USEC);
586: } // end while(1)
587:
588: }
589:
590:
591: void bcast_run_beacon_and_exit(void) {
592:
593: // pid of the client child process
594: pid_t child_pid = -1;
595:
596:
597: //
598: // fork
599: //
600:
601: child_pid = fork();
602:
603: if (child_pid < 0) {
604:
605: perror("fork()");
606: die("forking error");
607:
608: } else if (child_pid != 0) {
609:
610: //
611: // parent
612: //
613:
614: // return, reaper handler will take care of waiting for children
615:
616: } else {
617:
618: //
619: // child
620: //
621:
622: bcast_run_beacon();
623:
624: }
625:
626: }
627:
628:
629: void broadcast(void) {
630:
631: // forking: pid of the broadcaster child process
632: pid_t bcast_child_pid = -1;
633:
634:
635: //
636: // fork
637: //
638:
639: bcast_child_pid = fork();
640:
641: if (bcast_child_pid < 0) {
642:
643: perror("ERROR: forking error");
644: die("forking error");
645:
646: } else if (bcast_child_pid != 0) {
647:
648: //
649: // parent
650: //
651:
652: pid_t some_child_pid = -1;
653:
654: // make sure the child process exits
655: some_child_pid = wait(NULL);
656:
657: if (bcast_child_pid != some_child_pid) {
658:
659: status("debug: bcast_child_pid was %d, some_child_pid was %d\n",
660: bcast_child_pid,
661: some_child_pid);
662: die("problem waiting for broadcast client child process to terminate\n");
663:
664: } else {
665:
666: exit(0);
667:
668: }
669:
670: } else {
671:
672: //
673: // child
674: //
675:
676: bcast_run_beacon_and_exit();
677:
678: } // end fork handling
679:
680:
681: }
682:
683:
684:
685: void network_shutdown(void) {
686:
687: shutdown(cmd_socket_fd, SHUT_RDWR);
688:
689: }
690:
691:
692:
693: int wait_for_connection(void) {
694:
695: int sockfd = -1;
696:
697: // for standard socket address structure (of the accepted test connection)
698: // (note: data returned by accept is not used by gzmcpd subsequently)
699: int client_length;
700: struct sockaddr_in client_address;
701:
702: // client_length and client address are required for the accept syscall,
703: // but are not actually used subsequently by gzmcpd. Presumably they
704: // would be used if we cared about the origin of the incoming connection.
705: // (i.e. if we were getting nmap-ed at this precise time, we would see
706: // a 'corrupt' test message. An improvement, would be to discard
707: // connections not from the localhost. But despite the verboseness of
708: // this code as a personal reference, that is more than I care about now).
709: client_length = sizeof(client_address);
710:
711: // accept the connection and process it
712: sockfd = accept(cmd_socket_fd,
713: (struct sockaddr *)&client_address,
714: (socklen_t *)&client_length);
715:
716: if (sockfd < 0) {
717:
718: // just fail this connection
719: perror("accept()");
720: status("failed to accept on server socket");
721:
722: } else {
723:
724: status("accepted connection from client: %s\n\n",
725: inet_ntoa(client_address.sin_addr));
726: }
727:
728: fflush(stdout);
729: fflush(stderr);
730:
731: return sockfd;
732: }
733:
734:
735:
736: void handle_cmd_handshake(int client_socket_fd,
737: gzmcp_cmd cmd) {
738:
739: // for read/write return values
740: int bytes_written;
741:
742:
743: debug_more("debug: processing a handshake command...");
744: status("processing a handshake command...");
745:
746: bytes_written = write(client_socket_fd,
747: (void *)&cmd,
748: sizeof(gzmcp_cmd));
749:
750: if (bytes_written < 0) {
751: perror("write()");
752: status("warning: failed to write to server socket to return handshake");
753: } else if (bytes_written < sizeof(gzmcp_cmd)) {
754: status("BUG/FIXME: wrote partial handshake\n");
755: // XXX TODO: send the rest
756: } else {
757: debug_more("debug: wrote complete handshake\n");
758: status("debug: wrote complete handshake\n");
759: }
760:
761: }
762:
763:
764:
765: void handle_cmd_getupdate(int client_socket_fd) {
766:
767: unsigned char magic[2];
768:
769: // for read/write return values
770: int bytes_written;
771: int rv;
772:
773: // for update file size...
774: struct stat stat_buf;
775:
776: FILE *update_file;
777:
778: // for update file send loop
779: int bytes_to_write;
780: int chunk_bytes_to_write;
781: unsigned char write_buf[UPD_WR_BUF_SZ];
782:
783: char update_filename[PATH_MAXLEN + 1];
784:
785: //edunote: ref to C99 standard that uint32_t is preferred: (over u_int32_t)
786: // http://www.oreillynet.com/pub/a/network/2003/10/07/michael_barr.html
787: uint32_t update_filesize = -1;
788: // effectively a return packet type
789: // todo: move to protocol or otherwise improve
790: uint32_t return_data[3];
791:
792: // XXX: hardcoded magic
793:
794: magic[0] = 42;
795: magic[1] = 24;
796:
797: debug_more("debug: processing a getupdate command...");
798:
799: status("checking for update");
800:
801: //
802: // get filesize of update file
803: //
804:
805: // first create full pathname to neighbor update file
806: snprintf(update_filename,
807: PATH_MAXLEN,
808: "%s/%s",
809: prog_dir,
810: UPDATE_FILENAME);
811: rv = stat(update_filename, &stat_buf);
812: if (rv != 0) {
813: // finally try full pathname to systemwide update file
814: snprintf(update_filename,
815: PATH_MAXLEN,
816: "%s/%s",
817: VARLIBDIR,
818: UPDATE_FILENAME);
819: rv = stat(update_filename, &stat_buf);
820: if (rv != 0) {
821: status("no update file available, won't send anything to client");
822: return;
823: }
824: }
825:
826: update_filesize = (int)stat_buf.st_size;
827:
828: update_file = fopen(update_filename, "r");
829: if (update_file == NULL) {
830: die("failed to open update file %s for reading in order to send to client\n",
831: update_filename);
832: }
833:
834: status("update file size is %d bytes\n",
835: update_filesize);
836:
837: status("sending return magic");
838:
839: // send magic
840: bytes_written = write(client_socket_fd,
841: (void *)magic,
842: 2);
843:
844: if (bytes_written < 0) {
845: perror("write()");
846: status("warning: failed to write to server socket to return magic");
847: } else if (bytes_written < 2) {
848: status("BUG/FIXME: wrote partial return magic\n");
849: // XXX TODO: send the rest
850: } else {
851: debug_more("debug: wrote complete return magic\n");
852: }
853:
854: status("sending update signature metadata");
855:
856: return_data[0] = update_filesize;
857: // no parity/hash/xor/signature yet
858: return_data[1] = 0;
859: // no data sampling yet
860: return_data[2] = 0;
861:
862: // 4 bytes per int32_t, 3 values in return_data[]
863: bytes_written = write(client_socket_fd,
864: (void *)return_data,
865: 4 * 3);
866:
867: if (bytes_written < 0) {
868: perror("write()");
869: status("warning: failed to write to server socket to return signature");
870: } else if (bytes_written < (4 * 3)) {
871: status("BUG/FIXME: wrote partial return signature\n");
872: // XXX TODO: send the rest
873: } else {
874: debug_more("debug: wrote complete return magic\n");
875: }
876:
877: status("sending update");
878:
879: // write up to 1kb at a time until done
880: bytes_to_write = update_filesize;
881:
882: while (bytes_to_write) {
883:
884: if (bytes_to_write < UPD_WR_BUF_SZ) {
885: chunk_bytes_to_write = bytes_to_write;
886: } else {
887: chunk_bytes_to_write = UPD_WR_BUF_SZ;
888: }
889:
890: // no error checking here (yet)
891: fread(write_buf, 1, chunk_bytes_to_write, update_file);
892:
893: while (chunk_bytes_to_write) {
894:
895: bytes_written = write(client_socket_fd,
896: (void *)write_buf,
897: chunk_bytes_to_write);
898:
899: if (bytes_written < 0) {
900: perror("write()");
901: die("failed to write to server socket to return update file data");
902: } else if (bytes_written < chunk_bytes_to_write) {
903: status("note: wrote partial update file data chunk: %d/%d bytes\n",
904: bytes_written,
905: chunk_bytes_to_write);
906: }
907:
908: chunk_bytes_to_write -= bytes_written;
909:
910: } // end while (chunk_bytes_to_write)
911:
912: if (bytes_to_write < UPD_WR_BUF_SZ) {
913: bytes_to_write = 0;
914: } else {
915: bytes_to_write -= UPD_WR_BUF_SZ;
916: }
917:
918: } // end while (bytes_to_write)
919:
920: }
921:
922:
923:
924: void connection_handler(int client_socket_fd) {
925:
926: // simple data buffers for use with the socket
927:
928: // the buffer to store newly read commands from the network pipe
929: // the +1 is to support storage for a partially read command
930: unsigned char cmd_read_buf[(CMD_BUF_SIZE + 1) * sizeof(gzmcp_cmd)];
931: int cmd_data_size;
932:
933: // a pointer to walk through the read buffer
934: void *next_cmd;
935:
936: // no goto here
937: int client_done;
938:
939: // for read/write return values
940: int bytes_read;
941:
942: // command structure for incoming commands
943: gzmcp_cmd cmd;
944:
945: // pid of the client child process
946: pid_t child_pid = -1;
947:
948: // a midi event to send to a midi receiver
949: snd_seq_event_t midi_event;
950:
951:
952: //
953: // fork
954: //
955:
956: child_pid = fork();
957:
958: if (child_pid < 0) {
959:
960: perror("fork()");
961: die("forking error");
962:
963: } else if (child_pid != 0) {
964:
965: //
966: // parent
967: //
968:
969: close(client_socket_fd);
970:
971: // return, reaper handler will take care of waiting for children
972:
973: } else {
974:
975: //
976: // child
977: //
978:
979: // initialize the reception buffers
980: memset(cmd_read_buf, 0, (CMD_BUF_SIZE + 1) * sizeof(gzmcp_cmd));
981: cmd_data_size = 0;
982:
983: // begin command processing loop
984: client_done = 0;
985: while (!client_done) {
986:
987: //
988: // read command message
989: //
990:
991: // read into the buffer, offset by a possible unprocessed partial command
992: bytes_read = read(client_socket_fd,
993: cmd_read_buf + cmd_data_size,
994: CMD_BUF_SIZE * sizeof(gzmcp_cmd));
995: if (bytes_read < 0) {
996: perror("read()");
997: status("error: failed to read from server socket");
998: status("client disconnected, user count is now %d\n", user_count);
999: status("the reaper should be knocking right about now...\n");
1000: client_done = 1;
1001: return;
1002: } else {
1003: // debug/info
1004: if (bytes_read != 0) {
1005: debug_more("debug: received %d bytes of new command data\n", bytes_read);
1006: }
1007: // integrate the partial command with the newly read stream
1008: cmd_data_size += bytes_read;
1009: }
1010:
1011:
1012: //
1013: // process one or more commands
1014: //
1015:
1016: // start at the beginning
1017: next_cmd = cmd_read_buf;
1018:
1019: while (cmd_data_size >= sizeof(gzmcp_cmd)) {
1020:
1021: debug_more("debug: processing a command...");
1022:
1023: // extract the first remaining command
1024: memcpy((void *)&cmd,
1025: next_cmd,
1026: sizeof(gzmcp_cmd));
1027: // increment the next command
1028: next_cmd += sizeof(gzmcp_cmd);
1029: // decrement the amount of data to be processed
1030: cmd_data_size -= sizeof(gzmcp_cmd);
1031:
1032: debug_more("debug: command type is %08x",
1033: cmd.type);
1034:
1035: //
1036: // check for command type and handle appropriately
1037: //
1038:
1039: if (cmd.type == GZMCP_CMD_HANDSHAKE) {
1040: handle_cmd_handshake(client_socket_fd,
1041: cmd);
1042: }
1043:
1044: if (cmd.type == GZMCP_CMD_GETUPDATE) {
1045: handle_cmd_getupdate(client_socket_fd);
1046: }
1047:
1048: // check for set-preset
1049: if (cmd.type == GZMCP_CMD_PRESET) {
1050:
1051: status("changing to preset %d on channel %d\n",
1052: cmd.data.preset.preset,
1053: cmd.data.preset.channel);
1054:
1055: //
1056: // craft and send a midi event
1057: //
1058:
1059: // init structure
1060: snd_seq_ev_clear(&midi_event);
1061: // set things up ...
1062: snd_seq_ev_set_pgmchange(&midi_event,
1063: cmd.data.preset.channel - 1,
1064: cmd.data.preset.preset);
1065: snd_seq_ev_set_subs(&midi_event);
1066: snd_seq_ev_set_direct(&midi_event);
1067: // .. and fire off the midi event
1068: snd_seq_event_output_direct(mainport,
1069: &midi_event);
1070:
1071:
1072: } // end if preset
1073:
1074: // check for set-parameter
1075: if (cmd.type == GZMCP_CMD_PARAMETER) {
1076:
1077: status("changing parameter %d to value %d on channel %d\n",
1078: cmd.data.parameter.parameter,
1079: cmd.data.parameter.value,
1080: cmd.data.parameter.channel);
1081:
1082: //
1083: // craft and send a midi event
1084: //
1085:
1086: // new structure
1087: snd_seq_event_t midi_event;
1088: // init structure
1089: snd_seq_ev_clear(&midi_event);
1090: // set things up ...
1091: snd_seq_ev_set_controller(&midi_event,
1092: cmd.data.parameter.channel - 1,
1093: cmd.data.parameter.parameter,
1094: cmd.data.parameter.value);
1095: snd_seq_ev_set_subs(&midi_event);
1096: snd_seq_ev_set_direct(&midi_event);
1097: // ... and fire it off
1098: snd_seq_event_output_direct(mainport,
1099: &midi_event);
1100:
1101: } // end if preset
1102:
1103: debug_more("debug: done processing command...");
1104:
1105: } // end while complete commands are available to process
1106:
1107: // store any remaining partial command at the beginning of the buffer
1108: if (cmd_data_size) {
1109: memcpy(cmd_read_buf,
1110: next_cmd,
1111: cmd_data_size);
1112: }
1113:
1114: } // end while client is not done (reading from network for new commands)
1115:
1116: } // end child of the fork
1117:
1118: } // end connection_handler()
1119:
1120:
1121:
1122: void get_and_handle_a_connection(void) {
1123:
1124: // file descriptor for the client connection socket
1125: int client_socket_fd = -1;
1126:
1127: // forking: pid of the client child process
1128: pid_t child_pid = -1;
1129:
1130: // for return value of the final wait(ing for the child process to exit)
1131: pid_t some_child_pid = -1;
1132:
1133:
1134: // get a connection
1135: client_socket_fd = wait_for_connection();
1136:
1137: // handle it by spawing a server process with fork
1138: if (client_socket_fd != -1) {
1139:
1140: //
1141: // fork
1142: //
1143:
1144: child_pid = fork();
1145:
1146: if (child_pid < 0) {
1147:
1148: perror("ERROR: forking error");
1149: die("forking error");
1150:
1151: } else if (child_pid != 0) {
1152:
1153: //
1154: // parent
1155: //
1156:
1157: // close child socket file descriptor
1158: close(client_socket_fd);
1159:
1160: // make sure the child process exits
1161: some_child_pid = wait(NULL);
1162:
1163: if (child_pid != some_child_pid) {
1164:
1165: die("problem waiting for client child process to terminate\ndebug: child_pid was %d, some_child_pid was %d\n",
1166: child_pid,
1167: some_child_pid);
1168:
1169: } else {
1170:
1171: exit(0);
1172:
1173: }
1174:
1175: } else {
1176:
1177: //
1178: // child
1179: //
1180:
1181: // close parent server socket file descriptor
1182: // XXX: nowork?
1183: // close(cmd_socket_fd);
1184:
1185: connection_handler(client_socket_fd);
1186:
1187: } // end fork handling
1188:
1189: } // end if valid client_socket_fd
1190:
1191: }
1192:
1193:
1194: void configure_reaper(void) {
1195:
1196: // signal handler action type
1197: struct sigaction sig_action;
1198:
1199:
1200: // set signal handler
1201: sig_action.sa_handler = (__sighandler_t)offspring_reaper;
1202:
1203: // mask all signals
1204: if (sigfillset(&sig_action.sa_mask) < 0) {
1205: perror("sigfillset()");
1206: die("sigfillset failed");
1207: }
1208:
1209: // this means that interrupted system calls will be restarted
1210: sig_action.sa_flags = SA_RESTART;
1211:
1212: // set signal disposition for child-termination signals
1213: if (sigaction(SIGCHLD, &sig_action, 0) < 0) {
1214: perror("sigaction()");
1215: die("sigaction failed");
1216: }
1217:
1218: }
1219:
1220:
1221:
1222: void offspring_reaper(void) {
1223:
1224: pid_t pid;
1225:
1226: // wait on the next child process to exit
1227: while ( ( pid = waitpid((pid_t)-1, NULL, WNOHANG) ) > 0 ) {
1228:
1229: // decrement the global user_count
1230: user_count--;
1231:
1232: status("childreaper: user count is now %d\n",
1233: user_count);
1234: }
1235:
1236: }
1237: