home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume15 / xstratego / part02 / socket.c < prev    next >
C/C++ Source or Header  |  1993-01-27  |  6KB  |  259 lines

  1. /*
  2.  * Socket.h
  3.  *
  4.  * Initial handshake and pecking order determination module.
  5.  */
  6.  
  7. #include "stratego.h"
  8.  
  9. #include <signal.h>
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <fcntl.h>
  13. #include <netinet/in.h>
  14. #include <netdb.h>
  15.  
  16. static struct sockaddr_in channel;
  17.  
  18. static void read_player_data (), write_player_data ();
  19. static void read_data (), write_data ();
  20.  
  21. static void perror_exit (label)
  22. char *label;
  23. {
  24.     perror (label);
  25.     exit (-1);
  26. }
  27.  
  28. static int generate_port (name)
  29. char *name;
  30. {
  31.     int port = 1;
  32.  
  33.     while (*name != '\0')
  34.         port *= (*name++ & 0xFF);
  35.  
  36.     return (port & ~0x8000) | 0x4000;
  37. }
  38.  
  39. static void setup_channel (machine, port_name)
  40. char *machine;
  41. char *port_name;
  42. {
  43.     struct hostent *hostentry;
  44.  
  45.     if ((hostentry = gethostbyname (machine)) == NULL) {
  46.         fprintf (stderr, "%s: No such host\n", machine);
  47.         exit (-1);
  48.     }
  49.  
  50.     channel.sin_family = AF_INET;
  51.     channel.sin_port   = htons (generate_port (port_name));
  52.     channel.sin_addr   = (*(struct in_addr *) hostentry->h_addr);
  53. }
  54.  
  55. static int connect_socket (machine, port_name)
  56. char *machine;
  57. char *port_name;
  58. {
  59.     int s, retries;
  60.  
  61.     setup_channel (machine, port_name);
  62.  
  63.     for (retries = 60; retries > 0; retries--) {
  64.         if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  65.             perror_exit ("connect_socket: socket()");
  66.  
  67.         if (connect (s, (struct sockaddr *) &channel, sizeof (channel))
  68.             >=0) break;
  69.  
  70.         sleep (2);
  71.         close(s);
  72.     }
  73.  
  74.     return retries ? s : -1;
  75. }
  76.  
  77. static int make_socket (machine, port_name)
  78. char *machine;
  79. char *port_name;
  80. {
  81.     int s, size;
  82.     struct sockaddr_in get_chan;
  83.  
  84.     setup_channel (machine, port_name);
  85.  
  86.     if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  87.         perror_exit ("make_socket: socket()");
  88.  
  89.     if (bind (s, (struct socketaddr *) &channel, sizeof (channel)) < 0)
  90.         return -1;
  91.  
  92.     if (listen (s, 1) < 0)
  93.         perror_exit ("make_socket: listen()");
  94.  
  95.     size = sizeof (get_chan);
  96.     if ((s = accept (s, &get_chan, &size)) < 0)
  97.         perror_exit ("make_socket: accept()");
  98.  
  99.     return s;
  100. }
  101.  
  102. void setup_communication (name, opponent, machine)
  103. char *name, *opponent, *machine;
  104. {
  105.     struct hostent *hostentry;
  106.     char new_port[20];
  107.     int fd, cmp;
  108.     Boolean master;
  109.     char *port, *ptr;
  110.     time_t start;
  111.  
  112.     strcpy (players[0].name, name);
  113.     strcpy (players[0].login, cuserid (NULL));
  114.  
  115.     if (gethostname (players[0].machine, MAXHOSTNAMELEN) < 0)
  116.         perror_exit ("Can't find your machine name.\n");
  117.  
  118. /* Strip domain name from machine name (if any) */
  119.     for (ptr = players[0].machine; *ptr != '\0' && *ptr != '.'; ptr++)
  120.         ;
  121.     *ptr = '\0';
  122.  
  123.     if (getdomainname (players[0].domain, NAME_LENGTH) < 0)
  124.         perror_exit ("Can't find your domain name.\n");
  125.  
  126.     if ((hostentry = gethostbyname (machine)) == NULL)
  127.         perror_exit ("Can't find opponents machine name.\n");
  128.     
  129.     strcpy  (players[1].login, opponent);
  130.     strncpy (players[1].machine, hostentry->h_name, MAXHOSTNAMELEN);
  131.     players[1].machine[MAXHOSTNAMELEN - 1] = '\0';
  132.  
  133. /* Strip domain name from machine name (if any) */
  134.     for (ptr = players[1].machine; *ptr != '\0' && *ptr != '.'; ptr++)
  135.         ;
  136.     *ptr = '\0';
  137.  
  138.     if ((cmp = strcmp (players[0].login, players[1].login)) == 0)
  139.         cmp = strcmp (players[0].machine, players[1].machine);
  140.  
  141.     master  = (cmp <= 0) ? True : False;
  142.  
  143.     if (master == True) {
  144.         machine = players[0].machine;
  145.         port    = players[0].login;
  146.  
  147.         printf ("Waiting for response from \"%s@%s\"...",
  148.             players[1].login, players[1].machine);
  149.         fflush (stdout);
  150.         if ((fd = make_socket (machine, port)) < 0) {
  151.             if (cmp != 0)
  152.                 perror_exit ("Cannot setup communications channel to opponent");
  153.             master = False;
  154.         }
  155.     }
  156.  
  157.     if (master == False) {
  158.         machine = players[1].machine;
  159.         port    = players[1].login;
  160.  
  161.         printf ("Connecting to \"%s@%s\"...", port, machine);
  162.         fflush (stdout);
  163.         if ((fd = connect_socket (machine, port)) < 0)
  164.             perror_exit ("Cannot setup communications channel to opponent");
  165.     }
  166.  
  167.     printf ("\n\nConnected.\n");
  168.     fflush (stdout);
  169.  
  170.     if (master == False) {
  171.         read_data (fd, new_port, sizeof (new_port));
  172.         close (fd);
  173.  
  174.         start = time (NULL);
  175.         do {
  176.             fd = connect_socket (machine, new_port);
  177.         } while (fd == -1 && time (NULL) < start + 5);
  178.  
  179.         if (fd == -1)
  180.             perror_exit ("Cannot reconnect to opponent");
  181.  
  182.         write_player_data (fd, &players[0]);
  183.         read_player_data  (fd, &players[1]);
  184.         players[0].has_first_move = !players[1].has_first_move;
  185.     }
  186.     else {
  187.         sprintf (new_port, "comm%u", time(0));
  188.         write_data (fd, new_port, sizeof (new_port));
  189.         close (fd);
  190.  
  191.         if ((fd = make_socket (machine, new_port)) < 0)
  192.             perror_exit ("Cannot recontact opponent");
  193.  
  194.         srand ((time (NULL) ^ getpid ()) >> 3);
  195.         players[0].has_first_move = (rand () >> 4) & 0x01;
  196.  
  197.         read_player_data  (fd, &players[1]);
  198.         write_player_data (fd, &players[0]);
  199.     }
  200.  
  201.     players[1].fd = fd;
  202.  
  203.     signal (SIGIO, SIG_IGN);
  204.     fcntl (fd, F_SETFL, FASYNC);
  205.     fcntl (fd, F_SETOWN, getpid ());
  206. }
  207.  
  208. static void read_player_data (fd, player)
  209. int fd;
  210. PLAYER *player;
  211. {
  212.     read_data (fd, player->name,    sizeof (player->name));
  213.     read_data (fd, player->login,    sizeof (player->login));
  214.     read_data (fd, player->machine,    sizeof (player->machine));
  215.     read_data (fd, player->domain,    sizeof (player->domain));
  216.     read_data (fd, &player->has_first_move, sizeof (player->has_first_move));
  217. }
  218.  
  219. static void write_player_data (fd, player)
  220. int fd;
  221. PLAYER *player;
  222. {
  223.     write_data (fd, player->name,     sizeof (player->name));
  224.     write_data (fd, player->login,     sizeof (player->login));
  225.     write_data (fd, player->machine, sizeof (player->machine));
  226.     write_data (fd, player->domain,     sizeof (player->domain));
  227.     write_data (fd, &player->has_first_move, sizeof(player->has_first_move));
  228. }
  229.  
  230. static void read_data (fd, output, length)
  231. int fd, length;
  232. char *output;
  233. {
  234.     int bytes;
  235.  
  236.     if ((bytes = read (fd, output, length)) != length) {
  237.         fprintf (stderr, "Read %d instead of %d bytes.\n", bytes,
  238.              length);
  239.         perror_exit ("read_data: read()");
  240.     }
  241. }
  242.  
  243. static void write_data (fd, input, length)
  244. int fd, length;
  245. char *input;
  246. {
  247.     while (length > 0) {
  248.         int r, persist = 30;
  249.  
  250.         while ((r = write (fd, input, length)) < 0) {
  251.             if (--persist == 0)
  252.                 perror_exit ("write_data: write()");
  253.             sleep (2);
  254.         }
  255.         input  += r;
  256.         length -= r;
  257.     }
  258. }
  259.