home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume14 / okbridge2 / part07 / network.c < prev    next >
C/C++ Source or Header  |  1993-01-27  |  33KB  |  1,300 lines

  1. /* network.c
  2.  *
  3.  ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  4.  ! 
  5.  ! OKbridge is made available as a free service to the Internet.
  6.  ! Accordingly, the following restrictions are placed on its use:
  7.  ! 
  8.  ! 1.  OKbridge may not be modified in any way without the explicit 
  9.  !     permission of Matthew Clegg.  
  10.  ! 
  11.  ! 2.  OKbridge may not be used in any way for commercial advantage.
  12.  !     It may not be placed on for-profit networks or on for-profit
  13.  !     computer systems.  It may not be bundled as part of a package
  14.  !     or service provided by a for-profit organization.
  15.  ! 
  16.  ! If you have questions about restrictions on the use of OKbridge,
  17.  ! write to mclegg@cs.ucsd.edu.
  18.  ! 
  19.  ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  20.  ! damage which may be caused by OKbridge.
  21.  *
  22.  * This is the implementation of the network module.  The network module
  23.  * provides two functions.  First it abstracts the socket communication
  24.  * into messages which are handled on the message queues, and second
  25.  * it provides a branch point between the server and client sides of
  26.  * the code.
  27.  *
  28.  */  
  29.  
  30. /* The NO_TM_ZONE definition is for machines which do not have the
  31.    field tm_zone defined in the struct tm returned by localtime.
  32.    In this case, we use the struct timezone returned by gettimeofday
  33.    to determine an offset from GMT.
  34. */
  35.  
  36. #ifdef AIX
  37. #define NO_TM_ZONE 1
  38. #define NO_PWCOMMENT 1
  39. #endif
  40.  
  41. #ifdef HARRIS
  42. #define NO_TM_ZONE 1
  43. #endif
  44.  
  45. /* The NO_PWCOMMENT definition is for machines which do not have the
  46.    pw_comment field defined in struct passwd returned by getpwuid ().
  47. */
  48.  
  49. #ifdef AIX
  50. #define NO_PWCOMMENT 1
  51. #endif
  52.  
  53. #ifdef SGI
  54. #define NO_TM_ZONE 1
  55. #endif
  56.  
  57. #include <ctype.h>
  58. #include <sys/errno.h>
  59. #include <sys/types.h>
  60. #include <sys/socket.h>
  61. #include <netinet/in.h>
  62. #include <arpa/inet.h>
  63. #include <netdb.h>
  64. #include <pwd.h>
  65. #include <stdio.h>
  66. #include <string.h>
  67. #include <sys/time.h>
  68. #include <sys/resource.h>
  69. #ifdef AIX
  70. #include <sys/select.h>
  71. #include <time.h>
  72. #endif
  73.  
  74. #define _NETWORK_ 
  75.  
  76. #include "state.h"
  77. #include "socket.h"
  78. #include "display.h"
  79. #include "gps.h"
  80. #include "fds.h"
  81.  
  82. #ifdef GCC
  83. extern bzero (), fprintf (), fflush (), accept ();
  84. extern time_t time ();
  85. #endif
  86.  
  87. extern int errno;
  88. extern char *sys_errlist [];
  89. extern char *getlogin(), *getenv();
  90. extern char *strdup ();
  91. extern char *malloc ();
  92. extern void close ();
  93. extern int select ();
  94. extern int gethostname ();
  95. extern uid_t getuid ();
  96.  
  97. extern int Terminate_Program ();
  98. extern void restore_cursor ();
  99. extern void Broadcast_Comment ();
  100. extern void Generate_reset ();
  101. extern void Vacate_seat ();
  102.  
  103. #ifndef index
  104. extern char *index();
  105. #endif
  106.  
  107. #ifdef LOGFILE
  108.   FILE *net_log = NULL;
  109. #endif
  110.  
  111. #define DISCARD (void)
  112.  
  113. #define RETRY_LIMIT 60
  114.  
  115. static Message message_free_list = NULL;
  116. static Connection connection_freelist = NULL;
  117.  
  118. static int listen_port = -1;
  119.   /* The socket we have opened for listening for new connections. */
  120. static int server_port = -1;
  121.   /* The socket opened by the client for listening to the server. */
  122.  
  123. extern char socket_error[];
  124.   /* An error message buffer for recording socket errors. */
  125.  
  126. /* Procedures for manipulating command queues: */
  127.  
  128. static message_queue Allocate_message_queue ()
  129. {
  130.   message_queue m;
  131.  
  132.   m = (message_queue) malloc (sizeof(struct Message_queue_struct));
  133.   m->head = m->tail = NULL;
  134.   return (m);
  135. }
  136.  
  137. int message_available (queue)
  138.      message_queue queue;
  139. /* Returns true if the given queue is nonempty. */
  140. {
  141.   return (queue->head != NULL);
  142. }
  143.  
  144. Message dequeue_message (queue)
  145.      message_queue queue;
  146. /* Deletes the first message from the given queue and returns a pointer
  147.    to that message.  
  148. */
  149. {
  150.   Message m;
  151.  
  152.   if (!message_available(queue))
  153.     return (NULL);
  154.  
  155.   m = queue->head;
  156.   queue->head = m->next;
  157.   if (queue->head == NULL)
  158.     queue->tail = NULL;
  159.   return (m);
  160. }
  161.  
  162. void enqueue_message (queue, m)
  163.      message_queue queue; Message m;
  164. /* Appends m to the list of messages stored in the given message queue. */
  165. {
  166.   m->next = NULL;
  167.   if (queue->tail == NULL)
  168.     queue->head = queue->tail = m;
  169.   else {
  170.     queue->tail->next = m;
  171.     queue->tail = m;
  172.   }
  173.  
  174. }
  175.  
  176. Message allocate_message ()
  177. /* Allocates a message structure and returns a pointer to the structure. */
  178. {
  179.   Message m;
  180.  
  181.   if (message_free_list == NULL)
  182.     m = (Message) malloc (sizeof(struct Message_struct));
  183.   else {
  184.     m = message_free_list;
  185.     message_free_list = m->next;
  186.   }
  187.  
  188.   m->p.command_text[0] = '\0';
  189.   m->p.player_no = 0;
  190.   m->private = 0;
  191.   m->loopback = 0;
  192.   return (m);
  193. }
  194.  
  195. void deallocate_message (m)
  196.      Message m;
  197. /* Returns the message structure m to the pool of free message structs. */
  198. {
  199.   m->next = message_free_list;
  200.   message_free_list = m;
  201.   m->p.player_no = 0;
  202. }
  203.  
  204. void clear_message_queue (queue)
  205.      message_queue queue;
  206. /* Deletes all messages from the named queue. */
  207. {
  208.   Message m;
  209.  
  210.   while (message_available(queue)) {
  211.     m =  dequeue_message (queue);
  212.     deallocate_message (m);
  213.   }
  214. }
  215.  
  216. void clear_all_message_queues (t)
  217.      Table t;
  218. /* Clears all of the message queues. */
  219. {
  220.   clear_message_queue (t->protocol_queue);
  221.   clear_message_queue (t->conversation_queue);
  222.   clear_message_queue (t->game_queue);
  223. }
  224.  
  225. static Connection Allocate_Dummy_Connection ()
  226. /* Allocates a new connection structure and fills in the fields with
  227.    appropriate initial values.  Does not link the connection into any list. */
  228. {
  229.   Connection c;
  230.  
  231.   if (connection_freelist == NULL)
  232.     c = (Connection) malloc (sizeof(struct Connection_struct));
  233.   else {
  234.     c = connection_freelist;
  235.     connection_freelist = c->inext;
  236.   }
  237.  
  238.   c->channel = 0;
  239.   c->local   = 1;
  240.   c->state   = CSTATE_CONNECTED;
  241.   c->player_name[0] = '\0';
  242.   c->fullname[0] = '\0';
  243.   c->email[0] = '\0';
  244.   c->registry[0] = '\0';
  245.   c->seat    = PLAYER_OBS;
  246.   c->table = NULL;
  247.  
  248.   c->iprev = c->inext = c->oprev = c->onext = NULL;
  249.   if (Connections == NULL)
  250.     Connections = c;
  251.  
  252.   return (c);
  253. }
  254.  
  255. static Connection Allocate_Connection ()
  256. /* Allocates a new connection structure, and fills in the pointer fields
  257.    appropriately.  Links the connection into the Connection list. */
  258. {
  259.   Connection c = Allocate_Dummy_Connection ();
  260.  
  261.   c->inext = Connections->inext;
  262.   c->iprev = Connections;
  263.   if (c->inext != NULL)
  264.     c->inext->iprev = c;
  265.   Connections->inext = c;
  266.  
  267.   return (c);
  268. }
  269.  
  270. static void Link_Output_Connection (p, c)
  271.      Connection p, c;
  272. /* Links the connection c into the list pointed to by p.  Since we
  273.    always store dummy header elements in connection lists, p is guaranteed
  274.    to be non-NULL, even in the case of an empty list.*/
  275. {
  276.  
  277.   c->oprev = p;
  278.   c->onext = p->onext;
  279.   if (c->onext != NULL)
  280.     c->onext->oprev = c;
  281.   p->onext = c;
  282.  
  283. }
  284.  
  285. static void Unlink_Output_Connection (c)
  286.      Connection c;
  287. /* Unlinks the connection c from the list containing it. */
  288. {
  289.   if (c->onext != NULL)
  290.     c->onext->oprev = c->oprev;
  291.  
  292.   if (c->oprev != NULL)
  293.     c->oprev->onext = c->onext;
  294.  
  295.   c->oprev = c->onext = NULL;
  296. }
  297.  
  298. static void Deallocate_Connection (c)
  299.      Connection c;
  300. /* Unlinks the connection c from any lists which may contain it and
  301.    then returns the connection to the free store. */
  302. {
  303.   Unlink_Output_Connection (c);
  304.   
  305.   if (c->inext != NULL)
  306.     c->inext->iprev = c->iprev;
  307.   c->iprev->inext = c->inext;
  308.  
  309.   c->inext = connection_freelist;
  310.   connection_freelist = c;
  311. }
  312.  
  313. void close_connection (c)
  314.      Connection c;
  315. /* void close_connection (Connection c) */
  316. /* Closes the connection to c. */
  317. {
  318.   Table t = c->table;
  319. #ifdef DEBUG
  320.   char error_buf[100];
  321. #endif
  322.  
  323.   if (c->local)
  324.     return;
  325.  
  326. #ifdef DEBUG
  327.   sprintf (error_buf, "CLOSED CONNECTION ON FD %d.", c->channel);
  328.   Network_Comment (error_buf);
  329. #endif 
  330.  
  331.   Vacate_seat (c->table, c->seat);
  332.  
  333.   if (c->channel > 0)
  334.     close (c->channel);
  335.  
  336.   Deallocate_Connection (c);
  337. }
  338.  
  339. int No_connections (t)
  340.      Table t;
  341. /* Returns the number of connections to the table t. */
  342. {
  343.   int n;
  344.   Connection c;
  345.  
  346.   n = 0;
  347.   FOREACH_PLAYER (c, t)
  348.     n++;
  349.   return (n);
  350. }
  351.  
  352. Message loopback_message_unformatted (t, c, message)
  353.      Table t; Connection c; char *message;
  354. /* void loopback_message_unformatted (Table t, char *message); */
  355. /* Constructs a message structure using the the given message.
  356.    Assumes that the message is in the format which is used by the
  357.    client in transmitting messages.  Appends the message structure
  358.    to the protocol queue for the table t.
  359. */
  360. {
  361.   Message m = allocate_message ();
  362.   strcpy (m->p.command_text, message);
  363.   Parse_Command_for_Client (&(m->p));
  364.   m->source = c;
  365.   m->loopback = 1;
  366.   enqueue_message (t->protocol_queue, m);
  367.   return (m);
  368. }
  369.  
  370. Message loopback_message (t, c, message)
  371.      Table t; Connection c; char *message;
  372. /* void loopback_message (Table t, Connection c, char *message); */
  373. /* Constructs a message structure using the given source, source name
  374.    and message text.  Appends the message structure to the protocol
  375.    queue for the table t.
  376. */
  377. {
  378.   Message m = allocate_message ();
  379.  
  380.   sprintf (m->p.command_text, "%s %s %s", seat_names[c->seat],
  381.        c->player_name, message);
  382.   m->source = c;
  383.   m->loopback = 1;
  384.   Parse_Command_for_Client (&(m->p));
  385.   enqueue_message (t->protocol_queue, m);
  386.   return (m);
  387. }
  388.  
  389. int server_send_unformatted (c, message)
  390.      Connection c; char *message;
  391. /* Transmits the message to the given player.  Returns 0 if successful or 1
  392.    if an error.  If an error occurs, then the connection is closed.
  393. */
  394. {
  395.   int status;                 /* return code from Select call. */
  396.   int log;                    /* number of bytes transmitted. */
  397.   int n;                      /* number of bytes to transmit. */
  398.   struct fd_set wait_set;     /* A set representing the connections that
  399.                  have been established. */
  400.   struct timeval tm;          /* A timelimit of zero for polling for new
  401.                  connections. */
  402.   char buf [100];
  403.  
  404.   if (c->local) {
  405. /*    loopback_message_unformatted (c->table, c, message); */
  406.     return (1);
  407.   }
  408.  
  409.   FD_ZERO (&wait_set);
  410.   FD_SET (c->channel, &wait_set);
  411.  
  412.   tm.tv_sec = 0;
  413.   tm.tv_usec = 0;
  414.   status = select (FD_SETSIZE, (fd_set *) 0, &wait_set, (fd_set *) 0, &tm);
  415.  
  416.   if (status < 0) {
  417.     sprintf (buf, "WRITE ERROR TO %s: %s", c->player_name, sys_errlist[errno]);
  418.     Network_Comment (buf);
  419.     shutdown (c->channel, 2);
  420.     c->channel = 0;
  421.     close_connection (c);
  422.     return (1);
  423.   } else if (status == 0) {
  424.     sprintf (buf, "WRITE BLOCK FOR %s", c->player_name);
  425.     Network_Comment (buf);
  426.     shutdown (c->channel, 2);
  427.     c->channel = 0;
  428.     close_connection (c);
  429.     return (1);
  430.   }
  431.  
  432.   n = strlen (message) + 1;
  433.   do {
  434.     log = fd_writeln (c->channel, message);
  435.   } while ((log < 0) && (errno == EINTR));
  436.  
  437.   if (log < n) {
  438.     sprintf (buf, "WRITE BLOCK FOR %s", c->player_name);
  439.     Network_Comment (buf);
  440.     close_connection (c);
  441.     return (1);
  442.   }
  443.  
  444. #ifdef LOGFILE
  445.   fprintf (net_log, "%2d > %s\n", c->channel, message);
  446.   fflush (net_log);
  447. #endif    
  448.   return (0);
  449. }
  450.  
  451. int server_send (c, source, player_name, message)
  452.      Connection c; int source; char *player_name, *message;
  453. /* Formats a message and sends it across the given connection.
  454.    Returns 0 if successful or 1 if an error.  If an error occurs,
  455.    then the connection is closed. */
  456. {
  457.   char buf [120];
  458.  
  459.   sprintf (buf, "%s %s %s", seat_names[source], player_name, message);
  460.   return (server_send_unformatted (c, buf));
  461. }
  462.  
  463. int May_receive (c, msg_type)
  464.      Connection c; int msg_type;
  465. /* Returns true if a message of type msg_type can be sent to channel c. */
  466. {
  467.   if (c == NULL)
  468.     return (0);
  469.   else if (c->state == CSTATE_PLAYING)
  470.     return (1);
  471.   else
  472.     return (0);
  473. }
  474.  
  475. void server_broadcast_unformatted (t, msg_type, message)
  476.      Table t; int msg_type; char *message;
  477. /* Broadcasts the message to all of the people sitting at table t who are
  478.    entitled to receive the message. */
  479. {
  480.   Connection c, d;
  481.   int local = 0;
  482.  
  483.   c = t->Players->onext;
  484.   while (c != NULL) {
  485.     d = c->onext;
  486.     if (May_receive (c, msg_type)) {
  487.       if (c->local)
  488.     local = 1;
  489.       else
  490.     server_send_unformatted (c, message);
  491.     }
  492.     c = d;
  493.   }
  494.  
  495.   if (local && (msg_type != CMD_BOARD) && (msg_type != CMD_RECORD))
  496.     loopback_message_unformatted (t, MODERATOR(t), message);
  497. }
  498.  
  499. void server_broadcast (t, source, player_name, msg_type, message)
  500.      Table t; int source, msg_type; char *player_name, *message;
  501. /* Formats and broadcasts the message to all of the people sitting at table t
  502.    who are entitled to receive the message. */
  503. {
  504.   char buf [120];
  505.  
  506.   sprintf (buf, "%s %s %s", seat_names[source], player_name, message);
  507.   server_broadcast_unformatted (t, msg_type, buf);
  508. }
  509.  
  510. void Relay_message (t, c, msg_type, message)
  511.      Table t; Connection c; int msg_type; char *message;
  512. /* Relays the message from c to all of the other players at table t who
  513.    are allowed to receive the message. */
  514. {
  515.   Connection p, q;
  516.  
  517.   p = t->Players->onext;
  518.   while (p != NULL) {
  519.     q = p->onext;
  520.     if ((p->channel != c->channel) && May_receive (p, msg_type))
  521.       server_send_unformatted (p, message);
  522.     p = q;
  523.   }
  524. }
  525.  
  526. Message send_message (t, msg_type, message)
  527.      Table t; int msg_type; char *message;
  528. /* If in server mode, sends a message to each of the clients.
  529.    If in client mode, sends a message to the server. */
  530. {
  531.   char message_buf [120];
  532.   Message m;
  533.  
  534.   m = loopback_message (t, Local_Player_Connection, message);
  535.  
  536.   if (client_mode) {
  537.     sprintf (message_buf, "%s %s", local_player_name, message);
  538.     fd_writeln (server_port, message_buf);
  539. #ifdef LOGFILE
  540.   fprintf (net_log, "   > %s\n", message_buf);
  541.   fflush (net_log);
  542. #endif    
  543.   }
  544.  
  545.   return (m);
  546. }
  547.  
  548. void send_server_message (t, msg_type, message)
  549.      Table t; int msg_type; char *message;
  550. /* Sends a message which originates from the 'SERVER'.
  551.    Should only be used if in server mode.
  552. */
  553. {
  554.   server_broadcast (t, PLAYER_SERVER, seat_names[PLAYER_SERVER], 
  555.             msg_type, message);
  556. }
  557.  
  558. void send_private_message (c, message)
  559.      Connection c; char *message;
  560. /* static void send_private_message (Connection c, char *message) */
  561. /* Only to be used in server mode.  Sends a message from the 'server'
  562.    to the connection c.  If the connection c is the local player,
  563.    then appends the message to the protocol queue of the table of
  564.    the local player.
  565. */
  566. {
  567.   Message m;
  568.  
  569.   if (c->local) {
  570.     m = loopback_message (c->table, MODERATOR(c->table), message);
  571.     m->private = 1;
  572.   } else
  573.     server_send (c, PLAYER_SERVER, seat_names[PLAYER_SERVER], message);
  574. }
  575.  
  576. static void Broadcast_Inline_Data (t, msg_type, buf)
  577.      Table t;
  578.      int msg_type;
  579.      char *buf;
  580. /* Broadcasts the contents of buf to each of the connections at table t. */
  581. {
  582.   Connection c, d;
  583.  
  584.   if (server_mode) {
  585.     c = t->Players->onext;
  586.     while (c != NULL) {
  587.       d = c->onext;
  588.       if (May_receive (c, msg_type)) {
  589.     if (!c->local)
  590.       server_send_unformatted (c, buf);
  591.       }
  592.       c = d;
  593.     }
  594.   } else
  595.     fd_writeln (server_port, buf);
  596. }
  597.  
  598. static void Relay_Inline_Data (t, f, msg_type, buf)
  599.      Table t;
  600.      Connection f;
  601.      int msg_type;
  602.      char *buf;
  603. /* Broadcasts the contents of buf to each of the connections at table
  604.    t EXCEPT f. */
  605. {
  606.   Connection c, d;
  607.  
  608.   c = t->Players->onext;
  609.   while (c != NULL) {
  610.     d = c->onext;
  611.     if (May_receive (c, msg_type)) {
  612.       if ((c != f) && !c->local)
  613.     server_send_unformatted (c, buf);
  614.     }
  615.     c = d;
  616.   }
  617. }
  618.  
  619. void Transmit_board (t, b)
  620.      Table t;
  621.      Board *b;
  622. /* If we are the server, then transmits the board b to each of the players
  623.    at the table t.  If we are a client, then transmits the board b to
  624.    the server. */
  625. {
  626.   char buf1[100], buf2[100];
  627.  
  628.   Encode_board (b, buf1, buf2);
  629.   Broadcast_Inline_Data (t, CMD_BOARD, buf1);
  630.   Broadcast_Inline_Data (t, CMD_BOARD, buf2);
  631. }
  632.  
  633. void Transmit_play_record (t, p)
  634.      Table t;
  635.      Play_record *p;
  636. /* If we are the server, then transmits the play record p to each of the
  637.    players at the table t.  If we are a client, then transmits the play
  638.    record p to the server. */
  639. {
  640.   char buf1[100], buf2[100], buf3[100];
  641.  
  642.   Encode_play_record (p, buf1, buf2, buf3);
  643.   Broadcast_Inline_Data (t, CMD_RECORD, buf1);
  644.   Broadcast_Inline_Data (t, CMD_RECORD, buf2);
  645.   Broadcast_Inline_Data (t, CMD_RECORD, buf3);
  646. }
  647.  
  648. void Relay_board (t, c, b)
  649.      Table t;
  650.      Connection c;
  651.      Board *b;
  652. /* Relays the in-line board data from the connection c to the other players
  653.    at the table t.
  654. */
  655. {
  656.   char buf1[100], buf2[100];
  657.  
  658.   Encode_board (b, buf1, buf2);
  659.   Relay_Inline_Data (t, c, CMD_BOARD, buf1);
  660.   Relay_Inline_Data (t, c, CMD_BOARD, buf2);
  661. }
  662.  
  663.  
  664. void Relay_play_record (t, c, p)
  665.      Table t;
  666.      Connection c;
  667.      Play_record *p;
  668. /* Relays the in-line play record from the connection c to the other players
  669.    at the table t.
  670. */
  671. {
  672.   char buf1[100], buf2[100], buf3[100];
  673.  
  674.   Encode_play_record (p, buf1, buf2, buf3);
  675.   Relay_Inline_Data (t, c, CMD_RECORD, buf1);
  676.   Relay_Inline_Data (t, c, CMD_RECORD, buf2);
  677.   Relay_Inline_Data (t, c, CMD_RECORD, buf3);
  678. }
  679.  
  680. Board *Receive_board (c)
  681.      Connection c;
  682. /* Receives a board as in-line data from the connection c. */
  683. {
  684.   char buf1[100], buf2[100];
  685.   int status;
  686.   Board *b;
  687.   int chan;
  688.  
  689.   if (client_mode)
  690.     chan = server_port;
  691.   else
  692.     chan = c->channel;
  693.  
  694.   status = fd_readln (chan, buf1, 100);
  695.   if (status <= 0)
  696.     return (NULL);
  697.  
  698.   status = fd_readln(chan, buf2, 100);
  699.   if (status <= 0)
  700.     return (NULL);
  701.  
  702.   b = Decode_board (buf1, buf2);
  703.   return (b);
  704. }
  705.  
  706. Play_record *Receive_play_record (c)
  707.      Connection c;
  708. /* Receives a play record as in-line data from the connection c. */
  709. {
  710.   char buf1[100], buf2[100], buf3[100];
  711.   int status;
  712.   Play_record *p;
  713.   int chan;
  714.  
  715.   if (client_mode)
  716.     chan = server_port;
  717.   else
  718.     chan = c->channel;
  719.  
  720.   status = fd_readln (chan, buf1, 100);
  721.   if (status < 0)
  722.     return (NULL);
  723.  
  724.   status = fd_readln (chan, buf2, 100);
  725.   if (status < 0)
  726.     return (NULL);
  727.  
  728.   status = fd_readln (chan, buf3, 100);
  729.   if (status < 0)
  730.     return (NULL);
  731.  
  732.   p = Decode_play_record (buf1, buf2, buf3);
  733.   return (p);
  734. }
  735.  
  736. static Table Allocate_Table ()
  737. /* Allocates a table structure and initializes it. */
  738. {
  739.   Table t;
  740.   int i;
  741.  
  742.   t = (Table) malloc(sizeof(struct Table_struct));
  743.  
  744.   for (i = 0; i < PLAYER_TYPES; i++) {
  745. /*    t->Seats[i].player_name[0] = '\0'; */
  746.     sprintf (t->Seats[i].player_name, "%s", seat_names[i]);
  747.     t->Seats[i].occupied = 0;
  748.     t->Seats[i].connection = NULL;
  749.   }
  750.  
  751.   t->protocol_queue = Allocate_message_queue ();
  752.   t->conversation_queue = Allocate_message_queue ();
  753.   t->game_queue = Allocate_message_queue ();
  754.  
  755.   /* The first element of the connections list is used to represent
  756.      the server for the table. */
  757.   t->Players = Allocate_Dummy_Connection ();
  758.   t->Players->local = 1;
  759.   t->Players->seat  = PLAYER_SERVER;
  760.   t->Players->table = t;
  761.   sprintf (t->Players->player_name, "MOD");
  762.  
  763.   t->table_no = 1;
  764.   t->game_mode = STARTUP_MODE;
  765.   t->playing_mode = CLUB_PLAYING_MODE;
  766.   t->board = NULL;
  767.   t->play_record = NULL;
  768.   t->above_line[0] = t->above_line[1] = 0;
  769.   t->below_line[0] = t->below_line[1] = 0;
  770.   
  771.   if (Table_List == NULL) {
  772.     Table_List = t;
  773.     t->prev = t->next = NULL;
  774.   } else {
  775.     t->next = Table_List->next;
  776.     if (t->next != NULL)
  777.       t->next->prev = t;
  778.     t->prev = Table_List;
  779.     t->prev->next = t;
  780.   }
  781.  
  782.   return (t);
  783. }
  784.      
  785. void Initialize_Table_List ()
  786. /* Initializes the array of tables. */
  787. {
  788.   Table_List = Local_table = Allocate_Table ();
  789.   Local_Player_Connection = Allocate_Connection ();
  790.   
  791.   Local_Player_Connection->channel = 0;
  792.   Local_Player_Connection->local   = 1;
  793.   Local_Player_Connection->spectator = 0;
  794.   Local_Player_Connection->seat    = local_player;
  795.   Local_Player_Connection->table   = Local_table;
  796.   sprintf (Local_Player_Connection->player_name, "%s", local_player_name);
  797.  
  798.   if (IS_PLAYER(local_player)) {
  799.     Local_table->Seats[local_player].connection = Local_Player_Connection;
  800.     Local_table->Seats[local_player].occupied = 1;
  801.     sprintf (Local_table->Seats[local_player].player_name, "%s", 
  802.          local_player_name);
  803.   }
  804.  
  805.   Link_Output_Connection (Local_table->Players, Local_Player_Connection);
  806. }
  807.  
  808. void Initialize_Network_Logfile ()
  809. {
  810. #ifdef LOGFILE
  811.   char buf[80];
  812.  
  813.   sprintf (buf, "%s.log", local_player_name);
  814.   net_log = fopen (buf, "w");
  815.   if (net_log == NULL) {
  816.     sprintf (buf, "Error opening net_log file %s: %s", buf,
  817.          sys_errlist[errno]);
  818.     fflush (net_log);
  819.     Terminate_Program (buf);
  820.   }
  821. #endif
  822. }
  823.  
  824. void Initialize_Network ()
  825. {
  826.   struct hostent *he;
  827.   struct passwd *pw_entry;
  828.   char *my_addr, *user, *name, *p;
  829.   char buf[100];
  830.  
  831. #ifdef NO_TM_ZONE
  832.   struct timeval tp;
  833.   struct timezone tzp;
  834. #else
  835.   time_t current_time;
  836.   struct tm *decoded_time;
  837. #endif
  838.  
  839.   gethostname (Host_name, 100);
  840.  
  841.   if (!Host_IP_is_known) {
  842.     he = gethostbyname (Host_name);
  843.     if (he != NULL) {
  844.       sprintf (Host_name, "%s", he->h_name);
  845. /*    in = (struct in_addr *) he->h_addr_list[0];
  846.       my_addr = inet_ntoa(*in);
  847. */
  848.       my_addr = inet_ntoa(**((struct in_addr **) he->h_addr_list));
  849.       if (my_addr == NULL) my_addr = "--";
  850.       sprintf (Host_IP, "%s", my_addr);
  851.       Host_IP_is_known = 1;
  852.     } else
  853.       sprintf (Host_IP, "--");
  854.   }
  855.  
  856.   pw_entry = getpwuid (getuid());
  857.   if (pw_entry != NULL) {
  858.     sprintf (User_name, "%s", pw_entry->pw_name);
  859. #ifndef NO_PWCOMMENT
  860.     if (pw_entry->pw_comment != NULL) {
  861.       sprintf (User_fullname, "%s", pw_entry->pw_gecos);
  862.       if ((p = index(User_fullname, ',')) != NULL)
  863.     *p = '\0';
  864.     } else 
  865. #endif
  866.     if ((name = getenv("NAME")) != NULL)
  867.       sprintf (User_fullname, "%s", name);
  868.     else
  869.       sprintf (User_fullname, "%s", User_name);
  870.   } else {
  871.     user = getlogin ();
  872.     if (user == NULL)
  873.       user = getenv("USER");
  874.     if (user == NULL)
  875.       user = "unknown";
  876.     sprintf (User_name, "%s", user);
  877.     name = getenv("NAME");
  878.     if (name != NULL)
  879.       sprintf (User_fullname, "%s", name);
  880.     else if (local_player_full_name != NULL)
  881.       sprintf (User_fullname, "%s", local_player_full_name);
  882.     else
  883.       sprintf (User_fullname, "%s", User_name);
  884.   }
  885.  
  886.   if (local_player_email == NULL) {
  887.     sprintf (buf, "%s@%s", pw_entry->pw_name, Host_name);
  888.     local_player_email = strdup (buf);
  889.   }
  890.  
  891.   if (Timezone_name == NULL) {
  892. #ifdef NO_TM_ZONE
  893.     gettimeofday (&tp, &tzp);
  894.     if (tzp.tz_minuteswest < 0)
  895.       sprintf (buf, "GMT+%d:%02d", 
  896.            (-tzp.tz_minuteswest)/60, (-tzp.tz_minuteswest)%60);
  897.     else
  898.       sprintf (buf, "GMT-%d:%02d", 
  899.            tzp.tz_minuteswest/60, tzp.tz_minuteswest%60);
  900.     Timezone_name = strdup (buf);
  901. #else
  902.     time (¤t_time);
  903.     decoded_time = localtime (¤t_time);
  904.     Timezone_name = strdup(decoded_time->tm_zone);
  905. #endif
  906.   }
  907.  
  908.   if (Registration == NULL)
  909.     Registration = strdup (local_player_email);
  910.  
  911.   /* Allocate a dummy head for the connections list. */
  912.   Connections = Allocate_Dummy_Connection ();
  913.  
  914.   Initialize_Network_Logfile ();
  915.   Initialize_Table_List ();
  916.   
  917.   client_mode = server_mode = 0;
  918.   server_port = listen_port = 0;
  919. }
  920.  
  921. void Close_all_connections ()
  922. {
  923.   Connection c, d;
  924.   Table t;
  925.   int i;
  926.  
  927.   if (server_mode) {
  928.     if (listen_port > 0) {
  929.       close (listen_port);
  930.       listen_port = 0;
  931.     }
  932.  
  933.     for (c = Connections->inext; c != NULL; ) {
  934.       d = c->inext;
  935.       if (!c->local) {
  936.     close_connection (c);
  937.     Vacate_seat (c->table, c->seat);
  938.       }
  939.       c = d;
  940.     }
  941.  
  942.     GPS_End_Server_Mode ();
  943.  
  944.   } else if (client_mode) {
  945.     for (t = Table_List; t != NULL; t = t->next)
  946.       for (i = 0; i < 4; i++)
  947.     if ((t != Local_table) || (i != local_player))
  948.       Vacate_seat (t, i);
  949.     if (server_port > 0)
  950.       close(server_port);
  951.   }
  952.  
  953. /*  Initialize_Table_List (); */
  954.   server_mode = client_mode = 0;
  955.   server_port = listen_port = 0;
  956. }
  957.  
  958. void Switch_Table (c, new_table)
  959.      Connection c;
  960.      Table new_table;
  961. /* Unlinks the connection c from the current table and links it into
  962.    the new table.
  963. */
  964. {
  965.   Unlink_Output_Connection (c);
  966.   Link_Output_Connection (new_table->Players, c);
  967. }
  968.  
  969. void Setup_server ()
  970. /* Initializes the data structures for the server. */
  971. {
  972.   char comment_buf [80];
  973.   int retries;
  974.   time_t current_time;
  975.   struct tm *decoded_time;
  976.  
  977.   retries = 0;
  978.   do {
  979.     listen_port = open_port (network_port);
  980.     retries = retries + 1;
  981.     if (listen_port <= 0)
  982.       network_port++;
  983.   } while ((listen_port <= 0) && (retries < 10));
  984.  
  985.   if (listen_port <= 0) {
  986.     Network_Comment (socket_error);
  987.     Network_Comment ("ERROR IN SETTING UP SERVER.");
  988.     return;
  989.   }
  990.  
  991.   sprintf (comment_buf, "ENTERING SERVER MODE ON PORT %d", network_port);
  992.   Network_Comment (comment_buf);
  993.  
  994.   sprintf (PLAYER_NAME(Local_table, PLAYER_SERVER), "%s", local_player_name);
  995.  
  996.   server_mode = 1;
  997.   time (¤t_time);
  998.   decoded_time = localtime (¤t_time);
  999.  
  1000.   sprintf (Server_Start_time, "%2d:%02d %s", decoded_time->tm_hour,
  1001.        decoded_time->tm_min, Timezone_name);
  1002.  
  1003.   if (local_player_full_name != NULL)
  1004.     sprintf (Local_Player_Connection->fullname, "%s", local_player_full_name);
  1005.   else if (strlen(User_fullname) > 0)
  1006.     sprintf (Local_Player_Connection->fullname, "%s", User_fullname);
  1007.  
  1008.   if (local_player_email != NULL)
  1009.     sprintf (Local_Player_Connection->email, "%s", local_player_email);
  1010.   sprintf (Local_Player_Connection->registry, "%s", Registration);
  1011.  
  1012.   GPS_Broadcast_Server ();
  1013.   Local_Player_Connection->state = CSTATE_PLAYING;
  1014.  
  1015. }
  1016.  
  1017. void Assign_seat ();
  1018.  
  1019. void Attempt_to_connect (seat_requested)
  1020.      int seat_requested;
  1021. /* Attempts to connect to the server named as server_name.  If the
  1022.  * connection is successful, then initializes the Table data structure
  1023.  * appropriately and sends an initial handshaking message.
  1024.  */
  1025. {
  1026.   int status;  /* Return code from client_init call. */
  1027.   char message_buf [80];
  1028.  
  1029.   sprintf (message_buf, "CONNECTING TO SERVER AT %s, PORT %d.", server_name,
  1030.        network_port);
  1031.   Network_Comment (message_buf);
  1032.   restore_cursor ();
  1033.  
  1034.   status = client_init (server_name, network_port, 3);
  1035.   if (status < 0) {
  1036.     Network_Comment (socket_error);
  1037.     return;
  1038.   }
  1039.  
  1040.   Network_Comment ("CONNECTION ESTABLISHED.");
  1041.   server_port = status;
  1042.   client_mode = 1;
  1043.  
  1044.   /* Now we construct the initial handshake message that we send
  1045.      to the server.  This message is of the form:
  1046.        HELLO <ver> <player-name>
  1047.      where
  1048.        <ver>  is the current version of the program, 
  1049.        <player-name> is the name of the local player.
  1050.   */
  1051.   sprintf (message_buf, "%s HELLO %s %s %s", local_player_name,
  1052.        major_revision_level, local_player_name,
  1053.        seat_names[seat_requested]);
  1054.   fd_writeln (server_port, message_buf);
  1055. #ifdef LOGFILE
  1056.   fprintf (net_log, "   > %s\n", message_buf);
  1057.   fflush (net_log);
  1058. #endif    
  1059.  
  1060.   local_player = PLAYER_OBS;
  1061.   (void) Assign_seat (Local_table, Local_Player_Connection, PLAYER_OBS);
  1062.   Local_Player_Connection->state = CSTATE_CONNECTED;
  1063.   Display_Player_Position();
  1064.  
  1065.   if (local_player_full_name != NULL)
  1066.     Send_fullname (Local_table, local_player_full_name);
  1067.   else if (strlen(User_fullname) > 0)
  1068.     Send_fullname (Local_table, User_fullname);
  1069.  
  1070.   if (local_player_email != NULL)
  1071.     Send_email (Local_table, local_player_email);
  1072. /*  Send_registry (Local_table, Registration); */
  1073. }
  1074.  
  1075. void Accept_new_connection ()
  1076. /* Given that a new connection is waiting to be accepted, makes
  1077.    the connection and begins processing for it.
  1078.  */
  1079. {
  1080.   Connection c;
  1081.   int fd_conn;  /* file descriptor for the connection. */
  1082.   struct sockaddr net_addr;
  1083.   int addrlen;
  1084. #ifdef DEBUG
  1085.   char error_buf[80];
  1086. #endif
  1087.  
  1088.   addrlen = sizeof(struct sockaddr);
  1089.   fd_conn = accept (listen_port, &net_addr, &addrlen);
  1090.   if (fd_conn < 0) {
  1091.     sprintf (socket_error, "Connection Error: %s", sys_errlist[errno]);
  1092.     Network_Comment (socket_error);
  1093.     return;
  1094.   }
  1095.  
  1096. #ifdef LOGFILE
  1097.   fprintf (net_log, "Connection established. fd %d.\n", fd_conn);
  1098.   fflush (net_log);
  1099. #endif
  1100.  
  1101.   c = Allocate_Connection ();
  1102.   c->local     = 0;
  1103.   c->channel   = fd_conn;
  1104.   c->spectator = 0;
  1105.   c->state     = CSTATE_CONNECTED;
  1106.   c->seat      = PLAYER_OBS;
  1107.   c->table     = Local_table;
  1108.   Link_Output_Connection (Local_table->Players, c);
  1109.  
  1110. #ifdef DEBUG
  1111.   sprintf (error_buf, "ACCEPTED A NEW CONNECTION FOR FD %d (%d).",
  1112.        c->channel, listen_port);
  1113.   Network_Comment (error_buf);
  1114. #endif
  1115.  
  1116. }
  1117.  
  1118. static void Get_network_message (c, channel)
  1119.      Connection c; int channel;
  1120. /* static void Get_network_message (Connection c) */
  1121. /* Gets a message from connection c, parses it, and processes it. */
  1122. {
  1123.   int buflen;                 /* return code from fd_readln */
  1124.   Message m;                  /* The message which was read from the
  1125.                  network. */
  1126.   char msg_buf[100];
  1127.  
  1128.   m = allocate_message ();
  1129.   buflen = fd_readln (channel, m->p.command_text, BUFFER_LENGTH);
  1130.  
  1131.   if (buflen <= 0) {
  1132.     deallocate_message (m);
  1133.     if (server_mode) {
  1134.       sprintf (msg_buf, "THE NETWORK CONNECTION WITH %s HAS BEEN LOST.",
  1135.            c->player_name);
  1136.       close_connection (c);
  1137.       Broadcast_Comment (msg_buf);
  1138.     } else {
  1139.       server_port = 0;
  1140.       Network_Comment 
  1141.     ("THE NETWORK CONNECTION WITH THE SERVER HAS BEEN LOST.");
  1142.       Generate_reset (RESET_DISCONNECT);
  1143.     }
  1144.   } else {
  1145.     m->source = c;
  1146.     if (server_mode) {
  1147.       Parse_Command_for_Server (&(m->p));
  1148.       m->p.player_no = c->seat;
  1149.     } else {
  1150.       Parse_Command_for_Client (&(m->p));
  1151.     }
  1152.  
  1153.     /* If we are receiving a BOARD or a RECORD message, then we must also
  1154.        recieve the associated in-line data. */
  1155.     if (m->p.command == CMD_BOARD)
  1156.       m->p.data.board.record = Receive_board (c);
  1157.     else if (m->p.command == CMD_RECORD)
  1158.       m->p.data.record.play = Receive_play_record (c);
  1159.  
  1160.     enqueue_message (c->table->protocol_queue, m);
  1161. #ifdef LOGFILE
  1162.   fprintf (net_log, "%2d < %s\n", channel, m->p.command_text);
  1163.   fflush (net_log);
  1164. #endif
  1165.   }
  1166. }
  1167.  
  1168. static void Wait_for_keyboard_event ()
  1169. {
  1170.   int status;                 /* return code from Select call. */
  1171.   struct fd_set wait_set;     /* A set representing the connections that
  1172.                  have been established. */
  1173.  
  1174.   do {
  1175.     FD_ZERO (&wait_set);
  1176.     FD_SET (fileno(stdin), &wait_set);
  1177.   
  1178.     if (GPS_request_in_progress && (GPS_socket > 0))
  1179.       FD_SET (GPS_socket, &wait_set);
  1180.     
  1181.     status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0,
  1182.              (struct timeval *) 0);
  1183.  
  1184.     if ((status < 0) && (errno != EINTR)) {
  1185.       sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
  1186.       Network_Comment (socket_error);
  1187.     }
  1188.   } while (status < 0);
  1189. }
  1190.  
  1191. static void Client_wait_for_network_event ()
  1192. {
  1193.   int status;                 /* return code from Select call. */
  1194.   struct fd_set wait_set;     /* A set representing the connections that
  1195.                  have been established. */
  1196.  
  1197.   do {
  1198.     FD_ZERO (&wait_set);
  1199.     FD_SET (fileno(stdin), &wait_set);
  1200.     FD_SET (server_port,   &wait_set);
  1201.  
  1202.     if (GPS_request_in_progress && (GPS_socket > 0))
  1203.       FD_SET (GPS_socket, &wait_set);
  1204.     
  1205.     status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0, 
  1206.              (struct timeval *) 0);
  1207.   
  1208.     if ((status < 0) && (errno != EINTR)) {
  1209.       sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
  1210.       Network_Comment (socket_error);
  1211.     }
  1212.   } while (status < 0);
  1213.  
  1214.   if (FD_ISSET(server_port, &wait_set))
  1215.     Get_network_message (Local_Player_Connection, server_port);
  1216. }
  1217.  
  1218. static void Server_wait_for_network_event ()
  1219. {
  1220.   Connection c, d;
  1221.   int status;                 /* return code from Select call. */
  1222.   struct fd_set wait_set;     /* A set representing the connections that
  1223.                  have been established. */
  1224.   int connection_available, data_available;
  1225.  
  1226.   data_available = 0;
  1227.   do {
  1228.     FD_ZERO (&wait_set);
  1229.     
  1230.     /* Set bits in the wait_set corresponding to the open socket 
  1231.        descriptors which we have at the moment. */
  1232.     FOREACH_CONNECTION (c) {
  1233.       if (!c->local)
  1234.     FD_SET (c->channel, &wait_set);
  1235.     }
  1236.     
  1237.     FD_SET (fileno(stdin), &wait_set);
  1238.     if (listen_port > 0)
  1239.       FD_SET (listen_port, &wait_set);
  1240.  
  1241.     if (GPS_request_in_progress && (GPS_socket > 0))
  1242.       FD_SET (GPS_socket, &wait_set);
  1243.     
  1244.     status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0, 
  1245.              (struct timeval *) 0);
  1246.  
  1247.     connection_available = 0;
  1248.     if (status < 0) {
  1249.       if (errno != EINTR) {
  1250.     sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
  1251.     Network_Comment (socket_error);
  1252.       }
  1253.       data_available = 0;
  1254.     } else {
  1255.       connection_available = ((listen_port > 0) 
  1256.                   && FD_ISSET(listen_port, &wait_set));
  1257.       if (connection_available)
  1258.     data_available = status - 1;
  1259.       else
  1260.     data_available = 1;
  1261.     } 
  1262.  
  1263.     if (connection_available)
  1264.       Accept_new_connection ();
  1265.  
  1266.   } while (!data_available);
  1267.  
  1268.   c = Connections->inext;
  1269.   while (c != NULL) {
  1270.     d = c->inext;
  1271.     if (!c->local && FD_ISSET(c->channel, &wait_set)) {
  1272.     FD_CLR(c->channel, &wait_set);
  1273.     Get_network_message (c, c->channel);
  1274.       }
  1275.     c = d;
  1276.   }
  1277.  
  1278. }
  1279.  
  1280. void Wait_for_network_event ()
  1281. /* Waits for an input event to occur.  If a network event occurs, then
  1282.    parses the message and places it onto the proper player queue.
  1283. */
  1284. {
  1285.   if (server_mode)
  1286.     Server_wait_for_network_event ();
  1287.   else if (client_mode)
  1288.     Client_wait_for_network_event ();
  1289.   else
  1290.     Wait_for_keyboard_event ();
  1291.  
  1292. #ifdef MDEBUG
  1293.   if (!malloc_verify ()) {
  1294.     Moderator_Comment ("A MEMORY ALLOCATION ERROR HAS BEEN DETECTED!");
  1295.     access_error_routine ();
  1296.   }
  1297. #endif
  1298. }
  1299.  
  1300.