Path: utzoo!attcan!uunet!husc6!bloom-beacon!mit-eddie!uw-beaver!tektronix!tekgen!tekred!games From: games@tekred.TEK.COM Newsgroups: comp.sources.games Subject: v04i020: bridge - multiplayer networked bridge game, Part02/02 Message-ID: <2582@tekred.TEK.COM> Date: 31 May 88 16:17:10 GMT Sender: billr@tekred.TEK.COM Lines: 595 Approved: billr@saab.CNA.TEK.COM Submitted by: Jiang-Hsing ChuComp.sources.games: Volume 4, Issue 20 Archive-name: bridge/Part02 [Oops! Forgot to mention in Part01 that this does look BSD specific. I don't know what it would take to get it running on SysV. -br] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh Makefile <<'END_OF_Makefile' X# Makefile for multi-player bridge X XOBJ1 = master_talk.o bridge.o get_names.o master_io.o msgs.o ctl.o init_disp.o get_addrs.o ctl_transact.o invite.o look_up.o X XOBJ2 = slave_talk.o get_names.o slave_io.o msgs.o ctl.o init_disp.o get_addrs.o ctl_transact.o invite.o look_up.o X Xall: invitebridge bridge X Xinvitebridge: $(OBJ1) X cc -O -o invitebridge $(OBJ1) -lcurses -ltermlib X Xbridge: $(OBJ2) X cc -O -o bridge $(OBJ2) -lcurses -ltermlib X Xclean: X -rm *.o bridge invitebridge END_OF_Makefile if test 478 -ne `wc -c ctl.c <<'END_OF_ctl.c' X#ifndef lint Xstatic char sccsid[] = "@(#)ctl.c 1.1 86/02/05 SMI"; /* from UCB 1.4 83/06/09 */ X#endif X X/* This file handles haggling with the various talk daemons to X get a socket to talk to. sockt is opened and connected in X the progress X */ X X#include "talk_ctl.h" X Xstruct sockaddr_in daemon_addr = { AF_INET }; Xstruct sockaddr_in ctl_addr = { AF_INET }; Xstruct sockaddr_in my_addr = { AF_INET }; X X /* inet addresses of the two machines */ Xstruct in_addr my_machine_addr; Xstruct in_addr his_machine_addr; X Xu_short daemon_port; /* port number of the talk daemon */ X Xint ctl_sockt; Xint sockt; Xint invitation_waiting = 0; X XCTL_MSG msg; X Xopen_sockt() X{ X int length; X X my_addr.sin_addr = my_machine_addr; X my_addr.sin_port = 0; X X sockt = socket(AF_INET, SOCK_STREAM, 0, 0); X X if (sockt <= 0) { X p_error("Bad socket"); X } X X if ( bind(sockt, &my_addr, sizeof(my_addr)) != 0) { X p_error("Binding local socket"); X } X X length = sizeof(my_addr); X X if (getsockname(sockt, &my_addr, &length) == -1) { X p_error("Bad address for socket"); X } X} X X /* open the ctl socket */ X Xopen_ctl() X{ X int length; X X ctl_addr.sin_port = 0; X ctl_addr.sin_addr = my_machine_addr; X X ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0, 0); X X if (ctl_sockt <= 0) { X p_error("Bad socket"); X } X X if (bind(ctl_sockt, &ctl_addr, sizeof(ctl_addr), 0) != 0) { X p_error("Couldn't bind to control socket"); X } X X length = sizeof(ctl_addr); X if (getsockname(ctl_sockt, &ctl_addr, &length) == -1) { X p_error("Bad address for ctl socket"); X } X} X X/* print_addr is a debug print routine */ X Xprint_addr(addr) Xstruct sockaddr_in addr; X{ X int i; X X printf("addr = %x, port = %o, family = %o zero = ", X addr.sin_addr, addr.sin_port, addr.sin_family); X X for (i = 0; i<8;i++) { X printf("%o ", (int)addr.sin_zero[i]); X } X putchar('\n'); X} END_OF_ctl.c if test 1868 -ne `wc -c ctl.h <<'END_OF_ctl.h' X/* @(#)ctl.h 1.1 86/02/05 SMI; from UCB 1.4 83/03/28 */ X X/* ctl.h describes the structure that talk and talkd pass back X and forth X */ X X#include X#include X#include X#include X X#define NAME_SIZE 9 X#define TTY_SIZE 16 X#define HOST_NAME_LENGTH 256 X X#define MAX_LIFE 60 /* maximum time an invitation is saved by the X talk daemons */ X#define RING_WAIT 30 /* time to wait before refreshing invitation X should be 10's of seconds less than MAX_LIFE */ X X /* the values for type */ X X#define LEAVE_INVITE 0 X#define LOOK_UP 1 X#define DELETE 2 X#define ANNOUNCE 3 X X /* the values for answer */ X X#define SUCCESS 0 X#define NOT_HERE 1 X#define FAILED 2 X#define MACHINE_UNKNOWN 3 X#define PERMISSION_DENIED 4 X#define UNKNOWN_REQUEST 5 X Xtypedef struct ctl_response CTL_RESPONSE; X Xstruct ctl_response { X char type; X char answer; X int id_num; X struct sockaddr_in addr; X}; X Xtypedef struct ctl_msg CTL_MSG; X Xstruct ctl_msg { X char type; X char l_name[NAME_SIZE]; X char r_name[NAME_SIZE]; X int id_num; X int pid; X char r_tty[TTY_SIZE]; X struct sockaddr_in addr; X struct sockaddr_in ctl_addr; X}; END_OF_ctl.h if test 1170 -ne `wc -c get_addrs.c <<'END_OF_get_addrs.c' X#ifndef lint Xstatic char sccsid[] = "@(#)get_addrs.c 1.1 86/02/05 SMI"; /* from UCB 1.5 83/04/01 */ X#endif X X#include "talk_ctl.h" X Xstruct hostent *gethostbyname(); Xstruct servent *getservbyname(); X Xget_addrs(my_machine_name, his_machine_name) Xchar *my_machine_name; Xchar *his_machine_name; X{ X struct hostent *hp; X struct servent *sp; X X msg.pid = getpid(); X X /* look up the address of the local host */ X X hp = gethostbyname(my_machine_name); X X if (hp == (struct hostent *) 0) { X printf("This machine doesn't exist. Boy, am I confused!\n"); X exit(-1); X } X X if (hp->h_addrtype != AF_INET) { X printf("Protocal mix up with local machine address\n"); X exit(-1); X } X X bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length); X X /* if he is on the same machine, then simply copy */ X X if ( bcmp((char *)&his_machine_name, (char *)&my_machine_name, X sizeof(his_machine_name)) == 0) { X bcopy((char *)&my_machine_addr, (char *)&his_machine_addr, X sizeof(his_machine_name)); X } else { X X /* look up the address of the recipient's machine */ X X hp = gethostbyname(his_machine_name); X X if (hp == (struct hostent *) 0 ) { X printf("%s is an unknown host\n", his_machine_name); X exit(-1); X } X X if (hp->h_addrtype != AF_INET) { X printf("Protocol mix up with remote machine address\n"); X exit(-1); X } X X bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length); X } X X /* find the daemon portal */ X X#ifdef NTALK X sp = getservbyname("ntalk", "udp"); X#else X sp = getservbyname("talk", "udp"); X#endif X X if (strcmp(sp->s_proto, "udp") != 0) { X printf("Protocol mix up with talk daemon\n"); X exit(-1); X } X X daemon_port = sp->s_port; X} END_OF_get_addrs.c if test 1678 -ne `wc -c get_names.c <<'END_OF_get_names.c' X#ifndef lint Xstatic char sccsid[] = "@(#)get_names.c 1.1 86/02/05 SMI"; /* from UCB 1.2 83/03/26 */ X#endif X X#include "talk.h" X#include "ctl.h" X Xchar *getlogin(), *ttyname(), *rindex(); X Xextern CTL_MSG msg; X X/* X * Determine the local and remote user, tty, and machines X */ X Xstruct hostent *gethostbyname(); X Xget_names(argc, argv) Xint argc; Xchar *argv[]; X{ X char hostname[HOST_NAME_LENGTH]; X char *his_name; X char *my_name; X char *my_machine_name; X char *his_machine_name; X char *my_tty; X char *his_tty; X char *ptr; X int name_length; X X if (argc < 2 ) { X printf("Usage: talk user [ttyname]\n"); X exit(-1); X } X if ( !isatty(0) ) { X printf("Standard input must be a tty, not a pipe or a file\n"); X exit(-1); X } X X my_name = getlogin(); X if (my_name == NULL) { X printf("You don't exist. Go away.\n"); X exit(-1); X } X X name_length = HOST_NAME_LENGTH; X gethostname(hostname, &name_length); X my_machine_name = hostname; X X my_tty = rindex(ttyname(0), '/') + 1; X X /* check for, and strip out, the machine name X of the target */ X X for (ptr = argv[1]; *ptr != '\0' && X *ptr != '@' && X *ptr != ':' && X *ptr != '!' && X *ptr != '.' ; ptr++) { X } X X if (*ptr == '\0') { X X /* this is a local to local talk */ X X his_name = argv[1]; X his_machine_name = my_machine_name; X X } else { X X if (*ptr == '@') { X /* user@host */ X his_name = argv[1]; X his_machine_name = ptr + 1; X } else { X /* host.user or host!user or host:user */ X his_name = ptr + 1; X his_machine_name = argv[1]; X } X *ptr = '\0'; X } X X X if (argc > 2) { X his_tty = argv[2]; /* tty name is arg 2 */ X } else { X his_tty = ""; X } X X get_addrs(my_machine_name, his_machine_name); X X /* Load these useful values into the standard message header */ X X msg.id_num = 0; X X strncpy(msg.l_name, my_name, NAME_SIZE); X msg.l_name[NAME_SIZE - 1] = '\0'; X X strncpy(msg.r_name, his_name, NAME_SIZE); X msg.r_name[NAME_SIZE - 1] = '\0'; X X strncpy(msg.r_tty, his_tty, TTY_SIZE); X msg.r_tty[TTY_SIZE - 1] = '\0'; X} END_OF_get_names.c if test 2077 -ne `wc -c invitebridge.README <<'END_OF_invitebridge.README' X"invitebridge" is the brain of the whole system. The system looks like this: X X ---------- X |player1@| X |machine1| X ---------- X | bridge@ X | machine1 X | X ---------------------------------------- X | | | X | ---------- | | bridge@ ---------- X | |player4@| invitebridge@ | machine2 |player2@| X | |machine4|---- machine4 -------|------------|machine2| X | ---------- | | --------- X ---------------------------------------- X | bridge@ X | machine3 X | X ---------- X |player3@| X |machine3| X ---------- X XTo play the bridge game via compute communication, the central site needs Xthe "invitebridge" program and the remote sites need "bridge" program. XThe game is started by issuing the following command: X invitebridge player1@machine1 player2@machine2 player@machine3 X XIn the given example, the player1 will be the North, the player2 will be Xthe East, and the player3 will be the South. You, player4, are always Xthe West. X XThe game record will be stored in "bridge.log" in your working directory. XThe guide of bidding, playing,.. can be found in "bridge.README" which Xis part of this package. END_OF_invitebridge.README if test 1688 -ne `wc -c slave_talk.c <<'END_OF_slave_talk.c' X X#include "talk.h" X X Xxwin_t comwin[19]; Xchar *current_state; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X get_names(argc, argv); X X open_ctl(); X open_sockt(); X start_msgs(); X X if ( !check_local() ) { X invite_remote(); X } X end_msgs(); X X init_disp(); X X talk(); X} END_OF_slave_talk.c if test 264 -ne `wc -c talk.h <<'END_OF_talk.h' X/* @(#)talk.h 1.1 86/02/05 SMI; from UCB 1.2 83/04/23 */ X X#include X#include X X#define forever for(;;) X X#define BUF_SIZE 512 X#define PUT 1 X#define GET 2 X#define TYPE buf.type X#define WN buf.wn X#define ROW buf.row X#define COL buf.col X#define STR buf.string X XFILE *popen(); Xint quit(), sleeper(); X Xextern int sockt; Xextern int curses_initialized; Xextern int invitation_waiting; X Xextern char *current_state; Xextern int current_line; X Xtypedef struct xwin { X WINDOW *x_win; X int x_nlines; X int x_ncols; X int x_line; X int x_col; X} xwin_t; X Xextern xwin_t comwin[19]; X Xtypedef struct { X char type, wn, row, col; X char string[40]; X} BMSG; END_OF_talk.h if test 656 -ne `wc -c talk_ctl.h <<'END_OF_talk_ctl.h' X/* @(#)talk_ctl.h 1.1 86/02/05 SMI; from UCB 1.1 83/03/26 */ X X#include "ctl.h" X#include "talk.h" X#include X Xextern int errno; X Xextern struct sockaddr_in daemon_addr; Xextern struct sockaddr_in ctl_addr; Xextern struct sockaddr_in my_addr; Xextern struct in_addr my_machine_addr; Xextern struct in_addr his_machine_addr; Xextern u_short daemon_port; Xextern int ctl_sockt; Xextern CTL_MSG msg; END_OF_talk_ctl.h if test 395 -ne `wc -c