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: