Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-lcc!mordor!sri-spam!sri-unix!hplabs!pesnta!amd!intelca!mipos3!omepd!psu-cs!reed!tektronix!uw-beaver!fluke!toma From: toma@tc.fluke.COM (Tom Anderson) Newsgroups: net.sources.games Subject: network chess (4 of 5) Message-ID: <259@spock.tc.fluke.COM> Date: Thu, 8-Jan-87 18:51:44 EST Article-I.D.: spock.259 Posted: Thu Jan 8 18:51:44 1987 Date-Received: Thu, 15-Jan-87 19:49:46 EST Organization: John Fluke Mfg. Co., Inc., Everett, WA Lines: 940 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by spock!toma on Thu Jan 8 14:33:58 PST 1987 # Contents: ipc.c tool.c controlsw.c echo x - ipc.c sed 's/^@//' > "ipc.c" <<'@//E*O*F ipc.c//' /* * manage communication with the peer chess tool, if one exists. * some communication functions with a background chess process are * relayed by functions in this file. */ #include#include #include #include #include #include #include #include #include "nchess.h" unsigned long MyProgNum = (u_long) 0; /* my program number */ unsigned long PeerProgNum; /* program number of peer */ char * PeerHostName; /* host name of peer */ char * PeerUserName; /* user name of peer */ BOOL peerDead = FALSE; /* peer connection lost or chess program died */ BOOL UndoWanted = FALSE; /* undo was requested locally */ BOOL RestoringGame = FALSE; /* restoring a saved game via the peer */ SVCXPRT * Xprt; /* RPC service transport handle */ /* * get a transient program number */ unsigned long getTransient(vers, sockp) unsigned long vers; int * sockp; { unsigned long progNum = 0x52000000L; int s, len; struct sockaddr_in addr; /* create a socket */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr, "can't create a socket\n"); exit(1); } * sockp = s; addr.sin_addr.s_addr = 0; addr.sin_family = AF_INET; addr.sin_port = 0; len = sizeof(addr); bind(s, (struct sockaddr *) &addr, len); if (getsockname(s, (caddr_t) &addr, &len) < 0) { fprintf(stderr, "getsockname failed\n"); exit(1); } /* now find and reserve an available transient program number */ while ( ! pmap_set(progNum++, vers, IPPROTO_UDP, addr.sin_port)) continue; return(progNum - 1); } /* * timed out the peer */ void peerDied() { Message("Lost connection to your opponent"); peerDead = GameOver = TRUE; Mouse = LOCKED; } /* * RPC procedure dispatch routine */ void dispatch(request, xprt) struct svc_req * request; SVCXPRT * xprt; { Move move; SetupChange setup; GameRequest gr; char ans[80]; int isUndoOK; switch (request->rq_proc) { /* * are you there? */ case NULLPROC: if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { fprintf(stderr, "can't reply to remote peer\n"); exit(1); } break; /* * game invitation accepted */ case ACCEPTPROCNUM: if ( ! svc_getargs(xprt, XdrGameReq, &gr)) { svcerr_decode(xprt); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { fprintf(stderr, "can't reply to remote peer\n"); exit(1); } PeerProgNum = gr.progNum; PeerColor = gr.color; if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) { switch(MyColor) { /* I don't care - pick a color based on what the peer wants */ case EITHERCOLOR: switch(PeerColor) { case WANTSBLACK: MyColor = WANTSWHITE; break; case WANTSWHITE: MyColor = WANTSBLACK; break; default: fprintf(stderr, "color arbitration botch\n"); exit(1); } break; case WANTSBLACK: if (PeerColor == WANTSBLACK) { printf("Your opponent insists on playing black - is that OK? "); scanf("%s", ans); if (ans[0] == 'y' || ans[0] == 'Y') MyColor = WANTSWHITE; else { fprintf(stderr, "couldn't agree on colors - bye\n"); (void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0); exit(1); } } break; case WANTSWHITE: if (PeerColor == WANTSWHITE) { printf("Your opponent insists on playing white - is that OK? "); scanf("%s", ans); if (ans[0] == 'y' || ans[0] == 'Y') MyColor = WANTSBLACK; else { fprintf(stderr, "couldn't agree on colors - bye\n"); (void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0); exit(1); } } break; } } break; /* * the other player didn't ameliorate our insistence on color */ case COLORFAILPROCNUM: fprintf(stderr, "couldn't agree on colors - bye\n"); (void) svc_sendreply(xprt, xdr_void, (caddr_t) 0); exit(1); /* * receive a move from the other player */ case MOVEPROCNUM: if ( ! svc_getargs(xprt, XdrMove, &move)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { DoMove(&move, TRUE); Turn = MyColor; Flashing = TRUE; if (Mouse != CONFIRMING) WhoseMoveMessage((char *) 0); } break; /* * receive a setup change from the other player */ case SETUPPROCNUM: if ( ! svc_getargs(xprt, XdrSetup, &setup)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { DoSetupChange(&setup); } break; /* * receive a restoration move from the other player's process */ case RESTOREMOVEPROCNUM: if ( ! svc_getargs(xprt, XdrMove, &move)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { DoMove(&move, TRUE); Turn = OTHERCOLOR(Turn); } break; /* * restoration complete */ case ENDRESTOREPROCNUM: if ( ! svc_getargs(xprt, xdr_int, &Turn)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { WhoseMoveMessage((char *) 0); RestoringGame = FALSE; Mouse = IDLE; /* unlock the mouse */ Flashing = (Turn == MyColor); } break; /* * other player wants to undo his previous move */ case UNDOPROCNUM: if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { RequestUndo(); Flashing = TRUE; } break; /* * the other player blew away his tool. */ case GOODBYEPROCNUM: svc_sendreply(xprt, xdr_void, (caddr_t) 0); KillMouseActivity(); peerDead = GameOver = TRUE; Mouse = LOCKED; Message("Your opponent killed his tool process"); break; /* * other player is acknowledging our request to undo. */ case UNDOACKPROCNUM: if ( ! svc_getargs(xprt, xdr_int, &isUndoOK)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { if (isUndoOK) { UnDoMove(); if (Turn == MyColor) UnDoMove(); else Turn = MyColor; WhoseMoveMessage("Undo accepted"); } else { WhoseMoveMessage("Undo refused"); } UndoWanted = FALSE; Mouse = IDLE; Flashing = TRUE; } break; /* * other player resigned */ case RESIGNPROCNUM: if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) peerDead = TRUE; Message(PeerColor == BLACK ? "Black resigns" : "White resigns"); KillMouseActivity(); Mouse = LOCKED; /* game is over */ DoResignation(OTHERCOLOR(MyColor)); Flashing = TRUE; break; case MSGPROCNUM: if ( ! svc_getargs(xprt, XdrString, ans)) { fprintf(stderr, "can't get RPC args\n"); exit(1); } if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) { peerDied(); } else { RecvTalkMsg(ans); Flashing = TRUE; } break; } } /* * outstanding invitation - shared by InitRPC() and quitEarly(). */ GameRequest gr; /* * cancel our invitation with the remote daemon if we receive a signal * before the invitee responds. */ quitEarly() { callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, CANCELPROCNUM, XdrGameReq, (caddr_t) &gr, xdr_void, (caddr_t) 0); exit(1); } /* * initialize the RPC connection, using the user's "user@host" arg. */ void InitRPC(cp, progName) char * cp, * progName; { GameRequest gr2; int sock, rfds; char localHostName[256], ans[80]; BOOL resumeGame = FALSE; /* * decipher the remote host and user strings */ if (cp == (char *) 0 || (PeerHostName = index(cp, '@')) == (char *) 0) { fprintf(stderr, "%s: illegal/non-existent user@host arg\n", progName); exit(1); } *PeerHostName++ = '\0'; PeerUserName = cp; /* * determine the local host and user names */ if (gethostname(localHostName, sizeof(localHostName)) != 0) { fprintf(stderr, "%s: can't determine local host name\n", progName); exit(1); } /* * generate the transient RPC program number used by this player. */ MyProgNum = getTransient(VERSNUM, &sock); if ((Xprt = svcudp_create(sock)) == (SVCXPRT *) 0) { fprintf(stderr, "svcudp_create failed\n"); exit(1); } /* * register the peer-to-peer RPC dispatch procedure */ (void) svc_register(Xprt, MyProgNum, VERSNUM, dispatch, 0L); /* * check for an invitation registered with the local chess * daemon, indicating that we are responding to an invitation. */ (void) strcpy(gr.userName, PeerUserName); (void) strcpy(gr.hostName, PeerHostName); if (callrpc(localHostName, SERVERPROGNUM, VERSNUM, ACKPROCNUM, XdrGameReq, (caddr_t) &gr, XdrGameReq, (caddr_t) &gr2) != 0) { fprintf(stderr, "error: callrpc of local daemon (%s)\n", localHostName); exit(1); } PeerProgNum = gr2.progNum; PeerColor = gr2.color; resumeGame = gr2.resumeGame; do { /* * if no invitation was registered or the remote program * is no longer running, * then register an invitation with the remote daemon. */ if (PeerProgNum == 0L || callrpc(PeerHostName, PeerProgNum, VERSNUM, NULLPROC, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0) != 0) { gr.progNum = MyProgNum; gr.color = MyColor; gr.resumeGame = (RestoreFile != (FILE *) 0 || SetupMode); (void) strcpy(gr.userName, UserPWEntry->pw_name); (void) strcpy(gr.hostName, localHostName); signal(SIGINT, quitEarly); signal(SIGQUIT, quitEarly); signal(SIGHUP, quitEarly); if (callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, REQPROCNUM, XdrGameReq, (caddr_t) &gr, xdr_void, (caddr_t) 0) != 0) { fprintf(stderr, "error: callrpc of remote daemon\n"); exit(1); } printf("waiting for %s to respond...\n", PeerUserName); /* * wait for the remote peer to send us his program number and color */ do { rfds = svc_fds; switch(select(32, &rfds, (int *) 0, (int *) 0, (struct timeval *) 0)) { case -1: if (errno == EINTR) continue; fprintf(stderr, "RPC select botch\n"); exit(1); case 0: break; default: svc_getreq(rfds); break; } } while(PeerProgNum == 0L); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGHUP, SIG_DFL); } /* * else accept the invitation, sending the remote program * our program number and color. */ else { if (resumeGame) { MyColor = EITHERCOLOR; RestoringGame = TRUE; SetupMode = FALSE; } /* try to pre-arrange colors */ if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) { switch(MyColor) { /* I don't care - pick a color based on what the peer wants */ case EITHERCOLOR: switch(PeerColor) { case EITHERCOLOR: MyColor = (random() & 0x01) ? WANTSBLACK : WANTSWHITE; break; case WANTSBLACK: MyColor = WANTSWHITE; break; case WANTSWHITE: MyColor = WANTSBLACK; break; } break; case WANTSBLACK: if (PeerColor == WANTSBLACK) { printf("%s also wants to play black - is that OK? ", PeerUserName); scanf("%s", ans); if (ans[0] == 'y' || ans[0] == 'Y') MyColor = WANTSWHITE; } break; case WANTSWHITE: if (PeerColor == WANTSWHITE) { printf("%s also wants to play white - is that OK? ", PeerUserName); scanf("%s", ans); if (ans[0] == 'y' || ans[0] == 'Y') MyColor = WANTSBLACK; } break; } } gr.progNum = MyProgNum; gr.color = MyColor; if (callrpc(PeerHostName, PeerProgNum, VERSNUM, ACCEPTPROCNUM, XdrGameReq, (caddr_t) &gr, xdr_void, (caddr_t) 0) != 0) { PeerProgNum = 0L; } } } while(PeerProgNum == 0L); PeerColor = OTHERCOLOR(MyColor); PlayerName[MyColor] = UserPWEntry->pw_name; PlayerName[PeerColor] = PeerUserName; /* * if the other player is shipping us the game state, lock the * mouse in the meantime. */ if (RestoringGame) Mouse = LOCKED; } /* * send a move to the 'color' player */ BOOL SendMove(move, color) Move * move; int color; { if ( ! peerDead) { if (IsMachine[color]) { SendMachineMove(move, color); } else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, MOVEPROCNUM, XdrMove, (caddr_t) move, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } return( ! peerDead); } void SendRestoreMove(move, color) Move * move; int color; { if ( ! IsMachine[color] && ! peerDead && callrpc(PeerHostName, PeerProgNum, VERSNUM, RESTOREMOVEPROCNUM, XdrMove, (caddr_t) move, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } void SendEndRestore() { if ( ! peerDead && callrpc(PeerHostName, PeerProgNum, VERSNUM, ENDRESTOREPROCNUM, xdr_int, (caddr_t) &Turn, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } void SendUndoRequest(color) int color; { if ( ! peerDead) { if (IsMachine[color]) { if (Turn != MyColor) { Message("Will undo after machine moves..."); } else { MachineUndo(color); UndoWanted = FALSE; Mouse = IDLE; } } else { Message("Sending undo request to your opponent (please wait)..."); if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOPROCNUM, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } } } void SendResignation(color) int color; { if ( ! peerDead) { if (IsMachine[color]) { KillChessProcesses(); } else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, RESIGNPROCNUM, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } } void SendTalkMsg(cp) char * cp; { if ( ! peerDead && callrpc(PeerHostName, PeerProgNum, VERSNUM, MSGPROCNUM, XdrString, (caddr_t) cp, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } void SendSetupChange(setup, color) SetupChange * setup; int color; { if ( ! IsMachine[color] && ! peerDead && callrpc(PeerHostName, PeerProgNum, VERSNUM, SETUPPROCNUM, XdrSetup, (caddr_t) setup, xdr_void, (caddr_t) 0) != 0) { peerDied(); } } void SendUndoAcknowledgement(isUndoOK) int isUndoOK; { if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOACKPROCNUM, xdr_int, (caddr_t) &isUndoOK, xdr_void, (caddr_t) 0) != 0) { peerDied(); } else if (isUndoOK) { UnDoMove(); if (Turn == MyColor) Turn = OTHERCOLOR(MyColor); else UnDoMove(); Message(MyColor == WHITE ? "Waiting for black to re-play..." : "Waiting for white to re-play..."); } else WhoseMoveMessage((char *) 0); } void SendGoodbye() { if ( ! IsMachine[PeerColor] && ! peerDead) { callrpc(PeerHostName, PeerProgNum, VERSNUM, GOODBYEPROCNUM, xdr_void, (caddr_t) 0, xdr_void, (caddr_t) 0); } if (MyProgNum != 0) { /* unregister the RPC transport handle */ xprt_unregister(Xprt); /* release my program number for re-use */ pmap_unset(MyProgNum, VERSNUM); } } @//E*O*F ipc.c// chmod u=r,g=r,o=r ipc.c echo x - tool.c sed 's/^@//' > "tool.c" <<'@//E*O*F tool.c//' /* * handle the tool environment */ #include #include #include #include #include #include #include #include "nchess.h" Tool * NchessTool; char ** ToolAttrs = (char **) NULL; char * ToolName; /* * iconic form of window */ unsigned short IconImage[] = { #include "Icons/nchess.icon" }; DEFINE_ICON_FROM_IMAGE(WindowIcon, IconImage); sigwinched() { tool_sigwinch(NchessTool); } /* * parse the tool args. */ void ParseToolArgs(argc, argv) int *argc; char **argv; { ToolName = argv[0]; (*argc)--; argv++; if (tool_parse_all(argc, argv, &ToolAttrs, ToolName) == -1) { tool_usage(ToolName); exit(1); } (*argc)++; } /* * set up the tool environment */ void InitTool(useRetained, iconDirectory) BOOL useRetained; /* use a retained pixrect for the board */ char * iconDirectory; /* custom piece icon directory */ { register unsigned int height; register Toolsw * twsp; char c[256]; /* create the tool marquee */ strcpy(c, " "); strcat(c, PlayerName[WHITE]); strcat(c, " vs. "); strcat(c, PlayerName[BLACK]); if ((NchessTool = tool_make( WIN_LABEL, c, WIN_ICON, &WindowIcon, WIN_ATTR_LIST, ToolAttrs, WIN_WIDTH, 8 * (SQUARE_WIDTH-1) + 2 * tool_borderwidth(NchessTool) - 1, /* * NOTE: The following line was unnecessary in Sun release 2.2, * but is necessary in release 3.0. For some unknown reason, the * call to tool_set_attributes following the call to InitBoardSW * now fails to uncover the board area that was obscured by the * default tool height being too small (note that the tool has not * been installed yet). */ WIN_HEIGHT, 2000, 0)) == (Tool *) NULL) { fputs("Can't make tool\n", stderr); exit(1); } tool_free_attribute_list(ToolAttrs); /* initialize the subwindows */ InitTalkSW(); InitMsgSW(); InitControlSW(); InitBoardSW(useRetained, iconDirectory); /* * add up subwindow heights and force the tool to the resulting size */ height = tool_stripeheight(NchessTool) + tool_borderwidth(NchessTool) - tool_subwindowspacing(NchessTool); for (twsp = NchessTool->tl_sw ; twsp != (Toolsw *) 0 ; twsp = twsp->ts_next) height += twsp->ts_height + tool_subwindowspacing(NchessTool); /* * NOTE: under 2.2, the above calculation yielded the correct height. * under 3.0, we need to add a few pixels to make it come out right (the * reason is not yet known). */ height += 2; tool_set_attributes(NchessTool, WIN_HEIGHT, height, 0); signal(SIGWINCH, sigwinched); } void RunTool() { /* * NOTE: this is another difference between release 2.2 and 3.0: * in release 2.2, the SIGWINCH handler would get called once at the * outset to draw the board area; in release 3.0, this doesn't happen. */ DrawBoard(); tool_select(NchessTool, 0); tool_destroy(NchessTool); } @//E*O*F tool.c// chmod u=r,g=r,o=r tool.c echo x - controlsw.c sed 's/^@//' > "controlsw.c" <<'@//E*O*F controlsw.c//' /* * control panel subwindow handling */ #include #include #include #include #include "nchess.h" BOOL SaveWanted = FALSE; /* machine opponent and game save deferred */ struct toolsw * ControlPanelSW; Panel ControlPanel; /* button items */ Panel_item UndoButton; Panel_item LastPlayButton; Panel_item ResignButton; Panel_item TranscriptButton; Panel_item SaveButton; /* * undo move button event handler */ /*ARGSUSED*/ undoProc(item, event) Panel_item item; struct inputevent * event; { if ( ! IHaveMoved()) { Message("You haven't moved yet!"); } else if (Mouse == IDLE) { UndoWanted = TRUE; Mouse = LOCKED; /* lock the mouse until the reply arrives */ SendUndoRequest(PeerColor); } } /* * last play button event handler */ /*ARGSUSED*/ lastPlayProc(item, event) Panel_item item; struct inputevent * event; { ShowLastPlay(); } /* * resign button event handler */ /*ARGSUSED*/ resignProc(item, event) Panel_item item; struct inputevent * event; { /* make sure this is what the user wants to do */ if (Mouse == IDLE) { ConfirmResignation(); } } /* * write a transcript */ /*ARGSUSED*/ transcriptProc(item, event) Panel_item item; struct inputevent * event; { WriteTranscript(TranscriptFileName, TranscriptType); } /* * save the game */ /*ARGSUSED*/ saveProc(item, event) Panel_item item; struct inputevent * event; { /* * caveats: can't save games while we're still setting them up, * and cannot save a game involving machines after the game is over. */ if (SetupMode || GameOver && (IsMachine[WHITE] || IsMachine[BLACK])) return; if (IsMachine[WHITE] && IsMachine[BLACK] || IsMachine[PeerColor] && Turn != MyColor) { Message("Will save game when machine finishes move..."); SaveWanted = TRUE; } else { SaveGame(SaveFileName); } } /* * set up the control subwindow */ void InitControlSW() { if ((ControlPanelSW = panel_create(NchessTool, 0)) == NULL) { fprintf(stderr, "Can't create control panel\n"); exit(1); } ControlPanel = ControlPanelSW->ts_data; /* set up the buttons */ if ( ! IsMachine[WHITE] || ! IsMachine[BLACK]) { ResignButton = panel_create_item(ControlPanel, PANEL_BUTTON, PANEL_LABEL_STRING, "(Resign)", PANEL_NOTIFY_PROC, resignProc, 0); UndoButton = panel_create_item(ControlPanel, PANEL_BUTTON, PANEL_LABEL_STRING, "(Undo)", PANEL_NOTIFY_PROC, undoProc, 0); } LastPlayButton = panel_create_item(ControlPanel, PANEL_BUTTON, PANEL_LABEL_STRING, "(Last Play)", PANEL_NOTIFY_PROC, lastPlayProc, 0); TranscriptButton = panel_create_item(ControlPanel, PANEL_BUTTON, PANEL_LABEL_STRING, "(Transcript)", PANEL_NOTIFY_PROC, transcriptProc, 0); SaveButton = panel_create_item(ControlPanel, PANEL_BUTTON, PANEL_LABEL_STRING, "(Save)", PANEL_NOTIFY_PROC, saveProc, 0); panel_fit_height(ControlPanel); } @//E*O*F controlsw.c// chmod u=r,g=r,o=r controlsw.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 646 1975 15392 ipc.c 121 392 3019 tool.c 136 347 3010 controlsw.c 903 2714 21421 total !!! wc ipc.c tool.c controlsw.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0