home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume2 / nchess / part03 / ipc.c < prev    next >
C/C++ Source or Header  |  1987-11-25  |  16KB  |  652 lines

  1. /*
  2.  * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
  3.  * Stanwood, WA  98282.   All rights reserved.
  4.  */
  5.  
  6. /*
  7.  * manage communication with the peer chess tool, if one exists.
  8.  * some communication functions with a background chess process are
  9.  * relayed by functions in this file.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <rpc/rpc.h>
  14. #include <strings.h>
  15. #include <errno.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <pwd.h>
  19. #include <signal.h>
  20.  
  21. #include "nchess.h"
  22.  
  23. unsigned long MyProgNum = (u_long) 0;    /* my program number */
  24. unsigned long PeerProgNum;        /* program number of peer */
  25. char * PeerHostName;            /* host name of peer */
  26. char * PeerUserName;            /* user name of peer */
  27. BOOL peerDead = FALSE;            /* peer connection lost or chess program died */
  28.  
  29. BOOL UndoWanted = FALSE;        /* undo was requested locally */
  30. BOOL RestoringGame = FALSE;        /* restoring a saved game via the peer */
  31. SVCXPRT * Xprt;                /* RPC service transport handle */
  32.  
  33. /* 
  34.  * get a transient program number 
  35.  */
  36. unsigned long
  37. getTransient(vers, sockp)
  38.     unsigned long vers; 
  39.     int * sockp;
  40. {
  41.     unsigned long progNum = 0x52000000L;
  42.     int s, len;
  43.     struct sockaddr_in addr;
  44.  
  45.     /* create a socket */
  46.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  47.     fprintf(stderr, "can't create a socket\n");
  48.     exit(1);
  49.     }
  50.     * sockp = s;
  51.     addr.sin_addr.s_addr = 0;
  52.     addr.sin_family = AF_INET;
  53.     addr.sin_port = 0;
  54.     len = sizeof(addr);
  55.     bind(s, (struct sockaddr *) &addr, len);
  56.     if (getsockname(s, (caddr_t) &addr, &len) < 0) {
  57.     fprintf(stderr, "getsockname failed\n");
  58.     exit(1);
  59.     }
  60.     /* now find and reserve an available transient program number */
  61.     while ( ! pmap_set(progNum++, vers, IPPROTO_UDP, addr.sin_port))
  62.     continue;
  63.     return(progNum - 1);
  64. }
  65.  
  66. /*
  67.  * timed out the peer
  68.  */
  69. void 
  70. peerDied()
  71. {
  72.     Message("Lost connection to your opponent");
  73.     peerDead = GameOver = TRUE;
  74.     Mouse = LOCKED;
  75. }
  76.  
  77. /*
  78.  * RPC procedure dispatch routine
  79.  */
  80. void
  81. dispatch(request, xprt)
  82.     struct svc_req * request;
  83.     SVCXPRT * xprt;
  84. {
  85.     Move move;
  86.     SetupChange setup;
  87.     GameRequest gr;
  88.     char ans[80];
  89.     int isUndoOK;
  90.  
  91.     switch (request->rq_proc) {
  92.     /* 
  93.      * are you there? 
  94.      */
  95.     case NULLPROC:
  96.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  97.         fprintf(stderr, "can't reply to remote peer\n");
  98.         exit(1);
  99.     }
  100.     break;
  101.     /*  
  102.      * game invitation accepted 
  103.      */
  104.     case ACCEPTPROCNUM:
  105.     if ( ! svc_getargs(xprt, XdrGameReq, &gr)) {
  106.         svcerr_decode(xprt);
  107.         exit(1);
  108.     }
  109.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  110.         fprintf(stderr, "can't reply to remote peer\n");
  111.         exit(1);
  112.     }
  113.     PeerProgNum = gr.progNum;
  114.     PeerColor = gr.color;
  115.     if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
  116.         switch(MyColor) {
  117.         /* I don't care - pick a color based on what the peer wants */
  118.         case EITHERCOLOR:
  119.         switch(PeerColor) {
  120.         case WANTSBLACK:
  121.             MyColor = WANTSWHITE;
  122.             break;
  123.         case WANTSWHITE:
  124.             MyColor = WANTSBLACK;
  125.             break;
  126.         default:
  127.             fprintf(stderr, "color arbitration botch\n");
  128.             exit(1);
  129.         }
  130.         break;
  131.         case WANTSBLACK:
  132.         if (PeerColor == WANTSBLACK) {
  133.             printf("Your opponent insists on playing black - is that OK? ");
  134.             scanf("%s", ans);
  135.             if (ans[0] == 'y' || ans[0] == 'Y') 
  136.             MyColor = WANTSWHITE;
  137.             else {
  138.             fprintf(stderr, "couldn't agree on colors - bye\n");
  139.             (void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
  140.                 xdr_void, (caddr_t) 0,
  141.                 xdr_void, (caddr_t) 0);
  142.             exit(1);
  143.             }
  144.         }
  145.         break;
  146.         case WANTSWHITE:
  147.         if (PeerColor == WANTSWHITE) {
  148.             printf("Your opponent insists on playing white - is that OK? ");
  149.             scanf("%s", ans);
  150.             if (ans[0] == 'y' || ans[0] == 'Y') 
  151.             MyColor = WANTSBLACK;
  152.             else {
  153.             fprintf(stderr, "couldn't agree on colors - bye\n");
  154.             (void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
  155.                 xdr_void, (caddr_t) 0,
  156.                 xdr_void, (caddr_t) 0);
  157.             exit(1);
  158.             }
  159.         }
  160.         break;
  161.         }
  162.     }
  163.     break;
  164.     /* 
  165.      * the other player didn't ameliorate our insistence on color 
  166.      */
  167.     case COLORFAILPROCNUM:
  168.     fprintf(stderr, "couldn't agree on colors - bye\n");
  169.     (void) svc_sendreply(xprt, xdr_void, (caddr_t) 0);
  170.     exit(1);
  171.     /* 
  172.      * receive a move from the other player 
  173.      */
  174.     case MOVEPROCNUM:
  175.     if ( ! svc_getargs(xprt, XdrMove, &move)) {
  176.         fprintf(stderr, "can't get RPC args\n");
  177.         exit(1);
  178.     }
  179.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  180.         peerDied();
  181.     } else {
  182.         DoMove(&move, TRUE); 
  183.         Turn = MyColor;
  184.         Flashing = TRUE;
  185.         if (Mouse != CONFIRMING)
  186.         WhoseMoveMessage((char *) 0);
  187.     }
  188.     break;
  189.     /* 
  190.      * receive a setup change from the other player 
  191.      */
  192.     case SETUPPROCNUM:
  193.     if ( ! svc_getargs(xprt, XdrSetup, &setup)) {
  194.         fprintf(stderr, "can't get RPC args\n");
  195.         exit(1);
  196.     }
  197.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  198.         peerDied();
  199.     } else {
  200.         DoSetupChange(&setup);
  201.     }
  202.     break;
  203.     /* 
  204.      * receive a restoration move from the other player's process
  205.      */
  206.     case RESTOREMOVEPROCNUM:
  207.     if ( ! svc_getargs(xprt, XdrMove, &move)) {
  208.         fprintf(stderr, "can't get RPC args\n");
  209.         exit(1);
  210.     }
  211.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  212.         peerDied();
  213.     } else {
  214.         DoMove(&move, TRUE); 
  215.         Turn = OTHERCOLOR(Turn);
  216.     }
  217.     break;
  218.     /*
  219.      * restoration complete 
  220.      */
  221.     case ENDRESTOREPROCNUM:
  222.     if ( ! svc_getargs(xprt, xdr_int, &Turn)) {
  223.         fprintf(stderr, "can't get RPC args\n");
  224.         exit(1);
  225.     }
  226.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  227.         peerDied();
  228.     } else {
  229.         WhoseMoveMessage((char *) 0);
  230.         RestoringGame = FALSE;
  231.         Mouse = IDLE;    /* unlock the mouse */
  232.         Flashing = (Turn == MyColor);
  233.     }
  234.     break;
  235.     /* 
  236.      * other player wants to undo his previous move 
  237.      */
  238.     case UNDOPROCNUM:
  239.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  240.         peerDied();
  241.     } else {
  242.         RequestUndo();
  243.         Flashing = TRUE;
  244.     }
  245.     break;
  246.     /*
  247.      * the other player blew away his tool.
  248.      */
  249.     case GOODBYEPROCNUM:
  250.     svc_sendreply(xprt, xdr_void, (caddr_t) 0);
  251.     KillMouseActivity();
  252.     peerDead = GameOver = TRUE;
  253.     Mouse = LOCKED;
  254.     Message("Your opponent killed his tool process");
  255.     break;
  256.     /*
  257.      * other player is acknowledging our request to undo.
  258.      */
  259.     case UNDOACKPROCNUM:
  260.     if ( ! svc_getargs(xprt, xdr_int, &isUndoOK)) {
  261.         fprintf(stderr, "can't get RPC args\n");
  262.         exit(1);
  263.     }
  264.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  265.         peerDied();
  266.     } else {
  267.         if (isUndoOK) {
  268.         UnDoMove();
  269.         if (Turn == MyColor)
  270.             UnDoMove();
  271.         else
  272.             Turn = MyColor;
  273.         WhoseMoveMessage("Undo accepted");
  274.         } else {
  275.         WhoseMoveMessage("Undo refused");
  276.         }
  277.         UndoWanted = FALSE;
  278.         Mouse = IDLE;
  279.         Flashing = TRUE;
  280.     }
  281.     break;
  282.     /*
  283.      * other player resigned 
  284.      */
  285.     case RESIGNPROCNUM:
  286.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0))
  287.         peerDead = TRUE;
  288.     Message(PeerColor == BLACK ? "Black resigns" : "White resigns");
  289.     KillMouseActivity();
  290.     Mouse = LOCKED;        /* game is over */
  291.     DoResignation(OTHERCOLOR(MyColor));
  292.     Flashing = TRUE;
  293.     break;
  294.     case MSGPROCNUM:
  295.     if ( ! svc_getargs(xprt, XdrString, ans)) {
  296.         fprintf(stderr, "can't get RPC args\n");
  297.         exit(1);
  298.     }
  299.     if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
  300.         peerDied();
  301.     } else {
  302.         RecvTalkMsg(ans);
  303.         Flashing = TRUE;
  304.     }
  305.     break;
  306.     }
  307. }
  308.  
  309.  
  310. /*
  311.  * outstanding invitation - shared by InitRPC() and quitEarly().
  312.  */
  313. GameRequest gr;
  314.  
  315. /*
  316.  * cancel our invitation with the remote daemon if we receive a signal
  317.  * before the invitee responds.
  318.  */
  319. quitEarly()
  320. {
  321.     callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, CANCELPROCNUM, 
  322.     XdrGameReq, (caddr_t) &gr, 
  323.     xdr_void, (caddr_t) 0);
  324.     exit(1);
  325. }
  326.  
  327. /*
  328.  * initialize the RPC connection, using the user's "user@host" arg.
  329.  */
  330. void
  331. InitRPC(cp, progName)
  332.     char * cp, * progName;
  333. {
  334.     GameRequest gr2;
  335.     int sock, rfds; 
  336.     char localHostName[256], ans[80];
  337.     BOOL resumeGame = FALSE;
  338.  
  339.     /*
  340.      * decipher the remote host and user strings 
  341.      */
  342.     if (cp == (char *) 0 || (PeerHostName = index(cp, '@')) == (char *) 0) {
  343.     fprintf(stderr, "%s: illegal/non-existent user@host arg\n", progName);
  344.     exit(1);
  345.     }
  346.     *PeerHostName++ = '\0';
  347.     PeerUserName = cp;
  348.     /* 
  349.      * determine the local host and user names 
  350.      */
  351.     if (gethostname(localHostName, sizeof(localHostName)) != 0) {
  352.     fprintf(stderr, "%s: can't determine local host name\n", progName);
  353.     exit(1);
  354.     }
  355.     /*
  356.      * generate the transient RPC program number used by this player.
  357.      */
  358.     MyProgNum = getTransient(VERSNUM, &sock);
  359.     if ((Xprt = svcudp_create(sock)) == (SVCXPRT *) 0) {
  360.     fprintf(stderr, "svcudp_create failed\n");
  361.     exit(1);
  362.     }
  363.     /*
  364.      * register the peer-to-peer RPC dispatch procedure
  365.      */
  366.     (void) svc_register(Xprt, MyProgNum, VERSNUM, dispatch, 0L);
  367.     /*
  368.      * check for an invitation registered with the local chess
  369.      * daemon, indicating that we are responding to an invitation.
  370.      */
  371.     (void) strcpy(gr.userName, PeerUserName);
  372.     (void) strcpy(gr.hostName, PeerHostName);
  373.     if (callrpc(localHostName, SERVERPROGNUM, VERSNUM, ACKPROCNUM,
  374.     XdrGameReq, (caddr_t) &gr, 
  375.     XdrGameReq, (caddr_t) &gr2) != 0) 
  376.     {
  377.     fprintf(stderr, "error: callrpc of local daemon (%s)\n", localHostName);
  378.     exit(1);
  379.     }
  380.     PeerProgNum = gr2.progNum;
  381.     PeerColor = gr2.color;
  382.     resumeGame = gr2.resumeGame;
  383.     do {
  384.     /* 
  385.      * if no invitation was registered or the remote program 
  386.      * is no longer running,
  387.      *      then register an invitation with the remote daemon.
  388.      */
  389.     if (PeerProgNum == 0L
  390.     || callrpc(PeerHostName, PeerProgNum, VERSNUM, NULLPROC, 
  391.         xdr_void, (caddr_t) 0, 
  392.         xdr_void, (caddr_t) 0) != 0) 
  393.     {
  394.         gr.progNum = MyProgNum;
  395.         gr.color = MyColor;
  396.         gr.resumeGame = (RestoreFile != (FILE *) 0 || SetupMode);
  397.         (void) strcpy(gr.userName, UserPWEntry->pw_name);
  398.         (void) strcpy(gr.hostName, localHostName);
  399.         signal(SIGINT, quitEarly);
  400.         signal(SIGQUIT, quitEarly);
  401.         signal(SIGHUP, quitEarly);
  402.         if (callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, REQPROCNUM, 
  403.         XdrGameReq, (caddr_t) &gr, 
  404.         xdr_void, (caddr_t) 0) != 0) 
  405.         {
  406.         fprintf(stderr, "error: callrpc of remote daemon\n");
  407.         exit(1);
  408.         }
  409.         printf("waiting for %s to respond...\n", PeerUserName);
  410.         /* 
  411.          * wait for the remote peer to send us his program number and color 
  412.          */
  413.         do {
  414.         rfds = svc_fds;
  415.         switch(select(32, &rfds, (int *) 0, (int *) 0, (struct timeval *) 0)) {
  416.         case -1:
  417.             if (errno == EINTR)
  418.             continue;
  419.             fprintf(stderr, "RPC select botch\n");
  420.             exit(1);
  421.         case 0:
  422.             break;
  423.         default:
  424.             svc_getreq(rfds);
  425.             break;
  426.         }
  427.         } while(PeerProgNum == 0L);
  428.         signal(SIGINT, SIG_DFL);
  429.         signal(SIGQUIT, SIG_DFL);
  430.         signal(SIGHUP, SIG_DFL);
  431.     }
  432.     /*
  433.      * else accept the invitation, sending the remote program 
  434.      * our program number and color.
  435.      */
  436.     else {
  437.         if (resumeGame) {
  438.         MyColor = EITHERCOLOR;
  439.         RestoringGame = TRUE;
  440.         SetupMode = FALSE;
  441.         }
  442.         /* try to pre-arrange colors */
  443.         if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
  444.         switch(MyColor) {
  445.         /* I don't care - pick a color based on what the peer wants */
  446.         case EITHERCOLOR:
  447.             switch(PeerColor) {
  448.             case EITHERCOLOR:
  449.             MyColor = (random() & 0x01) ? WANTSBLACK : WANTSWHITE;
  450.             break;
  451.             case WANTSBLACK:
  452.             MyColor = WANTSWHITE;
  453.             break;
  454.             case WANTSWHITE:
  455.             MyColor = WANTSBLACK;
  456.             break;
  457.             }
  458.             break;
  459.         case WANTSBLACK:
  460.             if (PeerColor == WANTSBLACK) {
  461.             printf("%s also wants to play black - is that OK? ", PeerUserName);
  462.             scanf("%s", ans);
  463.             if (ans[0] == 'y' || ans[0] == 'Y') 
  464.                 MyColor = WANTSWHITE;
  465.             }
  466.             break;
  467.         case WANTSWHITE:
  468.             if (PeerColor == WANTSWHITE) {
  469.             printf("%s also wants to play white - is that OK? ", PeerUserName);
  470.             scanf("%s", ans);
  471.             if (ans[0] == 'y' || ans[0] == 'Y') 
  472.                 MyColor = WANTSBLACK;
  473.             }
  474.             break;
  475.         }
  476.         }
  477.         gr.progNum = MyProgNum;
  478.         gr.color = MyColor;
  479.         if (callrpc(PeerHostName, PeerProgNum, VERSNUM, ACCEPTPROCNUM, 
  480.         XdrGameReq, (caddr_t) &gr, 
  481.         xdr_void, (caddr_t) 0) != 0)
  482.         {
  483.         PeerProgNum = 0L;
  484.         }
  485.     }
  486.     } while(PeerProgNum == 0L);
  487.     PeerColor = OTHERCOLOR(MyColor);
  488.     PlayerName[MyColor] = UserPWEntry->pw_name;
  489.     PlayerName[PeerColor] = PeerUserName;
  490.     /*
  491.      * if the other player is shipping us the game state, lock the
  492.      * mouse in the meantime.
  493.      */
  494.     if (RestoringGame)
  495.     Mouse = LOCKED;
  496. }
  497.  
  498. /*
  499.  * send a move to the 'color' player
  500.  */
  501. BOOL
  502. SendMove(move, color)
  503.     Move * move;
  504.     int color;
  505. {
  506.     if ( ! peerDead) {
  507.     if (IsMachine[color]) {
  508.         SendMachineMove(move, color);
  509.     } else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, MOVEPROCNUM,
  510.         XdrMove, (caddr_t) move, 
  511.         xdr_void, (caddr_t) 0) != 0) 
  512.     {
  513.         peerDied();
  514.     }
  515.     }
  516.     return( ! peerDead);
  517. }
  518.  
  519. void
  520. SendRestoreMove(move, color)
  521.     Move * move;
  522.     int color;
  523. {
  524.     if ( ! IsMachine[color] 
  525.     && ! peerDead
  526.     && callrpc(PeerHostName, PeerProgNum, VERSNUM, RESTOREMOVEPROCNUM,
  527.     XdrMove, (caddr_t) move, 
  528.     xdr_void, (caddr_t) 0) != 0)
  529.     {
  530.     peerDied();
  531.     }
  532. }
  533.  
  534. void
  535. SendEndRestore()
  536. {
  537.     if ( ! peerDead
  538.     && callrpc(PeerHostName, PeerProgNum, VERSNUM, ENDRESTOREPROCNUM,
  539.     xdr_int, (caddr_t) &Turn, 
  540.     xdr_void, (caddr_t) 0) != 0)
  541.     {
  542.     peerDied();
  543.     }
  544. }
  545.  
  546. void
  547. SendUndoRequest(color)
  548.     int color;
  549. {
  550.     if ( ! peerDead) {
  551.     if (IsMachine[color]) {
  552.         if (Turn != MyColor) {
  553.         Message("Will undo after machine moves...");
  554.         } else {
  555.         MachineUndo(color);
  556.         UndoWanted = FALSE;
  557.         Mouse = IDLE;
  558.         }
  559.     } else {
  560.         Message("Sending undo request to your opponent (please wait)...");
  561.         if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOPROCNUM,
  562.         xdr_void, (caddr_t) 0, 
  563.         xdr_void, (caddr_t) 0) != 0)
  564.         {
  565.         peerDied();
  566.         }
  567.     }
  568.     }
  569. }
  570.  
  571. void
  572. SendResignation(color)
  573.     int color;
  574. {
  575.     if ( ! peerDead) {
  576.     if (IsMachine[color]) {
  577.         KillChessProcesses();
  578.     } else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, RESIGNPROCNUM,
  579.         xdr_void, (caddr_t) 0, 
  580.         xdr_void, (caddr_t) 0) != 0)
  581.     {
  582.         peerDied();
  583.     }
  584.     }
  585. }
  586.  
  587. void
  588. SendTalkMsg(cp)
  589.     char * cp;
  590. {
  591.     if ( ! peerDead
  592.     && callrpc(PeerHostName, PeerProgNum, VERSNUM, MSGPROCNUM,
  593.     XdrString, (caddr_t) cp, 
  594.     xdr_void, (caddr_t) 0) != 0)
  595.     {
  596.     peerDied();
  597.     }
  598. }
  599.  
  600. void
  601. SendSetupChange(setup, color)
  602.     SetupChange * setup;
  603.     int color;
  604. {
  605.     if ( ! IsMachine[color] 
  606.     && ! peerDead
  607.     && callrpc(PeerHostName, PeerProgNum, VERSNUM, SETUPPROCNUM,
  608.     XdrSetup, (caddr_t) setup, 
  609.     xdr_void, (caddr_t) 0) != 0)
  610.     {
  611.     peerDied();
  612.     }
  613. }
  614.  
  615. void
  616. SendUndoAcknowledgement(isUndoOK)
  617.     int isUndoOK;
  618. {
  619.     if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOACKPROCNUM,
  620.     xdr_int, (caddr_t) &isUndoOK, 
  621.     xdr_void, (caddr_t) 0) != 0)
  622.     {
  623.     peerDied();
  624.     } else if (isUndoOK) {
  625.     UnDoMove();
  626.     if (Turn == MyColor) 
  627.         Turn = OTHERCOLOR(MyColor);
  628.     else 
  629.         UnDoMove();
  630.     Message(MyColor == WHITE ?
  631.         "Waiting for black to re-play..." :
  632.         "Waiting for white to re-play...");
  633.     } else 
  634.     WhoseMoveMessage((char *) 0);
  635. }
  636.  
  637. void
  638. SendGoodbye()
  639. {
  640.     if ( ! IsMachine[PeerColor] && ! peerDead) {
  641.     callrpc(PeerHostName, PeerProgNum, VERSNUM, GOODBYEPROCNUM,
  642.         xdr_void, (caddr_t) 0,
  643.         xdr_void, (caddr_t) 0);
  644.     }
  645.     if (MyProgNum != 0) {
  646.     /* unregister the RPC transport handle */
  647.     xprt_unregister(Xprt);
  648.     /* release my program number for re-use */
  649.     pmap_unset(MyProgNum, VERSNUM);
  650.     }
  651. }
  652.