home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / x / xhearts.zip / HEARTS_D.C < prev    next >
C/C++ Source or Header  |  1992-01-07  |  10KB  |  429 lines

  1. /*
  2.  * hearts_dist - distributor for hearts
  3.  *
  4.  * Keeps track of games in progress and allows new players to select which
  5.  * game to join or start a new game.
  6.  *
  7.  *
  8.  *    Commands to hearts player:
  9.  *  tn        Following info regards table n (n is unique identifier).
  10.  *  hn        Now playing hand n.
  11.  *  rn        Now playing round n.
  12.  *  pn<name>    Player n is <name>.
  13.  *
  14.  *  xn        Table n has exited (game over).
  15.  *  g        Get table number to join.
  16.  *  cn        Connect to dealer on port n.
  17.  *
  18.  *    Commands from hearts player:
  19.  *  jn        Join table n.
  20.  *  n        Start new game.
  21.  *
  22.  *    Commands to dealer:
  23.  * none yet?!?
  24.  *
  25.  *    Commands from dealer:
  26.  *  hn        Now playing hand n.
  27.  *  rn        Now playing round n.
  28.  *  pn<name>    Player n is <name>.
  29.  *
  30.  */
  31.  
  32. #include "misc.h"
  33. #include "defs.h"
  34. #include "local.h"
  35. #include <string.h>
  36. #include <malloc.h>
  37.  
  38. typedef struct table *table_ptr;
  39.  
  40. struct table {
  41.     table_ptr    next_table;        /* Points to next table entry */
  42.     int        table_id;        /* Unique identifier */
  43.     char        player_name[4][9];    /* Name of players at table */
  44.     int        hand;            /* Current dealer hand (1..4) */
  45.     int        round;            /* Current round (1..13) */
  46.     int        port_num;        /* Port # assigned */
  47.     int        socket;            /* File descriptor for dealer */
  48.     int        pid;            /* Process id for dealer */
  49. };
  50.  
  51. typedef struct empty_table *empty_ptr;
  52.  
  53. struct empty_table {
  54.     empty_ptr    next_empty;
  55.     int        port_num;        /* Available port # */
  56. };
  57.  
  58. typedef struct new_comer *new_ptr;
  59.  
  60. struct new_comer {
  61.     new_ptr        next_new_comer;
  62.     int        socket;            /* File descriptor */
  63. };
  64.  
  65. table_ptr    first_table;
  66. empty_ptr    first_empty;
  67. new_ptr        first_new_comer;
  68.  
  69. int    main_sock,
  70.     next_port,                /* Next port to assign */
  71.     unique_id;
  72.  
  73. /*
  74.  * clear_table - dealer went away; drop that table.
  75.  */
  76. clear_table(tbl_ptr)
  77. table_ptr    tbl_ptr;
  78. {
  79.     table_ptr    prev_ptr = NULL;
  80.     table_ptr    cur_ptr;
  81.     empty_ptr    temp_empty, cur_empty;
  82.     new_ptr        cur_new_comer;
  83.     char        buf[16];
  84.  
  85.     while (wait(0) != tbl_ptr->pid)        /* Wait for process to die */
  86.         ;
  87.     (void) close(tbl_ptr->socket);
  88.     /*
  89.      * Inform new-comers
  90.      */
  91.     (void) sprintf(buf, "x%d", tbl_ptr->table_id);
  92.     for (cur_new_comer = first_new_comer; cur_new_comer;
  93.             cur_new_comer = cur_new_comer->next_new_comer)
  94.         write_socket(cur_new_comer->socket, buf);
  95.     for (cur_ptr = first_table; cur_ptr != tbl_ptr;
  96.                     cur_ptr = cur_ptr->next_table)
  97.         prev_ptr = cur_ptr;
  98.     if (prev_ptr)
  99.         prev_ptr->next_table = tbl_ptr->next_table;
  100.     else
  101.         if ((first_table = tbl_ptr->next_table) == NULL &&
  102.             first_new_comer == NULL)
  103.             exit(0);    /* No more dealers */
  104.             ;
  105.      if (first_table) {
  106.     temp_empty = (empty_ptr) malloc(sizeof(struct empty_table));
  107.     temp_empty->next_empty = NULL;
  108.     temp_empty->port_num = tbl_ptr->port_num;
  109.     free((char *) tbl_ptr);
  110.     if (first_empty) {
  111.         for (cur_empty = first_empty; cur_empty->next_empty;
  112.                     cur_empty = cur_empty->next_empty) ;
  113.         cur_empty->next_empty = temp_empty;
  114.     }
  115.     else
  116.         first_empty = temp_empty;
  117.       }
  118. }
  119.  
  120. /*
  121.  * drop_new_comer - New comer exited
  122.  */
  123. drop_new_comer(dead_new_comer)
  124. new_ptr    dead_new_comer;
  125. {
  126.     new_ptr    cur_new_comer,
  127.         prev_new_comer = NULL;
  128.  
  129.     (void) close(dead_new_comer->socket);
  130.     for (cur_new_comer = first_new_comer; cur_new_comer != dead_new_comer;
  131.             cur_new_comer = cur_new_comer->next_new_comer)
  132.         prev_new_comer = cur_new_comer;
  133.     if (prev_new_comer)
  134.         prev_new_comer->next_new_comer = dead_new_comer->next_new_comer;
  135.     else
  136.         first_new_comer = dead_new_comer->next_new_comer;
  137.     free((char *) dead_new_comer);
  138.     if ((first_table == NULL) && (first_new_comer == NULL))
  139.         exit(0);        /* Nobody connected */
  140. }
  141.  
  142. /*
  143.  * new_player - New player has connected.  Inform of games in progress and
  144.  *        request game to be joined.
  145.  */
  146. new_player()
  147. {
  148.     int    new_socket;        /* new file descriptor */
  149.     char    buf[64];
  150.     struct    sockaddr_in sockad;
  151.     int    ssize;            /* makes accept happy */
  152.     int    i;
  153.     new_ptr        cur_new_comer, temp_new_comer;
  154.     table_ptr    cur_ptr;
  155.  
  156.     /*
  157.      * add whoever's waiting
  158.      */
  159.     ssize = sizeof (sockad);
  160.     if ((new_socket = accept(main_sock, &sockad, &ssize)) == -1) {
  161.         perror("accept");
  162.         exit(-1);
  163.     }
  164.     /*
  165.      * add to list of new_comers
  166.      */
  167.     temp_new_comer = (new_ptr) malloc(sizeof(struct new_comer));
  168.     temp_new_comer->next_new_comer = NULL;
  169.     temp_new_comer->socket = new_socket;
  170.     if (first_new_comer) {
  171.         for (cur_new_comer = first_new_comer;
  172.             cur_new_comer->next_new_comer;
  173.             cur_new_comer = cur_new_comer->next_new_comer) ;
  174.         cur_new_comer->next_new_comer = temp_new_comer;
  175.     }
  176.     else {
  177.         first_new_comer = temp_new_comer;
  178.         first_new_comer->next_new_comer = NULL;
  179.     }
  180.     /*
  181.      * send info on games in progress
  182.      */
  183.     for (cur_ptr = first_table; cur_ptr; cur_ptr = cur_ptr->next_table) {
  184.         (void) sprintf(buf, "t%d", cur_ptr->table_id);
  185.         write_socket(new_socket, buf);
  186.         (void) sprintf(buf, "h%d", cur_ptr->hand);
  187.         write_socket(new_socket, buf);
  188.         (void) sprintf(buf, "r%d", cur_ptr->round);
  189.         write_socket(new_socket, buf);
  190.         for (i = 0; i < 4; i++) {
  191.             (void) sprintf(buf, "p%d%s", i, cur_ptr->player_name[i]);
  192.             write_socket(new_socket, buf);
  193.         }
  194.     }
  195.     write_socket(new_socket, "g");
  196. }
  197.  
  198. tell_new_comers(buf)
  199. char    *buf;
  200. {
  201.     new_ptr    cur_new;
  202.  
  203.     for (cur_new = first_new_comer; cur_new;
  204.             cur_new = cur_new->next_new_comer)
  205.         write_socket(cur_new->socket, buf);
  206. }
  207.  
  208. /*
  209.  * join - join an existing table.  table_num is unique identifier for table.
  210.  */
  211. join(table_num, socket)
  212. int    table_num, socket;
  213. {
  214.     table_ptr    cur_ptr;
  215.     char    buf[16];
  216.  
  217.     for (cur_ptr = first_table; cur_ptr && cur_ptr->table_id != table_num;
  218.                     cur_ptr = cur_ptr->next_table) ;
  219.     if (cur_ptr) {
  220.         (void) sprintf(buf, "c%d", cur_ptr->port_num);
  221.         write_socket(socket, buf);
  222.     }
  223.     else
  224.         write_socket(socket, "g");    /* Table doesn't exist?!? */
  225. }
  226.  
  227. /*
  228.  * new_table - start new hearts game.
  229.  */
  230. new_table(cur_new_comer)
  231. new_ptr    cur_new_comer;
  232. {
  233.     table_ptr    cur_table, new_tbl_ptr;
  234.     empty_ptr    tmp_empty;
  235.     int        i, socks[2];
  236.     int        dealer_port, dealer_socket, retry = 0;
  237.     char    buf[16], filename[1024];
  238.  
  239.     new_tbl_ptr = (table_ptr) malloc(sizeof(struct table));
  240.     new_tbl_ptr->next_table = NULL;
  241.     new_tbl_ptr->table_id = ++unique_id;
  242.     for (i = 0; i < 4; i++)
  243.         (void) strcpy(new_tbl_ptr->player_name[i], "<empty>");
  244.     /*
  245.      * Assign a port.  Reassign a used port if available.
  246.      */
  247.     do {
  248.         if (first_empty) {
  249.             dealer_port = first_empty->port_num;
  250.             tmp_empty = first_empty;
  251.             first_empty = first_empty->next_empty;
  252.             free((char *) tmp_empty);
  253.         }
  254.         else
  255.             dealer_port = next_port++;
  256.         /*
  257.          * Make sure port is ok before assigning.
  258.          */
  259.         if ((dealer_socket = open_socket(dealer_port)) == 0)
  260.             if (++ retry == 20) {
  261.                 fputs("Can't open a dealer port!\n", stderr);
  262.                 exit(1);
  263.             }
  264.     }
  265.     while (dealer_socket == 0);
  266.     new_tbl_ptr->port_num = dealer_port;
  267.     /*
  268.      * Open a socket pair to talk to dealer on.
  269.      */
  270.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1) {
  271.         perror("socketpair");
  272.         exit(1);
  273.     }
  274.     switch (new_tbl_ptr->pid = fork()) {
  275.     case 0:
  276.         (void) setpgrp (0, getpid());
  277.         (void) close(socks[0]);
  278.         if (socks[1] != 3)
  279.             (void) dup2(socks[1], 3);    /* Remap to fd 3 */
  280.         if (dealer_socket != 4)
  281.             (void) dup2(dealer_socket, 4);    /* Remap to fd 4 */
  282.         sprintf(filename, "%s/%s", HEARTSLIB, HEARTSD);
  283.         execl (filename, "heartsd", 0);
  284.         exit(1);
  285.     case -1:
  286.         perror("fork");
  287.         exit(1);
  288.     }
  289.     (void) close(socks[1]);
  290.     (void) close(dealer_socket);
  291.  
  292.     new_tbl_ptr->socket = socks[0];
  293.     if (first_table) {
  294.         for (cur_table = first_table; cur_table->next_table;
  295.             cur_table = cur_table->next_table)
  296.             ;
  297.         cur_table->next_table = new_tbl_ptr;
  298.     }
  299.     else
  300.         first_table = new_tbl_ptr;
  301.     /*
  302.      * Inform hearts player of port # to connect on.
  303.      */
  304.     (void) sprintf(buf, "c%d", dealer_port);
  305.     write_socket(cur_new_comer->socket, buf);
  306. }
  307.  
  308. main(argc, argv)
  309. char **argv;
  310. {
  311.     fd_type        read_fd;
  312.     table_ptr    cur_table;
  313.     new_ptr        cur_new_comer;
  314.     char        buf[64], tmp_buf[64];
  315.     int        ret;
  316.     int        table_num;
  317.     char        debug = FALSE;
  318.  
  319.     while (*++argv) {
  320.         if (**argv == '-') {
  321.             while (*++*argv) {
  322.                 switch (**argv) {
  323.                 case 'd':
  324.                     debug = TRUE;
  325.                     break;
  326.  
  327.                 default:
  328.                     fprintf (stderr, "usage: hearts_dist [-d]\n");
  329.                     exit (1);
  330.                     break;
  331.                 }
  332.             }
  333.         }
  334.     }
  335.  
  336.     first_table = NULL;
  337.     first_empty = NULL;
  338.     first_new_comer = NULL;
  339.     next_port = DIST_PORT;
  340.     unique_id = 0;
  341.  
  342.     if ((main_sock = open_socket(PORT)) == 0) {
  343.         fputs("Distributor port in use!\n", stderr);
  344.         exit(1);
  345.     }
  346.     if (!debug) {
  347.         /*
  348.          * Fork off and die.  Thus hearts invoker wait() returns.
  349.          * This signals ready to connect.
  350.          */
  351.         if (fork())
  352.             exit (0);
  353.     }
  354.  
  355.     for (;;) {
  356.         fd_init(main_sock, &read_fd);
  357.         /*
  358.          * Build mask for dealers
  359.          */
  360.         for (cur_table = first_table; cur_table;
  361.                 cur_table = cur_table->next_table)
  362.             fd_set(cur_table->socket, &read_fd);
  363.         /*
  364.          * Build mask for new_comers
  365.          */
  366.         for (cur_new_comer = first_new_comer; cur_new_comer;
  367.                 cur_new_comer = cur_new_comer->next_new_comer)
  368.             fd_set(cur_new_comer->socket, &read_fd);
  369.  
  370.         /*
  371.          * Wait for something to happen
  372.          */
  373.         if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
  374.                 (struct timeval *) 0)) {
  375.             if (fd_isset(main_sock, read_fd))
  376.                 new_player();
  377.             for (cur_table = first_table; cur_table;
  378.                     cur_table = cur_table->next_table)
  379.                 if (fd_isset(cur_table->socket, read_fd)) {
  380.                     /*
  381.                      * Message from dealer
  382.                      */
  383.                     ret = read_socket(cur_table->socket, buf);
  384.                     if (!ret) {
  385.                         clear_table(cur_table);
  386.                         break;
  387.                     } else {
  388.                         switch (buf[0]) {
  389.                         case 'h' :
  390.                             (void) sscanf(buf + 1, "%d", &cur_table->hand);
  391.                             break;
  392.                         case 'r' :
  393.                             (void) sscanf(buf + 1, "%d", &cur_table->round);
  394.                             break;
  395.                         case 'p' :
  396.                             (void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2);
  397.                         }
  398.                         (void) sprintf(tmp_buf, "t%d", cur_table->table_id);
  399.                         tell_new_comers(tmp_buf);
  400.                         tell_new_comers(buf);
  401.                     }
  402.                 }
  403.             for (cur_new_comer = first_new_comer; cur_new_comer;
  404.                 cur_new_comer = cur_new_comer->next_new_comer)
  405.                 if (fd_isset(cur_new_comer->socket, read_fd)) {
  406.                     /*
  407.                      * Message from newcomer
  408.                      */
  409.                     ret = read_socket(cur_new_comer->socket, buf);
  410.                     if (ret)
  411.                         switch (buf[0]) {
  412.                         case 'j' :
  413.                             (void) sscanf(buf + 1, "%d", &table_num);
  414.                             join(table_num, cur_new_comer->socket);
  415.                             break;
  416.  
  417.                         case 'n' :
  418.                             new_table(cur_new_comer);
  419.                         }
  420.                     else {
  421.                         drop_new_comer(cur_new_comer);
  422.                         break;
  423.                          }
  424.                 }
  425.         }
  426.     }
  427. }
  428.  
  429.