home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!zephyr.ens.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v14i085: okbridge2 - computer-mediated bridge game, Part07/14
- Message-ID: <3524@master.CNA.TEK.COM>
- Date: 7 Sep 92 21:42:01 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 1887
- Approved: billr@saab.CNA.TEK.COM
-
- Submitted-by: mclegg@cs.UCSD.EDU (Matthew Clegg)
- Posting-number: Volume 14, Issue 85
- Archive-name: okbridge2/Part07
- Supersedes: okbridge: Volume 13, Issue 16-22
- Environment: BSD-derived Unix, NeXT, curses, sockets
-
-
-
- #! /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 <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 7 (of 14)."
- # Contents: MkDistrib network.c protocol.h
- # Wrapped by billr@saab on Mon Sep 7 14:33:37 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'MkDistrib' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MkDistrib'\"
- else
- echo shar: Extracting \"'MkDistrib'\" \(576 characters\)
- sed "s/^X//" >'MkDistrib' <<'END_OF_FILE'
- X#!/bin/csh -f
- X#
- X# This shell script creates the compress okbridge tar file which
- X# is distributed. Unfortunately, it seems that the "make" command
- X# on some systems is not smart enough to handle the work which is
- X# done by this file.
- X#
- Xsetenv MAJOR `grep 'major_rev.*=' types.h | sed 's@.*"\(.*\)".*@\1@'`
- Xsetenv MINOR `grep 'minor_rev.*=' types.h | sed 's@.*"\(.*\)".*@\1@'`
- Xsetenv OKFILENAME okbridge-$MAJOR$MINOR
- Xsetenv OKBDIR `pwd | sed "s@.*/\([^/]*\)@\1@"`
- Xcd ..
- Xecho Ztar\'ing $OKBDIR into $OKFILENAME.tar.Z
- Xtar -cf $OKFILENAME.tar $OKBDIR
- Xcompress $OKFILENAME.tar
- X
- END_OF_FILE
- if test 576 -ne `wc -c <'MkDistrib'`; then
- echo shar: \"'MkDistrib'\" unpacked with wrong size!
- fi
- # end of 'MkDistrib'
- fi
- if test -f 'network.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'network.c'\"
- else
- echo shar: Extracting \"'network.c'\" \(33079 characters\)
- sed "s/^X//" >'network.c' <<'END_OF_FILE'
- X/* network.c
- X *
- X ! Copyright (C) 1990-1992 by Matthew Clegg. All Rights Reserved
- X !
- X ! OKbridge is made available as a free service to the Internet.
- X ! Accordingly, the following restrictions are placed on its use:
- X !
- X ! 1. OKbridge may not be modified in any way without the explicit
- X ! permission of Matthew Clegg.
- X !
- X ! 2. OKbridge may not be used in any way for commercial advantage.
- X ! It may not be placed on for-profit networks or on for-profit
- X ! computer systems. It may not be bundled as part of a package
- X ! or service provided by a for-profit organization.
- X !
- X ! If you have questions about restrictions on the use of OKbridge,
- X ! write to mclegg@cs.ucsd.edu.
- X !
- X ! DISCLAIMER: The user of OKbridge accepts full responsibility for any
- X ! damage which may be caused by OKbridge.
- X *
- X * This is the implementation of the network module. The network module
- X * provides two functions. First it abstracts the socket communication
- X * into messages which are handled on the message queues, and second
- X * it provides a branch point between the server and client sides of
- X * the code.
- X *
- X */
- X
- X/* The NO_TM_ZONE definition is for machines which do not have the
- X field tm_zone defined in the struct tm returned by localtime.
- X In this case, we use the struct timezone returned by gettimeofday
- X to determine an offset from GMT.
- X*/
- X
- X#ifdef AIX
- X#define NO_TM_ZONE 1
- X#define NO_PWCOMMENT 1
- X#endif
- X
- X#ifdef HARRIS
- X#define NO_TM_ZONE 1
- X#endif
- X
- X/* The NO_PWCOMMENT definition is for machines which do not have the
- X pw_comment field defined in struct passwd returned by getpwuid ().
- X*/
- X
- X#ifdef AIX
- X#define NO_PWCOMMENT 1
- X#endif
- X
- X#ifdef SGI
- X#define NO_TM_ZONE 1
- X#endif
- X
- X#include <ctype.h>
- X#include <sys/errno.h>
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <arpa/inet.h>
- X#include <netdb.h>
- X#include <pwd.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <sys/time.h>
- X#include <sys/resource.h>
- X#ifdef AIX
- X#include <sys/select.h>
- X#include <time.h>
- X#endif
- X
- X#define _NETWORK_
- X
- X#include "state.h"
- X#include "socket.h"
- X#include "display.h"
- X#include "gps.h"
- X#include "fds.h"
- X
- X#ifdef GCC
- Xextern bzero (), fprintf (), fflush (), accept ();
- Xextern time_t time ();
- X#endif
- X
- Xextern int errno;
- Xextern char *sys_errlist [];
- Xextern char *getlogin(), *getenv();
- Xextern char *strdup ();
- Xextern char *malloc ();
- Xextern void close ();
- Xextern int select ();
- Xextern int gethostname ();
- Xextern uid_t getuid ();
- X
- Xextern int Terminate_Program ();
- Xextern void restore_cursor ();
- Xextern void Broadcast_Comment ();
- Xextern void Generate_reset ();
- Xextern void Vacate_seat ();
- X
- X#ifndef index
- Xextern char *index();
- X#endif
- X
- X#ifdef LOGFILE
- X FILE *net_log = NULL;
- X#endif
- X
- X#define DISCARD (void)
- X
- X#define RETRY_LIMIT 60
- X
- Xstatic Message message_free_list = NULL;
- Xstatic Connection connection_freelist = NULL;
- X
- Xstatic int listen_port = -1;
- X /* The socket we have opened for listening for new connections. */
- Xstatic int server_port = -1;
- X /* The socket opened by the client for listening to the server. */
- X
- Xextern char socket_error[];
- X /* An error message buffer for recording socket errors. */
- X
- X/* Procedures for manipulating command queues: */
- X
- Xstatic message_queue Allocate_message_queue ()
- X{
- X message_queue m;
- X
- X m = (message_queue) malloc (sizeof(struct Message_queue_struct));
- X m->head = m->tail = NULL;
- X return (m);
- X}
- X
- Xint message_available (queue)
- X message_queue queue;
- X/* Returns true if the given queue is nonempty. */
- X{
- X return (queue->head != NULL);
- X}
- X
- XMessage dequeue_message (queue)
- X message_queue queue;
- X/* Deletes the first message from the given queue and returns a pointer
- X to that message.
- X*/
- X{
- X Message m;
- X
- X if (!message_available(queue))
- X return (NULL);
- X
- X m = queue->head;
- X queue->head = m->next;
- X if (queue->head == NULL)
- X queue->tail = NULL;
- X return (m);
- X}
- X
- Xvoid enqueue_message (queue, m)
- X message_queue queue; Message m;
- X/* Appends m to the list of messages stored in the given message queue. */
- X{
- X m->next = NULL;
- X if (queue->tail == NULL)
- X queue->head = queue->tail = m;
- X else {
- X queue->tail->next = m;
- X queue->tail = m;
- X }
- X
- X}
- X
- XMessage allocate_message ()
- X/* Allocates a message structure and returns a pointer to the structure. */
- X{
- X Message m;
- X
- X if (message_free_list == NULL)
- X m = (Message) malloc (sizeof(struct Message_struct));
- X else {
- X m = message_free_list;
- X message_free_list = m->next;
- X }
- X
- X m->p.command_text[0] = '\0';
- X m->p.player_no = 0;
- X m->private = 0;
- X m->loopback = 0;
- X return (m);
- X}
- X
- Xvoid deallocate_message (m)
- X Message m;
- X/* Returns the message structure m to the pool of free message structs. */
- X{
- X m->next = message_free_list;
- X message_free_list = m;
- X m->p.player_no = 0;
- X}
- X
- Xvoid clear_message_queue (queue)
- X message_queue queue;
- X/* Deletes all messages from the named queue. */
- X{
- X Message m;
- X
- X while (message_available(queue)) {
- X m = dequeue_message (queue);
- X deallocate_message (m);
- X }
- X}
- X
- Xvoid clear_all_message_queues (t)
- X Table t;
- X/* Clears all of the message queues. */
- X{
- X clear_message_queue (t->protocol_queue);
- X clear_message_queue (t->conversation_queue);
- X clear_message_queue (t->game_queue);
- X}
- X
- Xstatic Connection Allocate_Dummy_Connection ()
- X/* Allocates a new connection structure and fills in the fields with
- X appropriate initial values. Does not link the connection into any list. */
- X{
- X Connection c;
- X
- X if (connection_freelist == NULL)
- X c = (Connection) malloc (sizeof(struct Connection_struct));
- X else {
- X c = connection_freelist;
- X connection_freelist = c->inext;
- X }
- X
- X c->channel = 0;
- X c->local = 1;
- X c->state = CSTATE_CONNECTED;
- X c->player_name[0] = '\0';
- X c->fullname[0] = '\0';
- X c->email[0] = '\0';
- X c->registry[0] = '\0';
- X c->seat = PLAYER_OBS;
- X c->table = NULL;
- X
- X c->iprev = c->inext = c->oprev = c->onext = NULL;
- X if (Connections == NULL)
- X Connections = c;
- X
- X return (c);
- X}
- X
- Xstatic Connection Allocate_Connection ()
- X/* Allocates a new connection structure, and fills in the pointer fields
- X appropriately. Links the connection into the Connection list. */
- X{
- X Connection c = Allocate_Dummy_Connection ();
- X
- X c->inext = Connections->inext;
- X c->iprev = Connections;
- X if (c->inext != NULL)
- X c->inext->iprev = c;
- X Connections->inext = c;
- X
- X return (c);
- X}
- X
- Xstatic void Link_Output_Connection (p, c)
- X Connection p, c;
- X/* Links the connection c into the list pointed to by p. Since we
- X always store dummy header elements in connection lists, p is guaranteed
- X to be non-NULL, even in the case of an empty list.*/
- X{
- X
- X c->oprev = p;
- X c->onext = p->onext;
- X if (c->onext != NULL)
- X c->onext->oprev = c;
- X p->onext = c;
- X
- X}
- X
- Xstatic void Unlink_Output_Connection (c)
- X Connection c;
- X/* Unlinks the connection c from the list containing it. */
- X{
- X if (c->onext != NULL)
- X c->onext->oprev = c->oprev;
- X
- X if (c->oprev != NULL)
- X c->oprev->onext = c->onext;
- X
- X c->oprev = c->onext = NULL;
- X}
- X
- Xstatic void Deallocate_Connection (c)
- X Connection c;
- X/* Unlinks the connection c from any lists which may contain it and
- X then returns the connection to the free store. */
- X{
- X Unlink_Output_Connection (c);
- X
- X if (c->inext != NULL)
- X c->inext->iprev = c->iprev;
- X c->iprev->inext = c->inext;
- X
- X c->inext = connection_freelist;
- X connection_freelist = c;
- X}
- X
- Xvoid close_connection (c)
- X Connection c;
- X/* void close_connection (Connection c) */
- X/* Closes the connection to c. */
- X{
- X Table t = c->table;
- X#ifdef DEBUG
- X char error_buf[100];
- X#endif
- X
- X if (c->local)
- X return;
- X
- X#ifdef DEBUG
- X sprintf (error_buf, "CLOSED CONNECTION ON FD %d.", c->channel);
- X Network_Comment (error_buf);
- X#endif
- X
- X Vacate_seat (c->table, c->seat);
- X
- X if (c->channel > 0)
- X close (c->channel);
- X
- X Deallocate_Connection (c);
- X}
- X
- Xint No_connections (t)
- X Table t;
- X/* Returns the number of connections to the table t. */
- X{
- X int n;
- X Connection c;
- X
- X n = 0;
- X FOREACH_PLAYER (c, t)
- X n++;
- X return (n);
- X}
- X
- XMessage loopback_message_unformatted (t, c, message)
- X Table t; Connection c; char *message;
- X/* void loopback_message_unformatted (Table t, char *message); */
- X/* Constructs a message structure using the the given message.
- X Assumes that the message is in the format which is used by the
- X client in transmitting messages. Appends the message structure
- X to the protocol queue for the table t.
- X*/
- X{
- X Message m = allocate_message ();
- X strcpy (m->p.command_text, message);
- X Parse_Command_for_Client (&(m->p));
- X m->source = c;
- X m->loopback = 1;
- X enqueue_message (t->protocol_queue, m);
- X return (m);
- X}
- X
- XMessage loopback_message (t, c, message)
- X Table t; Connection c; char *message;
- X/* void loopback_message (Table t, Connection c, char *message); */
- X/* Constructs a message structure using the given source, source name
- X and message text. Appends the message structure to the protocol
- X queue for the table t.
- X*/
- X{
- X Message m = allocate_message ();
- X
- X sprintf (m->p.command_text, "%s %s %s", seat_names[c->seat],
- X c->player_name, message);
- X m->source = c;
- X m->loopback = 1;
- X Parse_Command_for_Client (&(m->p));
- X enqueue_message (t->protocol_queue, m);
- X return (m);
- X}
- X
- Xint server_send_unformatted (c, message)
- X Connection c; char *message;
- X/* Transmits the message to the given player. Returns 0 if successful or 1
- X if an error. If an error occurs, then the connection is closed.
- X*/
- X{
- X int status; /* return code from Select call. */
- X int log; /* number of bytes transmitted. */
- X int n; /* number of bytes to transmit. */
- X struct fd_set wait_set; /* A set representing the connections that
- X have been established. */
- X struct timeval tm; /* A timelimit of zero for polling for new
- X connections. */
- X char buf [100];
- X
- X if (c->local) {
- X/* loopback_message_unformatted (c->table, c, message); */
- X return (1);
- X }
- X
- X FD_ZERO (&wait_set);
- X FD_SET (c->channel, &wait_set);
- X
- X tm.tv_sec = 0;
- X tm.tv_usec = 0;
- X status = select (FD_SETSIZE, (fd_set *) 0, &wait_set, (fd_set *) 0, &tm);
- X
- X if (status < 0) {
- X sprintf (buf, "WRITE ERROR TO %s: %s", c->player_name, sys_errlist[errno]);
- X Network_Comment (buf);
- X shutdown (c->channel, 2);
- X c->channel = 0;
- X close_connection (c);
- X return (1);
- X } else if (status == 0) {
- X sprintf (buf, "WRITE BLOCK FOR %s", c->player_name);
- X Network_Comment (buf);
- X shutdown (c->channel, 2);
- X c->channel = 0;
- X close_connection (c);
- X return (1);
- X }
- X
- X n = strlen (message) + 1;
- X do {
- X log = fd_writeln (c->channel, message);
- X } while ((log < 0) && (errno == EINTR));
- X
- X if (log < n) {
- X sprintf (buf, "WRITE BLOCK FOR %s", c->player_name);
- X Network_Comment (buf);
- X close_connection (c);
- X return (1);
- X }
- X
- X#ifdef LOGFILE
- X fprintf (net_log, "%2d > %s\n", c->channel, message);
- X fflush (net_log);
- X#endif
- X return (0);
- X}
- X
- Xint server_send (c, source, player_name, message)
- X Connection c; int source; char *player_name, *message;
- X/* Formats a message and sends it across the given connection.
- X Returns 0 if successful or 1 if an error. If an error occurs,
- X then the connection is closed. */
- X{
- X char buf [120];
- X
- X sprintf (buf, "%s %s %s", seat_names[source], player_name, message);
- X return (server_send_unformatted (c, buf));
- X}
- X
- Xint May_receive (c, msg_type)
- X Connection c; int msg_type;
- X/* Returns true if a message of type msg_type can be sent to channel c. */
- X{
- X if (c == NULL)
- X return (0);
- X else if (c->state == CSTATE_PLAYING)
- X return (1);
- X else
- X return (0);
- X}
- X
- Xvoid server_broadcast_unformatted (t, msg_type, message)
- X Table t; int msg_type; char *message;
- X/* Broadcasts the message to all of the people sitting at table t who are
- X entitled to receive the message. */
- X{
- X Connection c, d;
- X int local = 0;
- X
- X c = t->Players->onext;
- X while (c != NULL) {
- X d = c->onext;
- X if (May_receive (c, msg_type)) {
- X if (c->local)
- X local = 1;
- X else
- X server_send_unformatted (c, message);
- X }
- X c = d;
- X }
- X
- X if (local && (msg_type != CMD_BOARD) && (msg_type != CMD_RECORD))
- X loopback_message_unformatted (t, MODERATOR(t), message);
- X}
- X
- Xvoid server_broadcast (t, source, player_name, msg_type, message)
- X Table t; int source, msg_type; char *player_name, *message;
- X/* Formats and broadcasts the message to all of the people sitting at table t
- X who are entitled to receive the message. */
- X{
- X char buf [120];
- X
- X sprintf (buf, "%s %s %s", seat_names[source], player_name, message);
- X server_broadcast_unformatted (t, msg_type, buf);
- X}
- X
- Xvoid Relay_message (t, c, msg_type, message)
- X Table t; Connection c; int msg_type; char *message;
- X/* Relays the message from c to all of the other players at table t who
- X are allowed to receive the message. */
- X{
- X Connection p, q;
- X
- X p = t->Players->onext;
- X while (p != NULL) {
- X q = p->onext;
- X if ((p->channel != c->channel) && May_receive (p, msg_type))
- X server_send_unformatted (p, message);
- X p = q;
- X }
- X}
- X
- XMessage send_message (t, msg_type, message)
- X Table t; int msg_type; char *message;
- X/* If in server mode, sends a message to each of the clients.
- X If in client mode, sends a message to the server. */
- X{
- X char message_buf [120];
- X Message m;
- X
- X m = loopback_message (t, Local_Player_Connection, message);
- X
- X if (client_mode) {
- X sprintf (message_buf, "%s %s", local_player_name, message);
- X fd_writeln (server_port, message_buf);
- X#ifdef LOGFILE
- X fprintf (net_log, " > %s\n", message_buf);
- X fflush (net_log);
- X#endif
- X }
- X
- X return (m);
- X}
- X
- Xvoid send_server_message (t, msg_type, message)
- X Table t; int msg_type; char *message;
- X/* Sends a message which originates from the 'SERVER'.
- X Should only be used if in server mode.
- X*/
- X{
- X server_broadcast (t, PLAYER_SERVER, seat_names[PLAYER_SERVER],
- X msg_type, message);
- X}
- X
- Xvoid send_private_message (c, message)
- X Connection c; char *message;
- X/* static void send_private_message (Connection c, char *message) */
- X/* Only to be used in server mode. Sends a message from the 'server'
- X to the connection c. If the connection c is the local player,
- X then appends the message to the protocol queue of the table of
- X the local player.
- X*/
- X{
- X Message m;
- X
- X if (c->local) {
- X m = loopback_message (c->table, MODERATOR(c->table), message);
- X m->private = 1;
- X } else
- X server_send (c, PLAYER_SERVER, seat_names[PLAYER_SERVER], message);
- X}
- X
- Xstatic void Broadcast_Inline_Data (t, msg_type, buf)
- X Table t;
- X int msg_type;
- X char *buf;
- X/* Broadcasts the contents of buf to each of the connections at table t. */
- X{
- X Connection c, d;
- X
- X if (server_mode) {
- X c = t->Players->onext;
- X while (c != NULL) {
- X d = c->onext;
- X if (May_receive (c, msg_type)) {
- X if (!c->local)
- X server_send_unformatted (c, buf);
- X }
- X c = d;
- X }
- X } else
- X fd_writeln (server_port, buf);
- X}
- X
- Xstatic void Relay_Inline_Data (t, f, msg_type, buf)
- X Table t;
- X Connection f;
- X int msg_type;
- X char *buf;
- X/* Broadcasts the contents of buf to each of the connections at table
- X t EXCEPT f. */
- X{
- X Connection c, d;
- X
- X c = t->Players->onext;
- X while (c != NULL) {
- X d = c->onext;
- X if (May_receive (c, msg_type)) {
- X if ((c != f) && !c->local)
- X server_send_unformatted (c, buf);
- X }
- X c = d;
- X }
- X}
- X
- Xvoid Transmit_board (t, b)
- X Table t;
- X Board *b;
- X/* If we are the server, then transmits the board b to each of the players
- X at the table t. If we are a client, then transmits the board b to
- X the server. */
- X{
- X char buf1[100], buf2[100];
- X
- X Encode_board (b, buf1, buf2);
- X Broadcast_Inline_Data (t, CMD_BOARD, buf1);
- X Broadcast_Inline_Data (t, CMD_BOARD, buf2);
- X}
- X
- Xvoid Transmit_play_record (t, p)
- X Table t;
- X Play_record *p;
- X/* If we are the server, then transmits the play record p to each of the
- X players at the table t. If we are a client, then transmits the play
- X record p to the server. */
- X{
- X char buf1[100], buf2[100], buf3[100];
- X
- X Encode_play_record (p, buf1, buf2, buf3);
- X Broadcast_Inline_Data (t, CMD_RECORD, buf1);
- X Broadcast_Inline_Data (t, CMD_RECORD, buf2);
- X Broadcast_Inline_Data (t, CMD_RECORD, buf3);
- X}
- X
- Xvoid Relay_board (t, c, b)
- X Table t;
- X Connection c;
- X Board *b;
- X/* Relays the in-line board data from the connection c to the other players
- X at the table t.
- X*/
- X{
- X char buf1[100], buf2[100];
- X
- X Encode_board (b, buf1, buf2);
- X Relay_Inline_Data (t, c, CMD_BOARD, buf1);
- X Relay_Inline_Data (t, c, CMD_BOARD, buf2);
- X}
- X
- X
- Xvoid Relay_play_record (t, c, p)
- X Table t;
- X Connection c;
- X Play_record *p;
- X/* Relays the in-line play record from the connection c to the other players
- X at the table t.
- X*/
- X{
- X char buf1[100], buf2[100], buf3[100];
- X
- X Encode_play_record (p, buf1, buf2, buf3);
- X Relay_Inline_Data (t, c, CMD_RECORD, buf1);
- X Relay_Inline_Data (t, c, CMD_RECORD, buf2);
- X Relay_Inline_Data (t, c, CMD_RECORD, buf3);
- X}
- X
- XBoard *Receive_board (c)
- X Connection c;
- X/* Receives a board as in-line data from the connection c. */
- X{
- X char buf1[100], buf2[100];
- X int status;
- X Board *b;
- X int chan;
- X
- X if (client_mode)
- X chan = server_port;
- X else
- X chan = c->channel;
- X
- X status = fd_readln (chan, buf1, 100);
- X if (status <= 0)
- X return (NULL);
- X
- X status = fd_readln(chan, buf2, 100);
- X if (status <= 0)
- X return (NULL);
- X
- X b = Decode_board (buf1, buf2);
- X return (b);
- X}
- X
- XPlay_record *Receive_play_record (c)
- X Connection c;
- X/* Receives a play record as in-line data from the connection c. */
- X{
- X char buf1[100], buf2[100], buf3[100];
- X int status;
- X Play_record *p;
- X int chan;
- X
- X if (client_mode)
- X chan = server_port;
- X else
- X chan = c->channel;
- X
- X status = fd_readln (chan, buf1, 100);
- X if (status < 0)
- X return (NULL);
- X
- X status = fd_readln (chan, buf2, 100);
- X if (status < 0)
- X return (NULL);
- X
- X status = fd_readln (chan, buf3, 100);
- X if (status < 0)
- X return (NULL);
- X
- X p = Decode_play_record (buf1, buf2, buf3);
- X return (p);
- X}
- X
- Xstatic Table Allocate_Table ()
- X/* Allocates a table structure and initializes it. */
- X{
- X Table t;
- X int i;
- X
- X t = (Table) malloc(sizeof(struct Table_struct));
- X
- X for (i = 0; i < PLAYER_TYPES; i++) {
- X/* t->Seats[i].player_name[0] = '\0'; */
- X sprintf (t->Seats[i].player_name, "%s", seat_names[i]);
- X t->Seats[i].occupied = 0;
- X t->Seats[i].connection = NULL;
- X }
- X
- X t->protocol_queue = Allocate_message_queue ();
- X t->conversation_queue = Allocate_message_queue ();
- X t->game_queue = Allocate_message_queue ();
- X
- X /* The first element of the connections list is used to represent
- X the server for the table. */
- X t->Players = Allocate_Dummy_Connection ();
- X t->Players->local = 1;
- X t->Players->seat = PLAYER_SERVER;
- X t->Players->table = t;
- X sprintf (t->Players->player_name, "MOD");
- X
- X t->table_no = 1;
- X t->game_mode = STARTUP_MODE;
- X t->playing_mode = CLUB_PLAYING_MODE;
- X t->board = NULL;
- X t->play_record = NULL;
- X t->above_line[0] = t->above_line[1] = 0;
- X t->below_line[0] = t->below_line[1] = 0;
- X
- X if (Table_List == NULL) {
- X Table_List = t;
- X t->prev = t->next = NULL;
- X } else {
- X t->next = Table_List->next;
- X if (t->next != NULL)
- X t->next->prev = t;
- X t->prev = Table_List;
- X t->prev->next = t;
- X }
- X
- X return (t);
- X}
- X
- Xvoid Initialize_Table_List ()
- X/* Initializes the array of tables. */
- X{
- X Table_List = Local_table = Allocate_Table ();
- X Local_Player_Connection = Allocate_Connection ();
- X
- X Local_Player_Connection->channel = 0;
- X Local_Player_Connection->local = 1;
- X Local_Player_Connection->spectator = 0;
- X Local_Player_Connection->seat = local_player;
- X Local_Player_Connection->table = Local_table;
- X sprintf (Local_Player_Connection->player_name, "%s", local_player_name);
- X
- X if (IS_PLAYER(local_player)) {
- X Local_table->Seats[local_player].connection = Local_Player_Connection;
- X Local_table->Seats[local_player].occupied = 1;
- X sprintf (Local_table->Seats[local_player].player_name, "%s",
- X local_player_name);
- X }
- X
- X Link_Output_Connection (Local_table->Players, Local_Player_Connection);
- X}
- X
- Xvoid Initialize_Network_Logfile ()
- X{
- X#ifdef LOGFILE
- X char buf[80];
- X
- X sprintf (buf, "%s.log", local_player_name);
- X net_log = fopen (buf, "w");
- X if (net_log == NULL) {
- X sprintf (buf, "Error opening net_log file %s: %s", buf,
- X sys_errlist[errno]);
- X fflush (net_log);
- X Terminate_Program (buf);
- X }
- X#endif
- X}
- X
- Xvoid Initialize_Network ()
- X{
- X struct hostent *he;
- X struct passwd *pw_entry;
- X char *my_addr, *user, *name, *p;
- X char buf[100];
- X
- X#ifdef NO_TM_ZONE
- X struct timeval tp;
- X struct timezone tzp;
- X#else
- X time_t current_time;
- X struct tm *decoded_time;
- X#endif
- X
- X gethostname (Host_name, 100);
- X
- X if (!Host_IP_is_known) {
- X he = gethostbyname (Host_name);
- X if (he != NULL) {
- X sprintf (Host_name, "%s", he->h_name);
- X/* in = (struct in_addr *) he->h_addr_list[0];
- X my_addr = inet_ntoa(*in);
- X*/
- X my_addr = inet_ntoa(**((struct in_addr **) he->h_addr_list));
- X if (my_addr == NULL) my_addr = "--";
- X sprintf (Host_IP, "%s", my_addr);
- X Host_IP_is_known = 1;
- X } else
- X sprintf (Host_IP, "--");
- X }
- X
- X pw_entry = getpwuid (getuid());
- X if (pw_entry != NULL) {
- X sprintf (User_name, "%s", pw_entry->pw_name);
- X#ifndef NO_PWCOMMENT
- X if (pw_entry->pw_comment != NULL) {
- X sprintf (User_fullname, "%s", pw_entry->pw_gecos);
- X if ((p = index(User_fullname, ',')) != NULL)
- X *p = '\0';
- X } else
- X#endif
- X if ((name = getenv("NAME")) != NULL)
- X sprintf (User_fullname, "%s", name);
- X else
- X sprintf (User_fullname, "%s", User_name);
- X } else {
- X user = getlogin ();
- X if (user == NULL)
- X user = getenv("USER");
- X if (user == NULL)
- X user = "unknown";
- X sprintf (User_name, "%s", user);
- X name = getenv("NAME");
- X if (name != NULL)
- X sprintf (User_fullname, "%s", name);
- X else if (local_player_full_name != NULL)
- X sprintf (User_fullname, "%s", local_player_full_name);
- X else
- X sprintf (User_fullname, "%s", User_name);
- X }
- X
- X if (local_player_email == NULL) {
- X sprintf (buf, "%s@%s", pw_entry->pw_name, Host_name);
- X local_player_email = strdup (buf);
- X }
- X
- X if (Timezone_name == NULL) {
- X#ifdef NO_TM_ZONE
- X gettimeofday (&tp, &tzp);
- X if (tzp.tz_minuteswest < 0)
- X sprintf (buf, "GMT+%d:%02d",
- X (-tzp.tz_minuteswest)/60, (-tzp.tz_minuteswest)%60);
- X else
- X sprintf (buf, "GMT-%d:%02d",
- X tzp.tz_minuteswest/60, tzp.tz_minuteswest%60);
- X Timezone_name = strdup (buf);
- X#else
- X time (¤t_time);
- X decoded_time = localtime (¤t_time);
- X Timezone_name = strdup(decoded_time->tm_zone);
- X#endif
- X }
- X
- X if (Registration == NULL)
- X Registration = strdup (local_player_email);
- X
- X /* Allocate a dummy head for the connections list. */
- X Connections = Allocate_Dummy_Connection ();
- X
- X Initialize_Network_Logfile ();
- X Initialize_Table_List ();
- X
- X client_mode = server_mode = 0;
- X server_port = listen_port = 0;
- X}
- X
- Xvoid Close_all_connections ()
- X{
- X Connection c, d;
- X Table t;
- X int i;
- X
- X if (server_mode) {
- X if (listen_port > 0) {
- X close (listen_port);
- X listen_port = 0;
- X }
- X
- X for (c = Connections->inext; c != NULL; ) {
- X d = c->inext;
- X if (!c->local) {
- X close_connection (c);
- X Vacate_seat (c->table, c->seat);
- X }
- X c = d;
- X }
- X
- X GPS_End_Server_Mode ();
- X
- X } else if (client_mode) {
- X for (t = Table_List; t != NULL; t = t->next)
- X for (i = 0; i < 4; i++)
- X if ((t != Local_table) || (i != local_player))
- X Vacate_seat (t, i);
- X if (server_port > 0)
- X close(server_port);
- X }
- X
- X/* Initialize_Table_List (); */
- X server_mode = client_mode = 0;
- X server_port = listen_port = 0;
- X}
- X
- Xvoid Switch_Table (c, new_table)
- X Connection c;
- X Table new_table;
- X/* Unlinks the connection c from the current table and links it into
- X the new table.
- X*/
- X{
- X Unlink_Output_Connection (c);
- X Link_Output_Connection (new_table->Players, c);
- X}
- X
- Xvoid Setup_server ()
- X/* Initializes the data structures for the server. */
- X{
- X char comment_buf [80];
- X int retries;
- X time_t current_time;
- X struct tm *decoded_time;
- X
- X retries = 0;
- X do {
- X listen_port = open_port (network_port);
- X retries = retries + 1;
- X if (listen_port <= 0)
- X network_port++;
- X } while ((listen_port <= 0) && (retries < 10));
- X
- X if (listen_port <= 0) {
- X Network_Comment (socket_error);
- X Network_Comment ("ERROR IN SETTING UP SERVER.");
- X return;
- X }
- X
- X sprintf (comment_buf, "ENTERING SERVER MODE ON PORT %d", network_port);
- X Network_Comment (comment_buf);
- X
- X sprintf (PLAYER_NAME(Local_table, PLAYER_SERVER), "%s", local_player_name);
- X
- X server_mode = 1;
- X time (¤t_time);
- X decoded_time = localtime (¤t_time);
- X
- X sprintf (Server_Start_time, "%2d:%02d %s", decoded_time->tm_hour,
- X decoded_time->tm_min, Timezone_name);
- X
- X if (local_player_full_name != NULL)
- X sprintf (Local_Player_Connection->fullname, "%s", local_player_full_name);
- X else if (strlen(User_fullname) > 0)
- X sprintf (Local_Player_Connection->fullname, "%s", User_fullname);
- X
- X if (local_player_email != NULL)
- X sprintf (Local_Player_Connection->email, "%s", local_player_email);
- X sprintf (Local_Player_Connection->registry, "%s", Registration);
- X
- X GPS_Broadcast_Server ();
- X Local_Player_Connection->state = CSTATE_PLAYING;
- X
- X}
- X
- Xvoid Assign_seat ();
- X
- Xvoid Attempt_to_connect (seat_requested)
- X int seat_requested;
- X/* Attempts to connect to the server named as server_name. If the
- X * connection is successful, then initializes the Table data structure
- X * appropriately and sends an initial handshaking message.
- X */
- X{
- X int status; /* Return code from client_init call. */
- X char message_buf [80];
- X
- X sprintf (message_buf, "CONNECTING TO SERVER AT %s, PORT %d.", server_name,
- X network_port);
- X Network_Comment (message_buf);
- X restore_cursor ();
- X
- X status = client_init (server_name, network_port, 3);
- X if (status < 0) {
- X Network_Comment (socket_error);
- X return;
- X }
- X
- X Network_Comment ("CONNECTION ESTABLISHED.");
- X server_port = status;
- X client_mode = 1;
- X
- X /* Now we construct the initial handshake message that we send
- X to the server. This message is of the form:
- X HELLO <ver> <player-name>
- X where
- X <ver> is the current version of the program,
- X <player-name> is the name of the local player.
- X */
- X sprintf (message_buf, "%s HELLO %s %s %s", local_player_name,
- X major_revision_level, local_player_name,
- X seat_names[seat_requested]);
- X fd_writeln (server_port, message_buf);
- X#ifdef LOGFILE
- X fprintf (net_log, " > %s\n", message_buf);
- X fflush (net_log);
- X#endif
- X
- X local_player = PLAYER_OBS;
- X (void) Assign_seat (Local_table, Local_Player_Connection, PLAYER_OBS);
- X Local_Player_Connection->state = CSTATE_CONNECTED;
- X Display_Player_Position();
- X
- X if (local_player_full_name != NULL)
- X Send_fullname (Local_table, local_player_full_name);
- X else if (strlen(User_fullname) > 0)
- X Send_fullname (Local_table, User_fullname);
- X
- X if (local_player_email != NULL)
- X Send_email (Local_table, local_player_email);
- X/* Send_registry (Local_table, Registration); */
- X}
- X
- Xvoid Accept_new_connection ()
- X/* Given that a new connection is waiting to be accepted, makes
- X the connection and begins processing for it.
- X */
- X{
- X Connection c;
- X int fd_conn; /* file descriptor for the connection. */
- X struct sockaddr net_addr;
- X int addrlen;
- X#ifdef DEBUG
- X char error_buf[80];
- X#endif
- X
- X addrlen = sizeof(struct sockaddr);
- X fd_conn = accept (listen_port, &net_addr, &addrlen);
- X if (fd_conn < 0) {
- X sprintf (socket_error, "Connection Error: %s", sys_errlist[errno]);
- X Network_Comment (socket_error);
- X return;
- X }
- X
- X#ifdef LOGFILE
- X fprintf (net_log, "Connection established. fd %d.\n", fd_conn);
- X fflush (net_log);
- X#endif
- X
- X c = Allocate_Connection ();
- X c->local = 0;
- X c->channel = fd_conn;
- X c->spectator = 0;
- X c->state = CSTATE_CONNECTED;
- X c->seat = PLAYER_OBS;
- X c->table = Local_table;
- X Link_Output_Connection (Local_table->Players, c);
- X
- X#ifdef DEBUG
- X sprintf (error_buf, "ACCEPTED A NEW CONNECTION FOR FD %d (%d).",
- X c->channel, listen_port);
- X Network_Comment (error_buf);
- X#endif
- X
- X}
- X
- Xstatic void Get_network_message (c, channel)
- X Connection c; int channel;
- X/* static void Get_network_message (Connection c) */
- X/* Gets a message from connection c, parses it, and processes it. */
- X{
- X int buflen; /* return code from fd_readln */
- X Message m; /* The message which was read from the
- X network. */
- X char msg_buf[100];
- X
- X m = allocate_message ();
- X buflen = fd_readln (channel, m->p.command_text, BUFFER_LENGTH);
- X
- X if (buflen <= 0) {
- X deallocate_message (m);
- X if (server_mode) {
- X sprintf (msg_buf, "THE NETWORK CONNECTION WITH %s HAS BEEN LOST.",
- X c->player_name);
- X close_connection (c);
- X Broadcast_Comment (msg_buf);
- X } else {
- X server_port = 0;
- X Network_Comment
- X ("THE NETWORK CONNECTION WITH THE SERVER HAS BEEN LOST.");
- X Generate_reset (RESET_DISCONNECT);
- X }
- X } else {
- X m->source = c;
- X if (server_mode) {
- X Parse_Command_for_Server (&(m->p));
- X m->p.player_no = c->seat;
- X } else {
- X Parse_Command_for_Client (&(m->p));
- X }
- X
- X /* If we are receiving a BOARD or a RECORD message, then we must also
- X recieve the associated in-line data. */
- X if (m->p.command == CMD_BOARD)
- X m->p.data.board.record = Receive_board (c);
- X else if (m->p.command == CMD_RECORD)
- X m->p.data.record.play = Receive_play_record (c);
- X
- X enqueue_message (c->table->protocol_queue, m);
- X#ifdef LOGFILE
- X fprintf (net_log, "%2d < %s\n", channel, m->p.command_text);
- X fflush (net_log);
- X#endif
- X }
- X}
- X
- Xstatic void Wait_for_keyboard_event ()
- X{
- X int status; /* return code from Select call. */
- X struct fd_set wait_set; /* A set representing the connections that
- X have been established. */
- X
- X do {
- X FD_ZERO (&wait_set);
- X FD_SET (fileno(stdin), &wait_set);
- X
- X if (GPS_request_in_progress && (GPS_socket > 0))
- X FD_SET (GPS_socket, &wait_set);
- X
- X status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0,
- X (struct timeval *) 0);
- X
- X if ((status < 0) && (errno != EINTR)) {
- X sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
- X Network_Comment (socket_error);
- X }
- X } while (status < 0);
- X}
- X
- Xstatic void Client_wait_for_network_event ()
- X{
- X int status; /* return code from Select call. */
- X struct fd_set wait_set; /* A set representing the connections that
- X have been established. */
- X
- X do {
- X FD_ZERO (&wait_set);
- X FD_SET (fileno(stdin), &wait_set);
- X FD_SET (server_port, &wait_set);
- X
- X if (GPS_request_in_progress && (GPS_socket > 0))
- X FD_SET (GPS_socket, &wait_set);
- X
- X status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0,
- X (struct timeval *) 0);
- X
- X if ((status < 0) && (errno != EINTR)) {
- X sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
- X Network_Comment (socket_error);
- X }
- X } while (status < 0);
- X
- X if (FD_ISSET(server_port, &wait_set))
- X Get_network_message (Local_Player_Connection, server_port);
- X}
- X
- Xstatic void Server_wait_for_network_event ()
- X{
- X Connection c, d;
- X int status; /* return code from Select call. */
- X struct fd_set wait_set; /* A set representing the connections that
- X have been established. */
- X int connection_available, data_available;
- X
- X data_available = 0;
- X do {
- X FD_ZERO (&wait_set);
- X
- X /* Set bits in the wait_set corresponding to the open socket
- X descriptors which we have at the moment. */
- X FOREACH_CONNECTION (c) {
- X if (!c->local)
- X FD_SET (c->channel, &wait_set);
- X }
- X
- X FD_SET (fileno(stdin), &wait_set);
- X if (listen_port > 0)
- X FD_SET (listen_port, &wait_set);
- X
- X if (GPS_request_in_progress && (GPS_socket > 0))
- X FD_SET (GPS_socket, &wait_set);
- X
- X status = select (FD_SETSIZE, &wait_set, (fd_set *) 0, (fd_set *) 0,
- X (struct timeval *) 0);
- X
- X connection_available = 0;
- X if (status < 0) {
- X if (errno != EINTR) {
- X sprintf (socket_error, "Error in select: %s", sys_errlist[errno]);
- X Network_Comment (socket_error);
- X }
- X data_available = 0;
- X } else {
- X connection_available = ((listen_port > 0)
- X && FD_ISSET(listen_port, &wait_set));
- X if (connection_available)
- X data_available = status - 1;
- X else
- X data_available = 1;
- X }
- X
- X if (connection_available)
- X Accept_new_connection ();
- X
- X } while (!data_available);
- X
- X c = Connections->inext;
- X while (c != NULL) {
- X d = c->inext;
- X if (!c->local && FD_ISSET(c->channel, &wait_set)) {
- X FD_CLR(c->channel, &wait_set);
- X Get_network_message (c, c->channel);
- X }
- X c = d;
- X }
- X
- X}
- X
- Xvoid Wait_for_network_event ()
- X/* Waits for an input event to occur. If a network event occurs, then
- X parses the message and places it onto the proper player queue.
- X*/
- X{
- X if (server_mode)
- X Server_wait_for_network_event ();
- X else if (client_mode)
- X Client_wait_for_network_event ();
- X else
- X Wait_for_keyboard_event ();
- X
- X#ifdef MDEBUG
- X if (!malloc_verify ()) {
- X Moderator_Comment ("A MEMORY ALLOCATION ERROR HAS BEEN DETECTED!");
- X access_error_routine ();
- X }
- X#endif
- X}
- X
- END_OF_FILE
- if test 33079 -ne `wc -c <'network.c'`; then
- echo shar: \"'network.c'\" unpacked with wrong size!
- fi
- # end of 'network.c'
- fi
- if test -f 'protocol.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'protocol.h'\"
- else
- echo shar: Extracting \"'protocol.h'\" \(18086 characters\)
- sed "s/^X//" >'protocol.h' <<'END_OF_FILE'
- X/* command.h -- Data structures and procedures used for communicating
- X * between the client and server.
- X *
- X ! Copyright (C) 1990-1992 by Matthew Clegg. All Rights Reserved
- X !
- X ! OKbridge is made available as a free service to the Internet.
- X ! Accordingly, the following restrictions are placed on its use:
- X !
- X ! 1. OKbridge may not be modified in any way without the explicit
- X ! permission of Matthew Clegg.
- X !
- X ! 2. OKbridge may not be used in any way for commercial advantage.
- X ! It may not be placed on for-profit networks or on for-profit
- X ! computer systems. It may not be bundled as part of a package
- X ! or service provided by a for-profit organization.
- X !
- X ! If you have questions about restrictions on the use of OKbridge,
- X ! write to mclegg@cs.ucsd.edu.
- X !
- X ! DISCLAIMER: The user of OKbridge accepts full responsibility for any
- X ! damage which may be caused by OKbridge.
- X *
- X * This module defines the data structures and procedures used for
- X * communicating with between the client and server. When a command
- X * is received from a remote machine, this module unpacks it into
- X * a data structure representing the command. When we wish to send
- X * a command to a remote machine, we invoke a procedure which is
- X * tailored for that command.
- X */
- X
- X#define PROTOCOL_INCLUDED
- X
- Xenum
- X{
- X CMD_ERROR = 0,
- X CMD_ACK,
- X CMD_ALERT,
- X CMD_BEGIN,
- X CMD_BID,
- X CMD_BOARD,
- X CMD_CC,
- X CMD_CLAIM,
- X CMD_CLAIMREQ,
- X CMD_CLAIMRESP,
- X CMD_COMMENT,
- X CMD_CONNERR,
- X CMD_DEAL,
- X CMD_ECHO,
- X CMD_EMAIL,
- X CMD_END,
- X CMD_FULLNAME,
- X CMD_HELLO,
- X CMD_MODE,
- X CMD_NAME,
- X CMD_PING,
- X CMD_PLAY,
- X CMD_PLAYREQ,
- X CMD_QUIT,
- X CMD_RECONNECT,
- X CMD_RECORD,
- X CMD_REGISTRY,
- X CMD_RESET,
- X CMD_SCORE,
- X CMD_SEAT,
- X CMD_SEATERR,
- X CMD_SEATPOS,
- X CMD_SEATREQ,
- X CMD_SERVEREQ,
- X CMD_SKIP,
- X CMD_SKIPACK,
- X CMD_SPEC,
- X CMD_TABLE,
- X CMD_TABLEREQ,
- X CMD_TALK,
- X CMD_USEREC,
- X CMD_WAKEUP,
- X CMD_WHO,
- X CMD_WHOIS,
- X CMD_WHORESP,
- X
- X CMD_MAX
- X};
- X
- X#define TALK_RCPT_LHO 0
- X#define TALK_RCPT_RHO 1
- X#define TALK_RCPT_OPPS 2
- X#define TALK_RCPT_SPEC 3
- X#define TALK_RCPT_ALL 4
- X
- X#define DUMMY int
- X
- Xtypedef struct Connection_struct *Conn;
- Xtypedef struct Board_struct *board_ptr;
- Xtypedef struct Play_record_struct *play_ptr;
- Xtypedef struct Table_struct *Table_ptr;
- X
- Xtypedef struct player_command_struct {
- X int command;
- X int player_no;
- X name_buffer player_name;
- X command_buffer command_text;
- X union {
- X struct { message_buffer message; } error;
- X struct { name_buffer player_name;
- X int position; } ack;
- X int alert;
- X DUMMY begin;
- X struct { int level, alert; } bid;
- X struct { name_buffer board_name;
- X int board_no;
- X board_ptr record; } board;
- X message_buffer cc;
- X struct { int no_tricks; } claim;
- X struct { int no_tricks; } claimreq;
- X int claimresp;
- X message_buffer comment;
- X message_buffer connerr;
- X DUMMY deal;
- X struct { name_buffer ping_source; } echo;
- X struct { message_buffer addr; } email;
- X DUMMY end;
- X struct { message_buffer name; } fullname;
- X struct { name_buffer version;
- X name_buffer player_name;
- X int seat_req; } hello;
- X int mode;
- X struct { name_buffer new_name; } name;
- X DUMMY ping;
- X int play;
- X struct { int card;
- X int play_no; } playreq;
- X DUMMY quit;
- X struct {name_buffer ip;
- X int port;
- X int seat; } reconnect;
- X struct { name_buffer board_name;
- X int board_no;
- X play_ptr play; } record;
- X struct { message_buffer id; } registry;
- X DUMMY reset;
- X struct { int above[2];
- X int below[2]; } score;
- X struct { name_buffer player_name;
- X int old_pos;
- X int new_pos; } seat;
- X struct { int free_seats[3]; } seaterr;
- X int seatpos;
- X int seatreq;
- X struct { message_buffer command; } servereq;
- X DUMMY skip;
- X DUMMY skipack;
- X DUMMY spec;
- X int table;
- X int tablereq;
- X struct { int recipients;
- X message_buffer message; } talk;
- X struct { name_buffer north;
- X name_buffer east;
- X name_buffer south;
- X name_buffer west; } userec;
- X struct { name_buffer recipient; } wakeup;
- X DUMMY who;
- X struct { name_buffer name; } whois;
- X struct { name_buffer recipient;
- X message_buffer message; } whoresp;
- X } data;
- X} *player_command;
- X
- X
- X/* The following routines define the interface for sending messages
- X * to remote processes. */
- X
- Xvoid Send_ack ();
- Xvoid Send_alert ();
- Xvoid Send_begin ();
- Xvoid Send_bid ();
- Xvoid Send_board ();
- Xvoid Send_cc ();
- Xvoid Send_claim ();
- Xvoid Send_claimreq ();
- Xvoid Send_claimresp ();
- Xvoid Send_comment ();
- Xvoid Send_deal ();
- Xvoid Send_echo ();
- Xvoid Send_email ();
- Xvoid Send_end ();
- Xvoid Send_fullname ();
- Xvoid Send_hello ();
- Xvoid Send_mode ();
- Xvoid Send_name ();
- Xvoid Send_ping ();
- Xvoid Send_play ();
- Xvoid Send_playreq ();
- Xvoid Send_quit ();
- Xvoid Send_reconnect ();
- Xvoid Send_record ();
- Xvoid Send_registry ();
- Xvoid Send_reset ();
- Xvoid Send_seat ();
- Xvoid Send_seaterr ();
- Xvoid Send_seatreq ();
- Xvoid Send_score ();
- Xvoid Send_servereq ();
- Xvoid Send_skip ();
- Xvoid Send_skipack ();
- Xvoid Send_spec ();
- Xvoid Send_tablereq ();
- Xvoid Send_table ();
- Xvoid Send_talk ();
- Xvoid Send_userec ();
- Xvoid Send_wakeup ();
- Xvoid Send_who ();
- Xvoid Send_whois ();
- Xvoid Send_whoresp ();
- X
- X/* The following two procedures are for parsing messages which have
- X * received from remote hosts. The difference is that in the first
- X * procedure, we assume that the identifier of the sender is prefixed
- X * to the message. Both procedures assume that the input buffer is
- X * stored in the player command record which is passed to the procedure.
- X * Both return 0 if no errors were encountered in parsing the message
- X * and -1 if an error was encountered.
- X */
- X
- Xint Parse_Command_for_Client ();
- Xint Parse_Command_for_Server ();
- X
- X
- X/* DESCRIPTION OF PROTOCOL.
- X
- XAll messages transmitted by okbridge are ASCII strings terminated by
- Xthe characters "\015\012" (^M^J). Each message is interpreted and
- Xconverted into a data structure with the help of the parser module.
- XEach message has a header which identifies the origin of the message.
- XThis is followed by a keyword which identifies the message type.
- XFollowing the keyword, there may be additional type-specific
- Xparameters. The fields in a message are separated by blanks.
- X
- XWhen a client sends a message to the server, it is of the form
- X <client-name> <message-type> <parameters>,
- Xwhere
- X <client-name> is the 8-character nickname of the client,
- X <message-type> is a keyword identifying the type of the message,
- X <parameters> is an optional list of message-specific parameters.
- X
- XWhen a server sends a message to a client, it is of the form
- X <position> <source> <message-type> <parameters>
- Xwhere
- X <position> is the name of the position occupied by the person
- X who originated the message. May be North, South,
- X East, West, Mod or Obs.
- X <source> is the nickname of the person who originated the message.
- X <message-type> is a keyword identifying the type of the message.
- X <parameters> is an optional list of message-specific parameters.
- X
- XTo see the sequence of messages transmitted by the program, compile
- Xwith the -DLOGFILE option.
- X
- XThere are three kinds of messages: protocol messages, conversational
- Xmessages and game messages. A protocol message affects the
- Xcommunications behavior of the program, and is typically handled
- Xdifferently according to whether we are operating in client mode or in
- Xserver mode. For example, the initial handshakes which are performed
- Xwhen a new client connects to the server are protocol messages.
- XConversational messages may affect the state of the game, but not
- Xdirectly. Examples of asynchronous messages are talk messages and
- Xclaim requests. Game messages convey changes to the state of the
- Xgame. Examples of game messages are deals, bids and plays.
- X
- XAll messages are first received by the network module. This module
- Xthen parses the message, creating a data structure as defined in
- Xprotocol.h to represent the message. The message is then put onto the
- Xprotocol queue associated to the table. The protocol queue is handled
- Xby the cs module. After a message from the protocol queue is handled,
- Xit may be put onto the conversational queue. The conversational queue
- Xis handled by the conversation module. After a message from the
- Xconversational queue is handled, it may finally be put onto the game
- Xqueue. The game queue is handled by the bridge module.
- X
- X
- XProtocol Messages
- X-------- --------
- X
- X HELLO <version> <player-name> <position>
- X When a client first establishes a connection to the server, it sends
- X a hello message identifying itself to the server. If the server
- X recognizes the client as using a compatible version of okbridge,
- X then the HELLO message is relayed to the other clients.
- X <version> := a string identifying the major revision level
- X <player-name> := an eight character name identifying the player
- X <position> := the seat requested by the player
- X
- X ACK <player-name> <position>
- X After verifying that the client is using the same version of okbridge,
- X the server sends to the client an ACK message for itself and for each
- X of the other clients, identifying all of the current connections.
- X <player-name> := an eight character name identifying the player
- X <position> := the current position of the player.
- X
- X CONNERR <message>
- X Used by the server to transmit error messages in case the client
- X is not using the same version of okbridge. The message is followed
- X by closing the socket connection.
- X
- X ECHO <ping-source>
- X A message sent in response to a PING request.
- X
- X PING
- X Sends a message which is automatically echoed by each of the other
- X players. The purpose of this message is to determine how quickly
- X the networks are operating.
- X
- X QUIT
- X Transmitted by a player as the final message before closing the
- X socket connection.
- X
- X RECONNECT <ip-name-or-number> <port-number> <seat-name>
- X Transmitted by the server to a player, indicating that the player
- X should reconnect to a new server at the given ip/port and sit
- X at the specified seat.
- X
- X SEAT <old-seat> <new-seat> <player-name>
- X Transmitted by the server to indicate that a player has changed seats.
- X If this message names the local player, it should be ignored.
- X Otherwise, problems may arise when two people choose the same name.
- X
- X SEATERR <seat1> <seat2> <seat3>
- X Transmitted by the server to indicate that the requested seat
- X is not available. The seats <seat1>, <seat2>, <seat3> list the
- X currently free seats.
- X
- X SEATPOS <seat-assignment>
- X Indicates the seat which is assigned to the local player.
- X This is a mandatory assignment, and may not necessarily be the
- X seat which was requested. Note that when a player makes a
- X seat request, he will receive a SEATPOS assignment and also
- X a SEAT message which is broadcast to everyone.
- X
- X SEATREQ <seat-name>
- X Requests a seat assignment from the server.
- X
- X SERVEREQ <command-name>
- X Makes a special request to the server which is not covered by
- X the other message types. The server is free to the <command-name>
- X in an implementation-specific way.
- X
- X TABLEREQ <requested-table-number>
- X Transmitted by a player to make a request to sit at the requested
- X table.
- X
- X TABLE <assigned-table-number>
- X Transmitted by the server to the table number assigned to the local
- X player.
- X
- X
- XConversational Messages
- X-------------- --------
- X
- X COMMENT <message>
- X Carries a message to each of the players which is from the MODERATOR.
- X
- X CC <convention-card>
- X Conveys the convention card which is in use by the team of the person
- X sending the message.
- X
- X CLAIMREQ n
- X Transmits a request by the declarer to claim n additional tricks.
- X The defenders should each respond with a CLAIMRESP message.
- X
- X CLAIMRESP YES|NO
- X Transmits a defender's response to a claim request message.
- X
- X EMAIL <email-address>
- X Transmits a player's email address to the server.
- X
- X FULLNAME <full-name>
- X Transmits a players full name to the server.
- X
- X NAME <new-name>
- X Informs the other players that the local player has changed his
- X or her name.
- X
- X REGISTRY <identification>
- X Registers a unique identity for the player with the server.
- X This is independent of the name supplied with the NAME command,
- X which may change.
- X
- X RESET
- X Resets the program to its initial state. Can only be used by server.
- X
- X SPEC
- X Sent by a player to indicate that s/he has entered spectator mode.
- X
- X TALK <recipients> <message>
- X Sends a message to the <recipients> from a player.
- X
- X WAKEUP [<player-name>|ALL]
- X Sends a wake-up signal. If <player-name> is specified, then
- X only that player receives the signal. Otherwise, everyone receives
- X the signal.
- X
- X WHO
- X Asks the server to generate a brief list of the people who are
- X currently connected.
- X
- X WHOIS <player-name>
- X Asks the player with name <player-name> to identify him/herself.
- X The identification should consist of the player's full name and
- X email address.
- X
- X WHORESP <recipient> <ident>
- X A response to the WHOIS message, <recipient> is the name of the
- X player who issued the WHOIS message and <ident> is the identifying
- X message returned by the target of the WHOIS message.
- X
- X
- X
- XGame Messages
- X---- --------
- X
- X ALERT <formal-mode>
- X Alerts the most recent bid by the partner of the transmitting player.
- X <formal-mode> is a boolean flag indicating whether or not the
- X bid should be displayed to partner as well.
- X
- X BEGIN
- X Sent by the server to announce that bidding should begin.
- X
- X BID <bid-name> [ALERT]
- X Reports a bid to the other players. The keyword ALERT appears
- X if the bidder has alerted his own bid.
- X
- X BOARD <board-name> <sequence-number>
- X Initiates the transmission of a board for play. The board name
- X and number are recorded along with the board itself in the local
- X database of boards. The board itself is then transmitted as
- X in-line data following the message. This board is then made the
- X Local_board, so it will be used in subsequent play.
- X Any subsequent RECORD messages apply to this board.
- X
- X CLAIM n
- X Claims n of the remaining tricks. Can only be used by the declarer
- X when it is his turn to play.
- X
- X DEAL
- X Sent by the server to announce the beginning of a new hand.
- X This message will be followed by a BOARD message plus one or more
- X RECORD messages from the server. Bidding will be allowed to
- X commence when the server sends a BEGIN command.
- X
- X END
- X Sent by the server at the end of each hand to cause each client
- X to re-enter the initial mode.
- X
- X MODE CLUB|PRACTICE|FORMAL
- X Sets the playing mode. Club mode is the usual mode of play.
- X Practice mode is used by two or more people to practice bidding
- X and planning play. In practice mode, the following behaviors occur:
- X 1. During bidding, the players who are sitting may bid. When it
- X is time for a bid to be made from an unoccupied seat, the program
- X automatically supplies a bid of "PASS".
- X 2. During play, the cards are revealed to everyone, and anyone may
- X specify the next card to be played.
- X 3. A hand may be ended with the /claim command. Confirmation is not
- X requested for claims.
- X In formal mode, the following actions are taken:
- X 1. Alerts are not shown to the partner of the person making the alert.
- X 2. Talk messages are not transmitted to partner.
- X 3. The dummy is not displayed to anyone until the opening lead has
- X been made.
- X 4. The bidding cannot be reviewed after play has begun.
- X
- X PLAY <card-name>
- X Reports a play of a card to the other players.
- X
- X PLAYREQ <card-name> <sequence-number>
- X Requests from the server that the given card be played for the
- X given play number. The PLAYREQ message is needed only during
- X practice mode, when multiple players may attempt to play
- X simultaneously.
- X
- X RECORD <board-name> <sequence-number>
- X Initiates the transmission of a record of play. The record itself
- X is transmitted as in-line data following the message. This record
- X pertains to the board having the given name and number. If this is
- X the name of the current board.
- X
- X SCORE <above-ns> <above-ew> <below-ns> <below-ew>
- X A message sent by the server to indicate the current scoring totals.
- X This may be independent of the scores which have been computed for
- X the hands that have been played.
- X
- X SKIP
- X Ends the current hand prematurely, causing all players to return
- X to STARTUP_MODE. Does not record a score for the hand.
- X
- X SKIPACK
- X Sent by each player in response to a skip message, indicating that
- X the local player has reset his state to startup mode.
- X
- X USEREC <north-name> <east-name> <south-name> <west-name>
- X A message sent by the server to indicate which play record should
- X is being used in the current hand.
- X*/
- END_OF_FILE
- if test 18086 -ne `wc -c <'protocol.h'`; then
- echo shar: \"'protocol.h'\" unpacked with wrong size!
- fi
- # end of 'protocol.h'
- fi
- echo shar: End of archive 7 \(of 14\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 14 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-