diff socket.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/socket.c	Sat Dec 06 05:41:29 1997 +0000
@@ -0,0 +1,3380 @@
+/* $Id: socket.c,v 1.1.1.1 1997/12/06 05:41:31 darius Exp $ */
+
+/*
+ * Socket.c
+ *
+ * Kevin P. Smith 1/29/89
+ * UDP stuff v1.0 by Andy McFadden  Feb-Apr 1992
+ *
+ * UDP protocol v1.0
+ *
+ * Routines to allow connection to the xtrek server.
+ */
+#include "copyright2.h"
+
+/* to see the packets sent/received: [BDyess] */
+#if 0
+#define SHOW_SEND
+#define SHOW_RECEIVED
+#endif				/* 0 */
+
+#ifndef GATEWAY
+#define USE_PORTSWAP		/* instead of using recvfrom() */
+#endif
+
+#undef USE_PORTSWAP		/* recvfrom is a better scheme */
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#ifdef RS6K
+#include <sys/select.h>
+#endif
+#ifndef DNET
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#else
+#include <devices/timer.h>
+#include <dos/dos.h>
+#endif				/* DNET */
+#include <math.h>
+#include <errno.h>
+#include <zlib.h>		/* for terrain info */
+#include "Wlib.h"
+#include "defs.h"
+#include "struct.h"
+#include "data.h"
+#include "packets.h"
+#include "proto.h"
+#include "gameconf.h"
+#ifdef SOUND
+#include "Slib.h"
+#endif				/* SOUND */
+#include "sound.h"
+
+#define INCLUDE_SCAN		/* include Amdahl scanning beams */
+#define INCLUDE_VISTRACT	/* include visible tractor beams */
+
+#ifdef GATEWAY
+/*
+ * (these values are now defined in "main.c":)
+ * char *gw_mach        = "charon";     |client gateway; strcmp(serverName)
+ * int   gw_serv_port   = 5000;         |what to tell the server to use
+ * int   gw_port        = 5001;         |where we will contact gw
+ * int   gw_local_port  = 5100;         |where we expect gw to contact us
+ *
+ * The client binds to "5100" and sends "5000" to the server (TCP).  The
+ * server sees that and sends a UDP packet to gw on port udp5000, which passes
+ * it through to port udp5100 on the client.  The client-gw gets the server's
+ * host and port from recvfrom.  (The client can't use the same method since
+ * these sockets are one-way only, so it connect()s to gw_port (udp5001)
+ * on the gateway machine regardless of what the server sends.)
+ *
+ * So all we need in .gwrc is:
+ *      udp 5000 5001 tde.uts 5100
+ *
+ * assuming the client is on tde.uts.  Note that a UDP declaration will
+ * work for ANY server, but you need one per player, and the client has to
+ * have the port numbers in advance.
+ *
+ * If we're using a standard server, we're set.  If we're running through a
+ * gatewayed server, we have to do some unpleasant work on the server side...
+ */
+#endif
+
+#ifdef SIZE_LOGGING
+int     send_total = 0;
+int     receive_total = 0;
+#endif				/* SIZE_LOGGING */
+
+/* Prototypes */
+static void resetForce P((void));
+static void checkForce P((void));
+#ifdef nodef
+static void set_tcp_opts P((int s));
+static void set_udp_opts P((int s));
+#endif				/* nodef */
+static int doRead P((int asock));
+static void handleTorp P((struct torp_spacket * packet));
+static void handleTorpInfo P((struct torp_info_spacket * packet));
+static void handleStatus P((struct status_spacket * packet));
+static void handleSelf P((struct you_spacket * packet));
+static void handlePlayer P((struct player_spacket * packet));
+static void handleWarning P((struct warning_spacket * packet));
+void sendServerPacket P((struct player_spacket * packet));
+static void handlePlanet P((struct planet_spacket * packet));
+static void handlePhaser P((struct phaser_spacket * packet));
+void handleMessage P((struct mesg_spacket * packet));
+static void handleQueue P((struct queue_spacket * packet));
+static void handlePickok P((struct pickok_spacket * packet));
+static void handleLogin P((struct login_spacket * packet));
+static void handlePlasmaInfo P((struct plasma_info_spacket * packet));
+static void handlePlasma P((struct plasma_spacket * packet));
+static void handleFlags P((struct flags_spacket * packet));
+static void handleKills P((struct kills_spacket * packet));
+static void handlePStatus P((struct pstatus_spacket * packet));
+static void handleMotd P((struct motd_spacket * packet));
+static void handleMask P((struct mask_spacket * packet));
+static void pickSocket P((int old));
+static void handleBadVersion P((struct badversion_spacket * packet));
+int gwrite P((int fd, char *buf, int bytes));
+static void handleHostile P((struct hostile_spacket * packet));
+static void handlePlyrLogin P((struct plyr_login_spacket * packet));
+static void handleStats P((struct stats_spacket * packet));
+static void handlePlyrInfo P((struct plyr_info_spacket * packet));
+static void handlePlanetLoc P((struct planet_loc_spacket * packet));
+static void handleReserved P((struct reserved_spacket * packet));
+
+static void handleScan P((struct scan_spacket * packet));
+static void handleSequence P((struct sequence_spacket * packet));
+static void handleUdpReply P((struct udp_reply_spacket * packet));
+static void informScan P((int p));
+static int openUdpConn P((void));
+#ifdef USE_PORTSWAP
+static int connUdpConn P((void));
+#endif
+static int recvUdpConn P((void));
+static void printUdpInfo P((void));
+/*static void dumpShip P((struct ship *shipp ));*/
+/*static int swapl P((int in ));*/
+static void handleShipCap P((struct ship_cap_spacket * packet));
+static void handleMotdPic P((struct motd_pic_spacket * packet));
+static void handleStats2 P((struct stats_spacket2 * packet));
+static void handleStatus2 P((struct status_spacket2 * packet));
+static void handlePlanet2 P((struct planet_spacket2 * packet));
+static void handleTerrain2 P((struct terrain_packet2 * pkt));
+static void handleTerrainInfo2 P((struct terrain_info_packet2 *pkt));
+static void handleTempPack P((struct obvious_packet * packet));
+static void handleThingy P((struct thingy_spacket * packet));
+static void handleThingyInfo P((struct thingy_info_spacket * packet));
+static void handleRSAKey P((struct rsa_key_spacket * packet));
+void    handlePing();
+static void handleExtension1 P((struct paradiseext1_spacket *));
+
+static void handleEmpty();
+
+
+#ifdef SHORT_PACKETS
+void    handleShortReply(), handleVPlayer(), handleVTorp(),
+        handleSelfShort(), handleSelfShip(), handleVPlanet(), handleSWarning();
+void    handleVTorpInfo(), handleSMessage();
+#endif
+
+#ifdef FEATURE
+void    handleFeature();	/* feature.c */
+#endif
+
+struct packet_handler handlers[] = {
+    {NULL},			/* record 0 */
+    {handleMessage},		/* SP_MESSAGE */
+    {handlePlyrInfo},		/* SP_PLAYER_INFO */
+    {handleKills},		/* SP_KILLS */
+    {handlePlayer},		/* SP_PLAYER */
+    {handleTorpInfo},		/* SP_TORP_INFO */
+    {handleTorp},		/* SP_TORP */
+    {handlePhaser},		/* SP_PHASER */
+    {handlePlasmaInfo},		/* SP_PLASMA_INFO */
+    {handlePlasma},		/* SP_PLASMA */
+    {handleWarning},		/* SP_WARNING */
+    {handleMotd},		/* SP_MOTD */
+    {handleSelf},		/* SP_YOU */
+    {handleQueue},		/* SP_QUEUE */
+    {handleStatus},		/* SP_STATUS */
+    {handlePlanet},		/* SP_PLANET */
+    {handlePickok},		/* SP_PICKOK */
+    {handleLogin},		/* SP_LOGIN */
+    {handleFlags},		/* SP_FLAGS */
+    {handleMask},		/* SP_MASK */
+    {handlePStatus},		/* SP_PSTATUS */
+    {handleBadVersion},		/* SP_BADVERSION */
+    {handleHostile},		/* SP_HOSTILE */
+    {handleStats},		/* SP_STATS */
+    {handlePlyrLogin},		/* SP_PL_LOGIN */
+    {handleReserved},		/* SP_RESERVED */
+    {handlePlanetLoc},		/* SP_PLANET_LOC */
+    {handleScan},		/* SP_SCAN (ATM) */
+    {handleUdpReply},		/* SP_UDP_STAT */
+    {handleSequence},		/* SP_SEQUENCE */
+    {handleSequence},		/* SP_SC_SEQUENCE */
+    {handleRSAKey},		/* SP_RSA_KEY */
+    {handleMotdPic},		/* SP_MOTD_PIC */
+    {handleStats2},		/* SP_STATS2 */
+    {handleStatus2},		/* SP_STATUS2 */
+    {handlePlanet2},		/* SP_PLANET2 */
+    {handleTempPack},		/* SP_TEMP_5 */
+    {handleThingy},		/* SP_THINGY */
+    {handleThingyInfo},		/* SP_THINGY_INFO */
+    {handleShipCap},		/* SP_SHIP_CAP */
+
+#ifdef SHORT_PACKETS
+    {handleShortReply},		/* SP_S_REPLY */
+    {handleSMessage},		/* SP_S_MESSAGE */
+    {handleSWarning},		/* SP_S_WARNING */
+    {handleSelfShort},		/* SP_S_YOU */
+    {handleSelfShip},		/* SP_S_YOU_SS */
+    {handleVPlayer},		/* SP_S_PLAYER */
+#else
+    {handleEmpty},		/* 40 */
+    {handleEmpty},		/* 41 */
+    {handleEmpty},		/* 42 */
+    {handleEmpty},		/* 43 */
+    {handleEmpty},		/* 44 */
+    {handleEmpty},		/* 45 */
+#endif
+    {handlePing},		/* SP_PING */
+#ifdef SHORT_PACKETS
+    {handleVTorp},		/* SP_S_TORP */
+    {handleVTorpInfo},		/* SP_S_TORP_INFO */
+    {handleVTorp},		/* SP_S_8_TORP */
+    {handleVPlanet},		/* SP_S_PLANET */
+#else
+    {handleEmpty},		/* 47 */
+    {handleEmpty},
+    {handleEmpty},
+    {handleEmpty},		/* 50 */
+#endif
+    {handleGameparams},
+    {handleExtension1},
+    {handleTerrain2},		/* 53 */
+    {handleTerrainInfo2},
+    {handleEmpty},
+    {handleEmpty},
+    {handleEmpty},
+    {handleEmpty},
+    {handleEmpty},		/* 59 */
+#ifdef FEATURE
+    {handleFeature},		/* SP_FEATURE */
+#else
+    {handleEmpty},		/* 60 */
+#endif
+};
+
+#define NUM_HANDLERS	(sizeof(handlers)/sizeof(*handlers))
+
+#define NUM_PACKETS (sizeof(handlers) / sizeof(handlers[0]) - 1)
+
+int     serverDead = 0;
+
+int UdpLocalPort = 0;	/* do we want a specified local UDP port */
+
+#ifdef SIZE_LOGGING
+void
+print_totals()
+/* prints the total number of bytes sent/received.  Called when exiting the
+   client [BDyess] */
+{
+    time_t  timeSpent = time(NULL) - timeStart;
+
+    /*
+       printf("Total bytes sent:     %d\nTotal bytes received: %d\n",
+       send_total, receive_total);
+    */
+    /* ftp format [BDyess] */
+    if (timeSpent < 600 /* 10 minutes */ ) {
+	printf("%8d bytes sent     in %d seconds (%.3f Kbytes/s)\n",
+	       send_total, timeSpent,
+	       (float) send_total / (1024.0 * timeSpent));
+	printf("%8d bytes received in %d seconds (%.3f Kbytes/s)\n",
+	       receive_total, timeSpent,
+	       (float) receive_total / (1024.0 * timeSpent));
+    } else {			/* number too big for seconds, use minutes */
+	printf("%8d bytes sent     in %.1f minutes (%.3f Kbytes/s)\n",
+	       send_total, timeSpent / 60.0,
+	       (float) send_total / (1024.0 * timeSpent));
+	printf("%8d bytes received in %.1f minutes (%.3f Kbytes/s)\n",
+	       receive_total, timeSpent / 60.0,
+	       (float) receive_total / (1024.0 * timeSpent));
+    }
+}
+#else
+#define EXIT exit
+#endif				/* SIZE_LOGGING */
+
+int     udpLocalPort = 0;
+static int udpServerPort = 0;
+static long serveraddr = 0;
+static long sequence = 0;
+static int drop_flag = 0;
+static int chan = -1;		/* tells sequence checker where packet is
+				   from */
+static short fSpeed, fDirection, fShield, fOrbit, fRepair, fBeamup, fBeamdown, fCloak,
+        fBomb, fDockperm, fPhaser, fPlasma, fPlayLock, fPlanLock, fTractor,
+        fRepress;
+
+/* reset all the "force command" variables */
+static void
+resetForce()
+{
+    fSpeed = fDirection = fShield = fOrbit = fRepair = fBeamup = fBeamdown =
+    fCloak = fBomb = fDockperm = fPhaser = fPlasma = fPlayLock = fPlanLock =
+    fTractor = fRepress = -1;
+}
+
+/*
+ * If something we want to happen hasn't yet, send it again.
+ *
+ * The low byte is the request, the high byte is a max count.  When the max
+ * count reaches zero, the client stops trying.  Checking is done with a
+ * macro for speed & clarity.
+ */
+#define FCHECK_FLAGS(flag, force, const) {                      \
+        if (force > 0) {                                        \
+            if (((me->p_flags & flag) && 1) ^ ((force & 0xff) && 1)) {  \
+                speedReq.type = const;                          \
+                speedReq.speed = (force & 0xff);                \
+                sendServerPacket((struct player_spacket *)&speedReq);   \
+                V_UDPDIAG(("Forced %d:%d\n", const, force & 0xff));     \
+                force -= 0x100;                                 \
+                if (force < 0x100) force = -1;  /* give up */   \
+            } else                                              \
+                force = -1;                                     \
+        }                                                       \
+}
+#define FCHECK_VAL(value, force, const) {                       \
+        if (force > 0) {                                        \
+            if ((value) != (force & 0xff)) {                    \
+                speedReq.type = const;                          \
+                speedReq.speed = (force & 0xff);                \
+                sendServerPacket((struct player_spacket *)&speedReq);   \
+                V_UDPDIAG(("Forced %d:%d\n", const, force & 0xff));     \
+                force -= 0x100;                                 \
+                if (force < 0x100) force = -1;  /* give up */   \
+            } else                                              \
+                force = -1;                                     \
+        }                                                       \
+}
+#define FCHECK_TRACT(flag, force, const) {                      \
+        if (force > 0) {                                        \
+            if (((me->p_flags & flag) && 1) ^ ((force & 0xff) && 1)) {  \
+                tractorReq.type = const;                        \
+                tractorReq.state = ((force & 0xff) >= 0x40);    \
+                tractorReq.pnum = (force & 0xff) & (~0x40);     \
+                sendServerPacket((struct player_spacket *)&tractorReq); \
+                V_UDPDIAG(("Forced %d:%d/%d\n", const,          \
+                        tractorReq.state, tractorReq.pnum));    \
+                force -= 0x100;                                 \
+                if (force < 0x100) force = -1;  /* give up */   \
+            } else                                              \
+                force = -1;                                     \
+        }                                                       \
+}
+
+static void
+checkForce()
+{
+    struct speed_cpacket speedReq;
+    struct tractor_cpacket tractorReq;
+
+    /* upgrading kludge [BDyess] */
+    if (!upgrading)
+	FCHECK_VAL(me->p_speed, fSpeed, CP_SPEED);	/* almost always repeats */
+    FCHECK_VAL(me->p_dir, fDirection, CP_DIRECTION);	/* (ditto) */
+    FCHECK_FLAGS(PFSHIELD, fShield, CP_SHIELD);
+    FCHECK_FLAGS(PFORBIT, fOrbit, CP_ORBIT);
+    FCHECK_FLAGS(PFREPAIR, fRepair, CP_REPAIR);
+    FCHECK_FLAGS(PFBEAMUP, fBeamup, CP_BEAM);
+    FCHECK_FLAGS(PFBEAMDOWN, fBeamdown, CP_BEAM);
+    FCHECK_FLAGS(PFCLOAK, fCloak, CP_CLOAK);
+    FCHECK_FLAGS(PFBOMB, fBomb, CP_BOMB);
+    FCHECK_FLAGS(PFDOCKOK, fDockperm, CP_DOCKPERM);
+    FCHECK_VAL(phasers[me->p_no].ph_status, fPhaser, CP_PHASER);	/* bug: dir 0 */
+    FCHECK_VAL(plasmatorps[me->p_no].pt_status, fPlasma, CP_PLASMA);	/* (ditto) */
+    FCHECK_FLAGS(PFPLOCK, fPlayLock, CP_PLAYLOCK);
+    FCHECK_FLAGS(PFPLLOCK, fPlanLock, CP_PLANLOCK);
+
+#ifdef HOCKEY
+    /* kludge to help prevent self-deflects */
+    if(! (hockey && me->p_tractor == 'g'-'a'+10 /*puck*/)) {
+#endif
+      FCHECK_TRACT(PFTRACT, fTractor, CP_TRACTOR);
+      FCHECK_TRACT(PFPRESS, fRepress, CP_REPRESS);
+#ifdef HOCKEY
+    }
+#endif
+}
+
+
+int
+idx_to_mask(i)
+    int     i;
+{
+    if (i == number_of_teams)
+	return ALLTEAM;
+    return 1 << i;
+}
+
+int
+mask_to_idx(m)
+    int     m;
+{
+    int     i, j;
+    for (i = 1, j = -1; m > 0 && i < 5; i++, m >>= 1)
+	if (m & 1)
+	    j += i;
+    if (j > number_of_teams)
+	j = number_of_teams;
+    return j;
+}
+
+
+void
+connectToServer(port)
+    int     port;
+{
+#ifndef DNET
+    int     s;
+    struct sockaddr_in addr;
+    struct sockaddr_in naddr;
+    int     len;
+    fd_set  readfds;
+    struct timeval timeout;
+    struct hostent *hp;
+
+    serverDead = 0;
+    if (sock != -1) {
+	shutdown(sock, 2);
+	sock = -1;
+    }
+    sleep(3);			/* I think this is necessary for some unknown
+				   reason */
+
+#ifdef RWATCH
+    printf("rwatch: Waiting for connection. \n");
+#else
+    printf("Waiting for connection (port %d). \n", port);
+#endif				/* RWATCH */
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+#ifdef RWATCH
+	printf("rwatch: I can't create a socket\n");
+#else
+	printf("I can't create a socket\n");
+#endif				/* RWATCH */
+#ifdef AUTOKEY
+	if (autoKey)
+	    W_AutoRepeatOn();
+#endif
+
+	EXIT(2);
+    }
+#ifndef RWATCH
+#ifdef nodef			/* don't use for now */
+    set_tcp_opts(s);
+#endif				/* nodef */
+#endif				/* RWATCH */
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = INADDR_ANY;
+    addr.sin_port = htons(port);
+
+    if (bind(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+	sleep(10);
+	if (bind(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+	    sleep(10);
+	    if (bind(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+#ifdef RWATCH
+		printf("rwatch: I can't bind to port!\n");
+#else
+		printf("I can't bind to port!\n");
+#endif				/* RWATCH */
+#ifdef AUTOKEY
+		if (autoKey)
+		    W_AutoRepeatOn();
+#endif
+
+		EXIT(3);
+	    }
+	}
+    }
+    listen(s, 1);
+
+    len = sizeof(naddr);
+
+tryagain:
+    timeout.tv_sec = 240;	/* four minutes */
+    timeout.tv_usec = 0;
+    FD_ZERO(&readfds);
+    FD_SET(s, &readfds);
+    if (select(32, &readfds, NULL, NULL, &timeout) == 0) {
+#ifdef RWATCH
+	printf("rwatch: server died.\n");
+#else
+	printf("Well, I think the server died!\n");
+#endif				/* RWATCH */
+#ifdef AUTOKEY
+	if (autoKey)
+	    W_AutoRepeatOn();
+#endif
+
+	EXIT(0);
+    }
+    sock = accept(s, (struct sockaddr *) & naddr, &len);
+
+    if (sock == -1) {
+#ifdef RWATCH
+	perror("rwatch: accept");
+#else
+	perror("accept");
+#endif				/* RWATCH */
+	goto tryagain;
+    }
+    close(s);
+    pickSocket(port);		/* new socket != port */
+
+
+    /*
+       This is strictly necessary; it tries to determine who the caller is,
+       and set "serverName" and "serveraddr" appropriately.
+    */
+    len = sizeof(struct sockaddr_in);
+    if (getpeername(sock, (struct sockaddr *) & addr, &len) < 0) {
+	perror("unable to get peername");
+	serverName = "nowhere";
+    } else {
+	serveraddr = addr.sin_addr.s_addr;
+	hp = gethostbyaddr((char *) &addr.sin_addr.s_addr, sizeof(long), AF_INET);
+	if (hp != NULL) {
+	    serverName = (char *) malloc(strlen(hp->h_name) + 1);
+	    strcpy(serverName, hp->h_name);
+	} else {
+	    serverName = (char *) malloc(strlen((char *) inet_ntoa(addr.sin_addr)) + 1);
+	    strcpy(serverName, (char *) inet_ntoa(addr.sin_addr));
+	}
+    }
+    printf("Connection from server %s (0x%x)\n", serverName, serveraddr);
+
+#else				/* DNET */
+    /*
+       unix end DNet server process connects to the server, on specified *
+       port
+    */
+    ConnectToDNetServer(port);
+#endif				/* DNET */
+
+}
+
+
+#ifndef DNET
+#ifdef nodef
+static void
+set_tcp_opts(s)
+    int     s;
+{
+    int     optval = 1;
+    struct protoent *ent;
+
+    ent = getprotobyname("TCP");
+    if (!ent) {
+	fprintf(stderr, "TCP protocol not found.\n");
+	return;
+    }
+    if (setsockopt(s, ent->p_proto, TCP_NODELAY, &optval, sizeof(int)) < 0)
+	perror("setsockopt");
+}
+
+static void
+set_udp_opts(s)
+    int     s;
+{
+    int     optval = BUFSIZ;
+    struct protoent *ent;
+    ent = getprotobyname("UDP");
+    if (!ent) {
+	fprintf(stderr, "UDP protocol not found.\n");
+	return;
+    }
+    if (setsockopt(s, ent->p_proto, SO_RCVBUF, &optval, sizeof(int)) < 0)
+	perror("setsockopt");
+}
+#endif				/* nodef */
+
+#endif				/* DNET */
+
+void
+callServer(port, server)
+    int     port;
+    char   *server;
+{
+#ifndef DNET
+    int     s;
+    struct sockaddr_in addr;
+    struct hostent *hp;
+#endif
+    serverDead = 0;
+
+    printf("Calling %s on port %d.\n", server, port);
+#ifdef DNET
+    CallDNetServer(server, port);
+#else
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	printf("I can't create a socket\n");
+	EXIT(0);
+    }
+#ifndef RWATCH
+#ifdef nodef
+    set_tcp_opts(s);
+#endif				/* nodef */
+#endif				/* RWATCH */
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    if ((addr.sin_addr.s_addr = inet_addr(server)) == -1) {
+	if ((hp = gethostbyname(server)) == NULL) {
+	    printf("Who is %s?\n", server);
+	    EXIT(0);
+	} else {
+	    addr.sin_addr.s_addr = *(long *) hp->h_addr;
+	}
+    }
+    serveraddr = addr.sin_addr.s_addr;
+
+    if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+	printf("Server not listening!\n");
+	EXIT(0);
+    }
+    printf("Got connection.\n");
+
+    sock = s;
+#endif				/* DNET */
+/* pickSocket is utterly useless with DNet, but the server needs the
+   packet to tell it the client is ready to start. */
+
+#ifdef RECORDER
+    startRecorder();
+#endif
+    pickSocket(port);		/* new socket != port */
+}
+
+int
+isServerDead()
+{
+    return (serverDead);
+}
+
+void
+socketPause(sec, usec)
+    int     sec, usec;
+{
+    struct timeval timeout;
+    fd_set  readfds;
+
+#ifdef RECORDER
+    if (playback)
+	return;
+#endif
+#ifdef DNET
+    (void) DNetServerPause(sec, usec, 0);
+#else
+
+    timeout.tv_sec = sec;
+    timeout.tv_usec = usec;
+    FD_ZERO(&readfds);
+    FD_SET(sock, &readfds);
+    if (udpSock >= 0)		/* new */
+	FD_SET(udpSock, &readfds);
+    select(32, &readfds, 0, 0, &timeout);
+#endif				/* DNET */
+}
+
+int
+readFromServer()
+{
+    struct timeval timeout;
+    fd_set  readfds;
+    int     retval = 0, rs;
+
+#ifdef RECORDER
+    if (playback) {
+	while (!pb_update)
+	    doRead(sock);
+	return 1;
+    }
+#endif
+
+    if (serverDead)
+	return (0);
+    if (commMode == COMM_TCP)
+	drop_flag = 0;		/* just in case */
+
+#ifndef DNET
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    FD_ZERO(&readfds);
+    FD_SET(sock, &readfds);
+    if (udpSock >= 0)
+	FD_SET(udpSock, &readfds);
+    if ((rs = select(32, &readfds, 0, 0, &timeout)) != 0) {
+	if (rs < 0) {
+	    /* NEW */
+	    perror("select");
+	    return 0;
+	}
+#else
+	/* this should have been done before calling the function.. not sure about this, should maybe be doing
+	   DNetServerPause here? -JR*/
+	/*	sigsPending=Wait(sockMask | udpSockMask | SIGBREAKF_CTRL_C);
+	 */
+	if (sigsPending & SIGBREAKF_CTRL_C) {
+	    printf("readFromServer: Ctrl-C break, exiting\n");
+	    exit(0);
+	}
+	/* note for DNet FD_ISSET is  redefined. */
+#endif				/* DNET */
+	/* Read info from the xtrek server */
+	if (FD_ISSET(sock, &readfds)) {
+	    chan = sock;
+	    retval += doRead(sock);
+	}
+	if (udpSock >= 0 && FD_ISSET(udpSock, &readfds)) {
+	    /* WAS V_ *//* should be! */
+	    V_UDPDIAG(("Activity on UDP socket\n"));
+	    chan = udpSock;
+	    if (commStatus == STAT_VERIFY_UDP) {
+		warning("UDP connection established");
+		sequence = 0;	/* reset sequence #s */
+		resetForce();
+		
+		if (udpDebug)
+		    printUdpInfo();
+		UDPDIAG(("UDP connection established.\n"));
+		
+		commMode = COMM_UDP;
+		commStatus = STAT_CONNECTED;
+		commSwitchTimeout = 0;
+		if (udpClientRecv != MODE_SIMPLE)
+		    sendUdpReq(COMM_MODE + udpClientRecv);
+		if (udpWin) {
+		    udprefresh(UDP_CURRENT);
+		    udprefresh(UDP_STATUS);
+		}
+	    }
+	    retval += doRead(udpSock);
+	}
+#ifndef DNET
+    }
+#endif
+
+    /* if switching comm mode, decrement timeout counter */
+    if (commSwitchTimeout > 0) {
+	if (!(--commSwitchTimeout)) {
+	    /*
+	      timed out; could be initial request to non-UDP server (which won't
+	      be answered), or the verify packet got lost en route to the
+	      server.  Could also be a request for TCP which timed out (weird),
+	      in which case we just reset anyway.
+	      */
+	    commModeReq = commMode = COMM_TCP;
+	    commStatus = STAT_CONNECTED;
+	    if (udpSock >= 0)
+		closeUdpConn();
+	    if (udpWin) {
+		udprefresh(UDP_CURRENT);
+		udprefresh(UDP_STATUS);
+	    }
+	    warning("Timed out waiting for UDP response from server");
+	    UDPDIAG(("Timed out waiting for UDP response from server\n"));
+	}
+    }
+    /* if we're in a UDP "force" mode, check to see if we need to do something */
+    if (commMode == COMM_UDP && udpClientSend > 1)
+	checkForce();
+    
+    return (retval != 0);		/* convert to 1/0 */
+}
+
+
+/* this used to be part of the routine above */
+char    buf[BUFSIZ * 2 + 16];
+
+static int
+doRead(asock)
+    int     asock;
+{
+    char   *bufptr;
+    int     size;
+    int     count;
+    int     temp;
+#ifdef HANDLER_TIMES
+    struct timeval htpre, htpost;
+    extern void log_time(int, struct timeval *, struct timeval *);
+#endif
+
+#ifndef DNET
+    struct timeval timeout;
+    fd_set  readfds;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+#endif				/* DNET */
+
+    count = sock_read(asock, buf, 2 * BUFSIZ);
+#ifdef DNET
+    if (count == 0) {		/* yuck. */
+	return 0;
+    }
+#endif
+/* TMP */
+#ifdef nodef
+    if (asock == udpSock)
+	printf("read %d bytes\n", count);
+#endif				/* nodef */
+
+    if (count <= 0) {
+	if (asock == udpSock) {
+#ifndef DNET
+	    if (errno == ECONNREFUSED) {
+		struct sockaddr_in addr;
+
+		UDPDIAG(("asock=%d, sock=%d, udpSock=%d, errno=%d\n",
+			 asock, sock, udpSock, errno));
+		UDPDIAG(("count=%d\n", count));
+		UDPDIAG(("Hiccup(%d)!  Reconnecting\n", errno));
+		addr.sin_addr.s_addr = serveraddr;
+		addr.sin_port = htons(udpServerPort);
+		addr.sin_family = AF_INET;
+		if (connect(udpSock, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
+		    perror("connect");
+		    UDPDIAG(("Unable to reconnect\n"));
+		    /* and fall through to disconnect */
+		} else {
+		    UDPDIAG(("Reconnect successful\n"));
+		    return (0);
+		}
+	    }
+#endif				/* DNET */
+	    UDPDIAG(("*** UDP disconnected (res=%d, err=%d)\n",
+		     count, errno));
+	    warning("UDP link severed");
+	    printUdpInfo();
+	    closeUdpConn();
+	    commMode = commModeReq = COMM_TCP;
+	    commStatus = STAT_CONNECTED;
+	    if (udpWin) {
+		udprefresh(UDP_STATUS);
+		udprefresh(UDP_CURRENT);
+	    }
+	    return (0);
+	}
+#ifndef RWATCH
+	printf("1) Got read() of %d. Server dead\n", count);
+	perror("");
+#endif				/* RWATCH */
+	serverDead = 1;
+	return (0);
+    }
+    bufptr = buf;
+    while (bufptr < buf + count) {
+#ifdef SHORT_PACKETS
+computesize:
+	if ((*bufptr == SP_S_MESSAGE && (buf + count - bufptr <= 4))
+	    || (buf + count - bufptr < 4)) {	/* last part may only be
+						   needed for DNet...I'm not
+						   so sure any more.
+						   certainly doesn't hurt to
+						   have it.-JR */
+	    /*
+	       printf("buf+count-bufptr=%d, *bufptr=%d\n",buf + count -
+	       bufptr,*bufptr);
+	    */
+	    size = 0;		/* problem with reads breaking before size
+				   byte for SP_S_MESSAGE has been read. Only
+				   a problem for messages because reads break
+				   on 4 byte boundaries,  other size bytes
+				   are always in the first 4. -JR */
+	} else
+#endif
+	{
+	    size = size_of_spacket(bufptr);
+	    if (size < 1) {
+#if 1
+		fprintf(stderr, "Unknown packet %d.  Faking it.\n",
+			*bufptr);
+		size = 4;
+#else
+		fprintf(stderr, "Unknown packet %d.  Aborting.\n",
+			*bufptr);
+		return (0);
+#endif
+	    }
+#ifdef SHOW_RECEIVED
+	    printf("recieved packet type %d, size %d\n", *bufptr, size);
+#endif				/* SHOW_RECEIVED */
+#ifdef PACKET_LIGHTS
+	    light_receive();
+#endif				/* PACKET_LIGHTS */
+#ifdef SIZE_LOGGING
+	    receive_total += size;
+#endif				/* SIZE_LOGGING */
+	}
+	while (size > count + (buf - bufptr) || size == 0) {
+	    /*
+	       We wait for up to ten seconds for rest of packet. If we don't
+	       get it, we assume the server died.
+	    */
+	    /*
+	       printf("er, possible packet fragment, waiting for the
+	       rest...\n");
+	    */
+#ifdef RECORDER
+	    if (!playback)
+#endif
+	    {
+#ifdef DNET
+		temp = DNetServerPause(20, 0, asock);
+#else				/* DNET */
+		timeout.tv_sec = 20;
+		timeout.tv_usec = 0;
+		FD_ZERO(&readfds);
+		FD_SET(asock, &readfds);
+		/* readfds=1<<asock; */
+		temp = select(32, &readfds, 0, 0, &timeout);
+#endif
+		if (temp == 0) {
+		    printf("Packet fragment.  Server must be dead\n");
+		    serverDead = 1;
+		    return (0);
+		}
+	    }
+#ifdef SHORT_PACKETS
+	    if (size == 0)
+		/* 84=largest short packet message - the 4 we have */
+		temp = sock_read(asock, buf + count, 84);
+	    else
+#endif
+		temp = sock_read(asock, buf + count, size - (count + (buf - bufptr)));
+	    count += temp;
+#ifdef DNET
+	    if (temp < 0)
+#else
+	    if (temp <= 0)
+#endif				/* DNET */
+	    {
+#ifndef RWATCH
+		printf("2) Got read() of %d.  Server is dead\n", temp);
+#endif				/* RWATCH */
+		serverDead = 1;
+		return (0);
+	    }
+#ifdef SHORT_PACKETS
+	    if (size == 0)	/* for the SP_S_MESSAGE problem */
+		goto computesize;
+#endif
+	}
+#ifdef UPDATE_SIZES
+	totalbytes += size;
+	packetbytes[*bufptr] += size;
+#endif
+#ifdef RECORDER
+	if (playback && (*bufptr == REC_UPDATE)) {
+	    pb_update++;
+	    me->p_tractor = bufptr[1];
+	    if (me->p_flags & PFPLOCK)
+		me->p_playerl = bufptr[2];
+	    else
+		me->p_planet = bufptr[2];
+/*	    printf("Read REC_UPDATE pseudo-packet!\n");*/
+	} else
+#endif
+	    if (*bufptr >= 1 &&
+		*bufptr < NUM_HANDLERS &&
+		handlers[(int) *bufptr].handler != NULL) {
+	    if (asock != udpSock ||
+		(!drop_flag || *bufptr == SP_SEQUENCE || *bufptr == SP_SC_SEQUENCE)) {
+		if (asock == udpSock)
+		    packets_received++;	/* ping stuff */
+#ifdef RECORDER
+		if (recordGame)
+		    recordPacket(bufptr, size);
+#endif
+#ifdef HANDLER_TIMES
+		gettimeofday(&htpre,0);
+#endif
+		(*(handlers[(unsigned char)*bufptr].handler)) (bufptr);
+#ifdef HANDLER_TIMES
+		gettimeofday(&htpost,0);
+		log_time(*bufptr, &htpre, &htpost);
+#endif
+		/* printf("handled packet %d\n", (unsigned char)*bufptr); */
+	    } else
+		UDPDIAG(("Ignored type %d\n", *bufptr));
+	} else {
+	    printf("Handler for packet %d not installed...\n", *bufptr);
+	}
+
+	bufptr += size;
+	if (bufptr > buf + BUFSIZ) {
+	    bcopy(buf + BUFSIZ, buf, BUFSIZ);
+	    if (count == BUFSIZ * 2) {
+#ifdef RECORDER
+		if (playback)
+		    temp = 0;
+		else
+#endif
+		{
+#ifdef DNET
+		    temp = DNetServerPause(3, 0, asock);
+#else
+		    FD_ZERO(&readfds);
+		    FD_SET(asock, &readfds);
+		    /* readfds = 1<<asock; */
+		    temp = select(32, &readfds, 0, 0, &timeout);
+#endif				/* DNET */
+		}
+		if (temp != 0) {
+		    temp = sock_read(asock, buf + BUFSIZ, BUFSIZ);
+		    count = BUFSIZ + temp;
+#ifdef DNET
+		    if (temp < 0)
+#else
+		    if (temp <= 0)
+#endif				/* DNET */
+		    {
+#ifndef RWATCH
+			printf("3) Got read() of %d.  Server is dead\n", temp);
+#endif				/* RWATCH */
+			serverDead = 1;
+			return (0);
+		    }
+		} else {
+		    count = BUFSIZ;
+		}
+	    } else {
+		count -= BUFSIZ;
+	    }
+	    bufptr -= BUFSIZ;
+	}
+    }
+    return (1);
+}
+
+#define SANITY_TORPNUM(idx) \
+	if ( (unsigned)(idx) >= ntorps*nplayers) { \
+	    fprintf(stderr, "torp index %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_PNUM(idx) \
+	if ( (unsigned)(idx) >= nplayers) { \
+	    fprintf(stderr, "player number %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_PHASNUM(idx) \
+	if ( (unsigned)(idx) >= nplayers*nphasers) { \
+	    fprintf(stderr, "phaser number %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_PLASNUM(idx) \
+	if ( (unsigned)(idx) >= nplayers*nplasmas) { \
+	    fprintf(stderr, "plasma number %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_THINGYNUM(idx) \
+	if ( (unsigned)(idx) >= npthingies*nplayers + ngthingies) { \
+	    fprintf(stderr, "thingy index %x out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_PLANNUM(idx) \
+	if ( (unsigned)(idx) >= nplanets) { \
+	    fprintf(stderr, "planet index %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+#define SANITY_SHIPNUM(idx) \
+	if ( (unsigned)(idx) >= nshiptypes) { \
+	    fprintf(stderr, "ship type %d out of bounds\n", (idx)); \
+	    return; \
+	}
+
+
+static void
+handleTorp(packet)
+    struct torp_spacket *packet;
+{
+    struct torp *thetorp;
+
+    SANITY_TORPNUM(ntohs(packet->tnum));
+
+    thetorp = &torps[ntohs(packet->tnum)];
+    thetorp->t_x = ntohl(packet->x);
+    thetorp->t_y = ntohl(packet->y);
+    thetorp->t_dir = packet->dir;
+
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&thetorp->t_x, &thetorp->t_y);
+	rotate_dir(&thetorp->t_dir, rotate_deg);
+#endif
+#ifdef BORGTEST
+	if (bd)
+	    bd_test_torp(ntohs(packet->tnum), thetorp);
+#endif
+    }
+}
+
+
+static void
+handleTorpInfo(packet)
+    struct torp_info_spacket *packet;
+{
+    struct torp *thetorp;
+
+    SANITY_TORPNUM(ntohs(packet->tnum));
+
+    thetorp = &torps[ntohs(packet->tnum)];
+
+    if (packet->status == TEXPLODE && thetorp->t_status == TFREE) {
+	/* FAT: redundant explosion; don't update p_ntorp */
+	/*
+	   printf("texplode ignored\n");
+	*/
+	return;
+    }
+
+    if (thetorp->t_status == TFREE && packet->status) {
+	players[thetorp->t_owner].p_ntorp++;
+	thetorp->frame = 0;
+#ifdef BORGTEST
+	if (bd)
+	    bd_new_torp(ntohs(packet->tnum), thetorp);
+#endif
+
+    }
+    if (thetorp->t_status && packet->status == TFREE) {
+	players[thetorp->t_owner].p_ntorp--;
+    }
+    thetorp->t_war = packet->war;
+
+    if (packet->status != thetorp->t_status) {
+	/* FAT: prevent explosion reset */
+	thetorp->t_status = packet->status;
+	if (thetorp->t_status == TEXPLODE) {
+	    thetorp->t_fuse = NUMDETFRAMES;
+	}
+    }
+}
+
+static void
+handleStatus(packet)
+    struct status_spacket *packet;
+{
+    status->tourn = packet->tourn;
+    status->armsbomb = ntohl(packet->armsbomb);
+    status->planets = ntohl(packet->planets);
+    status->kills = ntohl(packet->kills);
+    status->losses = ntohl(packet->losses);
+    status->time = ntohl(packet->time);
+    status->timeprod = ntohl(packet->timeprod);
+}
+
+static void
+handleSelf(packet)
+    struct you_spacket *packet;
+{
+    SANITY_PNUM(packet->pnum);
+    me = (ghoststart ? &players[ghost_pno] : &players[packet->pnum]);
+    myship = (me->p_ship);
+    mystats = &(me->p_stats);
+    me->p_hostile = packet->hostile;
+    me->p_swar = packet->swar;
+    me->p_armies = packet->armies;
+    me->p_flags = ntohl(packet->flags);
+    me->p_damage = ntohl(packet->damage);
+    me->p_shield = ntohl(packet->shield);
+    me->p_fuel = ntohl(packet->fuel);
+    me->p_etemp = ntohs(packet->etemp);
+    me->p_wtemp = ntohs(packet->wtemp);
+    me->p_whydead = ntohs(packet->whydead);
+    me->p_whodead = ntohs(packet->whodead);
+    status2->clock = (unsigned long) packet->pad2;
+    status2->clock += ((unsigned long) packet->pad3) << 8;
+#ifdef INCLUDE_VISTRACT
+    if (packet->tractor & 0x40)
+	me->p_tractor = (short) packet->tractor & (~0x40);	/* ATM - visible trac
+								   tors */
+#ifdef nodef			/* tmp */
+    else
+	me->p_tractor = -1;
+#endif				/* nodef */
+#endif
+#ifdef SOUND
+    S_HandlePFlags();
+#endif
+
+}
+
+static void
+handlePlayer(packet)
+    struct player_spacket *packet;
+{
+    register struct player *pl;
+    unsigned char newdir;
+
+    SANITY_PNUM(packet->pnum);
+
+
+    pl = &players[packet->pnum];
+    newdir = packet->dir;
+#ifdef ROTATERACE
+    if (rotate)
+	rotate_dir(&newdir, rotate_deg);
+#endif
+#ifdef CHECK_DROPPED
+    /* Kludge to fix lost uncloak packets! [3/94] -JR */
+    if (pl->p_flags & PFCLOAK && pl->p_cloakphase >= (CLOAK_PHASES - 1)) {
+	if (pl->p_dir != newdir) {	/* always sends the same direction
+					   when cloaked! */
+	    int     i, plocked = 0;
+
+	    /*
+	       nplayers is for paradise, probably want MAX_PLAYERS for other
+	       clients
+	    */
+	    for (i = 0; i < nplayers; i++) {	/* except when someone has
+						   this person phasered :( */
+		if ((phasers[i].ph_status & PHHIT) && (phasers[i].ph_target == packet->pnum)) {
+		    plocked = 1;
+		    break;
+		}
+	    }
+	    if (!plocked) {
+		pl->p_flags &= ~(PFCLOAK);
+		if (reportDroppedPackets)
+		    printf("Uncloak kludge, player %d\n", pl->p_no);
+	    }
+	}
+    }
+#endif
+    pl->p_dir = newdir;
+    pl->p_speed = packet->speed;
+    pl->p_x = ntohl(packet->x);
+    pl->p_y = ntohl(packet->y);
+    if (pl == me) {
+	extern int my_x, my_y;	/* from shortcomm.c */
+	my_x = me->p_x;
+	my_y = me->p_y;
+    }
+    redrawPlayer[packet->pnum] = 1;
+
+    if (me == pl) {
+	extern int my_x, my_y;	/* short packets need unrotated co-ords! */
+	my_x = pl->p_x;
+	my_y = pl->p_y;
+    }
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&pl->p_x, &pl->p_y);
+    }
+#endif
+
+}
+
+
+static void
+handleWarning(packet)
+    struct warning_spacket *packet;
+{
+    warning((char *) packet->mesg);
+}
+
+static void
+handleThingy(packet)
+    struct thingy_spacket *packet;
+{
+    struct thingy *thetorp;
+
+    SANITY_THINGYNUM(ntohs(packet->tnum));
+
+    thetorp = &thingies[ntohs(packet->tnum)];
+    thetorp->t_x = ntohl(packet->x);
+    thetorp->t_y = ntohl(packet->y);
+    /* printf("drone at %d, %d\n", thetorp->t_x, thetorp->t_y); */
+    thetorp->t_dir = packet->dir;
+
+
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&thetorp->t_x, &thetorp->t_y);
+	rotate_dir(&thetorp->t_dir, rotate_deg);
+    }
+#endif
+
+    if (thetorp->t_shape == SHP_WARP_BEACON)
+	redrawall = 1;		/* shoot, route has changed */
+
+}
+
+static void
+handleThingyInfo(packet)
+    struct thingy_info_spacket *packet;
+{
+    struct thingy *thetorp;
+
+    SANITY_THINGYNUM(ntohs(packet->tnum));
+
+    thetorp = &thingies[ntohs(packet->tnum)];
+
+#if 1
+    thetorp->t_owner = ntohs(packet->owner);
+#else
+    /* we have the gameparam packet now */
+#endif
+
+    if (thetorp->t_shape == SHP_WARP_BEACON)
+	redrawall = 1;		/* redraw the lines, I guess */
+
+    if (ntohs(packet->shape) == SHP_BOOM && thetorp->t_shape == SHP_BLANK) {
+	/* FAT: redundant explosion; don't update p_ntorp */
+	/*
+	   printf("texplode ignored\n");
+	*/
+	return;
+    }
+
+    if (thetorp->t_shape == SHP_BLANK && ntohs(packet->shape) != SHP_BLANK) {
+	players[thetorp->t_owner].p_ndrone++;	/* TSH */
+    }
+    if (thetorp->t_shape != SHP_BLANK && ntohs(packet->shape) == SHP_BLANK) {
+	players[thetorp->t_owner].p_ndrone--;	/* TSH */
+    }
+    thetorp->t_war = packet->war;
+
+    if (ntohs(packet->shape) != thetorp->t_shape) {
+	/* FAT: prevent explosion reset */
+	thetorp->t_shape = ntohs(packet->shape);
+	if (thetorp->t_shape == SHP_BOOM ||
+	    thetorp->t_shape == SHP_PBOOM) {
+	    thetorp->t_fuse = NUMDETFRAMES;
+	}
+    }
+}
+
+void
+sendShortPacket(type, state)
+    char    type, state;
+{
+    struct speed_cpacket speedReq;
+
+    speedReq.type = type;
+    speedReq.speed = state;
+#ifdef UNIX_SOUND
+    if (type == CP_SHIELD) play_sound (SND_SHIELD); /* Shields */
+#endif
+    sendServerPacket((struct player_spacket *) & speedReq);
+    /* printf("Sending packet #%d\n",type); */
+
+    /* if we're sending in UDP mode, be prepared to force it */
+    if (commMode == COMM_UDP && udpClientSend >= 2) {
+	switch (type) {
+	case CP_SPEED:
+	    fSpeed = state | 0x100;
+	    break;
+	case CP_DIRECTION:
+	    fDirection = state | 0x100;
+	    break;
+	case CP_SHIELD:
+	    fShield = state | 0xa00;
+	    break;
+	case CP_ORBIT:
+	    fOrbit = state | 0xa00;
+	    break;
+	case CP_REPAIR:
+	    fRepair = state | 0xa00;
+	    break;
+	case CP_CLOAK:
+	    fCloak = state | 0xa00;
+	    break;
+	case CP_BOMB:
+	    fBomb = state | 0xa00;
+	    break;
+	case CP_DOCKPERM:
+	    fDockperm = state | 0xa00;
+	    break;
+	case CP_PLAYLOCK:
+	    fPlayLock = state | 0xa00;
+	    break;
+	case CP_PLANLOCK:
+	    fPlanLock = state | 0xa00;
+	    break;
+	case CP_BEAM:
+	    if (state == 1)
+		fBeamup = 1 | 0x500;
+	    else
+		fBeamdown = 2 | 0x500;
+	    break;
+	}
+
+	/* force weapons too? */
+	if (udpClientSend >= 3) {
+	    switch (type) {
+	    case CP_PHASER:
+		fPhaser = state | 0x100;
+		break;
+	    case CP_PLASMA:
+		fPlasma = state | 0x100;
+		break;
+	    }
+	}
+    }
+}
+
+void
+sendServerPacket(packet)
+/* Pick a random type for the packet */
+    struct player_spacket *packet;
+{
+    int     size;
+
+#ifdef RWATCH
+    return;
+#endif				/* RWATCH */
+
+    if (serverDead)
+	return;
+    size = size_of_cpacket(packet);
+    if (size < 1) {
+	printf("Attempt to send strange packet %d!\n", packet->type);
+	return;
+    }
+#ifdef SHOW_SEND
+    printf("sending packet type %d, size %d\n", packet->type,
+	   size);
+#endif				/* SHOW_SEND */
+#ifdef PACKET_LIGHTS
+    light_send();
+#endif				/* PACKET_LIGHTS */
+#ifdef SIZE_LOGGING
+    send_total += size;
+#endif				/* SIZE_LOGGING */
+    if (commMode == COMM_UDP) {
+	/* for now, just sent everything via TCP */
+    }
+    if (commMode == COMM_TCP || !udpClientSend) {
+	/* special case for verify packet */
+	if (packet->type == CP_UDP_REQ) {
+	    if (((struct udp_req_cpacket *) packet)->request == COMM_VERIFY)
+		goto send_udp;
+	}
+	/*
+	   business as usual (or player has turned off UDP transmission)
+	*/
+	if (gwrite(sock, (char *) packet, size) != size) {
+	    printf("gwrite failed.  Server must be dead\n");
+	    serverDead = 1;
+	}
+    } else {
+	/*
+	   UDP stuff
+	*/
+	switch (packet->type) {
+	case CP_SPEED:
+	case CP_DIRECTION:
+	case CP_PHASER:
+	case CP_PLASMA:
+	case CP_TORP:
+	case CP_QUIT:
+	case CP_PRACTR:
+	case CP_REPAIR:
+	case CP_ORBIT:
+	case CP_BOMB:
+	case CP_BEAM:
+	case CP_DET_TORPS:
+	case CP_DET_MYTORP:
+	case CP_TRACTOR:
+	case CP_REPRESS:
+	case CP_COUP:
+	case CP_DOCKPERM:
+	case CP_SCAN:
+	case CP_PING_RESPONSE:
+	case CP_CLOAK:
+	case CP_SHIELD:
+	case CP_PLANLOCK:
+	    /*
+	       these are non-critical but don't expire, send with TCP
+	       [BDyess]
+	    */
+	    /* case CP_REFIT: */
+	    /* case CP_PLAYLOCK: */
+	    /* non-critical stuff, use UDP */
+    send_udp:
+	    packets_sent++;	/* ping stuff */
+
+	    V_UDPDIAG(("Sent %d on UDP port\n", packet->type));
+	    if (gwrite(udpSock, (char *) packet, size) != size) {
+		UDPDIAG(("gwrite on UDP failed.  Closing UDP connection\n"));
+		warning("UDP link severed");
+		/* serverDead=1; */
+		commModeReq = commMode = COMM_TCP;
+		commStatus = STAT_CONNECTED;
+		commSwitchTimeout = 0;
+		if (udpWin) {
+		    udprefresh(UDP_STATUS);
+		    udprefresh(UDP_CURRENT);
+		}
+		if (udpSock >= 0)
+		    closeUdpConn();
+	    }
+	    break;
+
+	default:
+	    /* critical stuff, use TCP */
+	    if (gwrite(sock, (char *) packet, size) != size) {
+		printf("gwrite failed.  Server must be dead\n");
+		serverDead = 1;
+	    }
+	}
+    }
+}
+
+static void
+handlePlanet(packet)
+    struct planet_spacket *packet;
+{
+    struct planet *plan;
+    /* FAT: prevent excessive redraw */
+    int     redraw = 0;
+#ifdef HOCKEY
+    int     hockey_update = 0;
+#endif /*HOCKEY*/
+
+    SANITY_PLANNUM(packet->pnum);
+
+    plan = &planets[packet->pnum];
+    if (plan->pl_owner != packet->owner) {
+	redraw = 1;
+#ifdef HOCKEY
+	hockey_update = 1;
+#endif
+    }
+    plan->pl_owner = packet->owner;
+
+    if (plan->pl_owner < (1 << 0) || plan->pl_owner > (1 << (number_of_teams - 1)))
+	plan->pl_owner = NOBODY;
+
+    if (plan->pl_info != packet->info)
+	redraw = 1;
+    plan->pl_info = packet->info;
+    /* Redraw the planet because it was updated by server */
+
+    if (plan->pl_flags != (int) ntohs(packet->flags))
+	redraw = 1;
+    plan->pl_flags = (unsigned short) ntohs(packet->flags);
+
+    if (plan->pl_armies != ntohl(packet->armies))
+	redraw = 1;
+
+    plan->pl_armies = ntohl(packet->armies);
+    if (plan->pl_info == 0) {
+	plan->pl_owner = NOBODY;
+    }
+    if (redraw) {
+	plan->pl_flags |= PLREDRAW;
+	pl_update[packet->pnum].plu_update = 1;	/* used to mean the planet
+						   had moved, now set as a
+						   sign we need to erase AND
+						   redraw. -JR */
+	pl_update[packet->pnum].plu_x = planets[packet->pnum].pl_x;
+	pl_update[packet->pnum].plu_y = planets[packet->pnum].pl_y;
+	if (infomapped && infotype == PLANETTYPE &&
+	    ((struct planet *) infothing)->pl_no == packet->pnum)
+	    infoupdate = 1;
+#ifdef HOCKEY
+        if(hockey_update && hockey) hockeyInit();
+#endif /*HOCKEY*/
+    }
+}
+
+static void
+handlePhaser(packet)
+    struct phaser_spacket *packet;
+{
+    struct phaser *phas;
+
+    SANITY_PHASNUM(packet->pnum);
+
+    phas = &phasers[packet->pnum];
+#ifdef CHECK_DROPPED
+    /* can't fire weapons cloaked, this guy must be uncloaked.. */
+    /* applying this to torps is trickier... -JR */
+    if (packet->status != PHFREE) {
+	if (reportDroppedPackets && (players[packet->pnum].p_flags & PFCLOAK))
+	    printf("Dropped uncloak, player %d. (fired phaser)\n", packet->pnum);
+	players[packet->pnum].p_flags &= ~(PFCLOAK);
+    } else {
+	if (longest_ph_fuse < phas->ph_fuse)
+	    longest_ph_fuse = phas->ph_fuse;
+    }
+#endif
+    phas->ph_status = packet->status;
+    phas->ph_dir = packet->dir;
+    phas->ph_x = ntohl(packet->x);
+    phas->ph_y = ntohl(packet->y);
+    phas->ph_target = ntohl(packet->target);
+    phas->ph_fuse = 0;
+
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&phas->ph_x, &phas->ph_y);
+	rotate_dir(&phas->ph_dir, rotate_deg);
+    }
+#endif
+#ifdef SOUND
+    if ((me->p_no == packet->pnum) && (packet->status != PHFREE)) {
+	S_PlaySound(S_PHASER);
+    }
+#endif
+#ifdef UNIX_SOUND
+    if ((me->p_no == packet->pnum) && (packet->status != PHFREE)) {
+        play_sound(SND_PHASER); /* Phasers */
+    }
+#endif
+}
+
+void
+handleMessage(packet)
+    struct mesg_spacket *packet;
+{
+    if ((int) packet->m_from >= nplayers)
+	packet->m_from = 255;
+    dmessage(packet->mesg, packet->m_flags, packet->m_from, packet->m_recpt);
+}
+
+
+static void
+handleQueue(packet)
+    struct queue_spacket *packet;
+{
+    queuePos = ntohs(packet->pos);
+    /* printf("Receiving queue position %d\n",queuePos); */
+}
+
+static void
+handleEmpty(ptr)
+    char   *ptr;
+{
+    printf("Unknown packet type: %d\n", *ptr);
+    return;
+}
+
+void
+sendTeamReq(team, ship)
+    int     team, ship;
+{
+    struct outfit_cpacket outfitReq;
+
+    outfitReq.type = CP_OUTFIT;
+    outfitReq.team = team;
+    outfitReq.ship = ship;
+    sendServerPacket((struct player_spacket *) & outfitReq);
+}
+
+static void
+handlePickok(packet)
+    struct pickok_spacket *packet;
+{
+    pickOk = packet->state;
+#ifdef RECORDER
+    if (playback) {		/* added when the packet is recorded. */
+	extern int lastTeamReq;
+	lastTeamReq = packet->pad2;
+    }
+#endif
+}
+
+void
+sendLoginReq(name, pass, login, query)
+    char   *name, *pass;
+    char   *login;
+    char    query;
+{
+    struct login_cpacket packet;
+
+    strcpy(packet.name, name);
+    strcpy(packet.password, pass);
+    if (strlen(login) > 15)
+	login[15] = 0;
+    strcpy(packet.login, login);
+    packet.type = CP_LOGIN;
+    packet.query = query;
+    packet.pad2 = 0x69;		/* added 1/19/93 KAO */
+    packet.pad3 = 0x43;		/* added 1/19/93 KAO *//* was 0x42 3/2/93 */
+    sendServerPacket((struct player_spacket *) & packet);
+}
+
+static void
+handleLogin(packet)
+    struct login_spacket *packet;
+{
+
+
+    loginAccept = packet->accept;
+    if ((packet->pad2 == 69) && (packet->pad3 == 42))
+	paradise = 1;
+    else {
+	/*nshiptypes = 8;*/
+	nplayers=20;
+	nplanets=40;
+    }
+    if (packet->accept) {
+
+	/* we no longer accept keymaps from the server */
+
+	mystats->st_flags = ntohl(packet->flags);
+	keeppeace = (me->p_stats.st_flags / ST_KEEPPEACE) & 1;
+    }
+}
+
+void
+sendTractorReq(state, pnum)
+    char    state;
+    char    pnum;
+{
+    struct tractor_cpacket tractorReq;
+
+    tractorReq.type = CP_TRACTOR;
+    tractorReq.state = state;
+    tractorReq.pnum = pnum;
+    sendServerPacket((struct player_spacket *) & tractorReq);
+
+    if (state)
+	fTractor = pnum | 0x40;
+    else
+	fTractor = 0;
+}
+
+void
+sendRepressReq(state, pnum)
+    char    state;
+    char    pnum;
+{
+    struct repress_cpacket repressReq;
+
+    repressReq.type = CP_REPRESS;
+    repressReq.state = state;
+    repressReq.pnum = pnum;
+    sendServerPacket((struct player_spacket *) & repressReq);
+
+    if (state)
+	fRepress = pnum | 0x40;
+    else
+	fRepress = 0;
+}
+
+void
+sendDetMineReq(torp)
+    short   torp;
+{
+    struct det_mytorp_cpacket detReq;
+
+    detReq.type = CP_DET_MYTORP;
+    detReq.tnum = htons(torp);
+    sendServerPacket((struct player_spacket *) & detReq);
+}
+
+static void
+handlePlasmaInfo(packet)
+    struct plasma_info_spacket *packet;
+{
+    struct plasmatorp *thetorp;
+
+    SANITY_PLASNUM(ntohs(packet->pnum));
+
+    thetorp = &plasmatorps[ntohs(packet->pnum)];
+    if (packet->status == PTEXPLODE && thetorp->pt_status == PTFREE) {
+	/* FAT: redundant explosion; don't update p_nplasmatorp */
+	return;
+    }
+    if (!thetorp->pt_status && packet->status) {
+	players[thetorp->pt_owner].p_nplasmatorp++;
+#ifdef UNIX_SOUND
+    play_sound (SND_PLASMA); /* Plasma */
+#endif
+    }
+    if (thetorp->pt_status && !packet->status) {
+	players[thetorp->pt_owner].p_nplasmatorp--;
+    }
+    thetorp->pt_war = packet->war;
+    if (thetorp->pt_status != packet->status) {
+	/* FAT: prevent explosion timer from being reset */
+	thetorp->pt_status = packet->status;
+	if (thetorp->pt_status == PTEXPLODE) {
+	    thetorp->pt_fuse = NUMDETFRAMES;
+	}
+    }
+}
+
+static void
+handlePlasma(packet)
+    struct plasma_spacket *packet;
+{
+    struct plasmatorp *thetorp;
+
+    SANITY_PLASNUM(ntohs(packet->pnum));
+
+    thetorp = &plasmatorps[ntohs(packet->pnum)];
+    thetorp->pt_x = ntohl(packet->x);
+    thetorp->pt_y = ntohl(packet->y);
+
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&thetorp->pt_x, &thetorp->pt_y);
+    }
+#endif
+}
+
+static void
+handleFlags(packet)
+    struct flags_spacket *packet;
+{
+    SANITY_PNUM(packet->pnum);
+
+    if (players[packet->pnum].p_flags != ntohl(packet->flags) ||
+    players[packet->pnum].p_tractor != ((short) packet->tractor & (~0x40))) {
+	/* FAT: prevent redundant player update */
+	redrawPlayer[packet->pnum] = 1;
+    } else
+	return;
+
+#ifdef CHECK_DROPPED
+/* TEST */
+/* For the dropped uncloak kludge, completely ignore uncloaks :-) */
+/*    if(players[packet->pnum].p_flags & PFCLOAK) packet->flags |= htonl(PFCLOAK);*/
+/* TEST */
+    /* when a player cloaks, clear his phaser */
+    if (ntohl(packet->flags) & PFCLOAK) {
+	if (phasers[packet->pnum].ph_status != PFREE) {
+	    if (reportDroppedPackets)
+		printf("Lost phaser free packet, player %d. (cloaked)\n", packet->pnum);
+	    phasers[packet->pnum].ph_status = PHFREE;
+	    phasers[packet->pnum].ph_fuse = 0;
+	}
+    }
+#endif
+
+    players[packet->pnum].p_flags = ntohl(packet->flags);
+#ifdef INCLUDE_VISTRACT
+    if (packet->tractor & 0x40)
+	players[packet->pnum].p_tractor = (short) packet->tractor & (~0x40);	/* ATM - visible
+										   tractors */
+    else
+#endif				/* INCLUDE_VISTRACT */
+	players[packet->pnum].p_tractor = -1;
+}
+
+static void
+handleKills(packet)
+    struct kills_spacket *packet;
+{
+
+    SANITY_PNUM(packet->pnum);
+
+    if (players[packet->pnum].p_kills != ntohl(packet->kills) / 100.0) {
+	players[packet->pnum].p_kills = ntohl(packet->kills) / 100.0;
+	/* FAT: prevent redundant player update */
+	updatePlayer[packet->pnum] |= ALL_UPDATE;
+	if (infomapped && infotype == PLAYERTYPE &&
+	    ((struct player *) infothing)->p_no == packet->pnum)
+	    infoupdate = 1;
+#ifdef PLPROF
+	printf("Got handleKills for %d\n", packet->pnum);
+#endif				/* PLPROF */
+#ifdef ARMY_SLIDER
+	if (me == &players[packet->pnum]) {
+	    calibrate_stats();
+	    redrawStats();
+	}
+#endif				/* ARMY_SLIDER */
+    }
+}
+
+static void
+handlePStatus(packet)
+    struct pstatus_spacket *packet;
+{
+    SANITY_PNUM(packet->pnum);
+
+    if (packet->status == PEXPLODE) {
+	players[packet->pnum].p_explode = 0;
+    }
+    /*
+       Ignore DEAD status. Instead, we treat it as PEXPLODE. This gives us
+       time to animate all the frames necessary for the explosions at our own
+       pace.
+    */
+    if (packet->status == PDEAD) {
+	packet->status = PEXPLODE;
+    }
+    if (players[packet->pnum].p_status != packet->status) {
+	players[packet->pnum].p_status = packet->status;
+	redrawPlayer[packet->pnum] = 1;
+#ifdef PLPROF
+	printf("Got handlePStatus for %d\n", packet->pnum);
+#endif				/* PLPROF */
+	updatePlayer[packet->pnum] |= ALL_UPDATE;
+	if (infomapped && infotype == PLAYERTYPE &&
+	    ((struct player *) infothing)->p_no == packet->pnum)
+	    infoupdate = 1;
+#ifdef CHECK_DROPPED
+	if (players[packet->pnum].p_status == POUTFIT) {
+	    int     i;
+	    /* clear phasers on this guy */
+#if 0
+	    for (i = 0; i < nplayers; i++) {
+		if (phasers[i].ph_target == packet->pnum && phasers[i].ph_status == PHHIT) {
+		    if (reportDroppedPackets)
+			printf("Lost phaser free packet, player %d->player %d (target not alive)\n",
+			       i, packet->pnum);
+		    phasers[i].ph_status = PHFREE;
+		}
+	    }
+#endif
+	    if (phasers[packet->pnum].ph_status != PHFREE) {
+		if (reportDroppedPackets)
+		    printf("Lost phaser free packet, player %d (outfitting)\n", packet->pnum);
+		phasers[packet->pnum].ph_status = PHFREE;	/* and his own */
+	    }
+	    if (reportDroppedPackets && players[packet->pnum].p_ntorp > 1)
+		/* only report it on 2 or more left, always clear it. */
+		printf("Lost torp free packet, (%d torps) player %d (outfitting)\n",
+		       players[packet->pnum].p_ntorp, packet->pnum);
+	    players[packet->pnum].p_ntorp = 0;
+	    for (i = packet->pnum * ntorps; i < (packet->pnum + 1) * ntorps; i++) {
+		torps[i].t_status = TFREE;
+	    }
+	}
+#endif
+    }
+}
+
+static void
+handleMotd(packet)
+    struct motd_spacket *packet;
+{
+    newMotdLine((char *) packet->line);
+}
+
+void
+sendMessage(mes, group, indiv)
+    char   *mes;
+    int     group, indiv;
+{
+    struct mesg_cpacket mesPacket;
+
+#ifdef SHORT_PACKETS
+    if (recv_short) {
+	int     size;
+	size = strlen(mes);
+	size += 5;		/* 1 for '\0', 4 packetheader */
+	if ((size % 4) != 0)
+	    size += (4 - (size % 4));
+	mesPacket.pad1 = (char) size;
+
+	/*
+	   OH SHIT!!!! sizes[CP_S_MESSAGE] = size;
+	*/
+
+	mesPacket.type = CP_S_MESSAGE;
+    } else
+#endif
+	mesPacket.type = CP_MESSAGE;
+    mesPacket.group = group;
+    mesPacket.indiv = indiv;
+    strcpy(mesPacket.mesg, mes);
+    sendServerPacket((struct player_spacket *) & mesPacket);
+}
+
+static void
+handleMask(packet)
+    struct mask_spacket *packet;
+{
+    tournMask = packet->mask;
+}
+
+void
+sendOptionsPacket()
+{
+    struct options_cpacket optPacket;
+    register int i;
+    long    flags;
+
+    optPacket.type = CP_OPTIONS;
+    flags = (
+	     ST_NOBITMAPS * (!sendmotdbitmaps) +
+	     ST_KEEPPEACE * keeppeace +
+	     0
+	);
+    optPacket.flags = htonl(flags);
+    /* copy the keymap and make sure no ctrl chars are sent [BDyess] */
+    for (i = 32; i < 128; i++) {
+	optPacket.keymap[i - 32] =
+	    (myship->s_keymap[i] & 128) ? i : myship->s_keymap[i];
+    }
+    /* bcopy(mystats->st_keymap+32, optPacket.keymap,96); */
+    sendServerPacket((struct player_spacket *) & optPacket);
+}
+
+static void
+pickSocket(old)
+    int     old;
+{
+    int     newsocket;
+    struct socket_cpacket sockPack;
+#ifdef RWATCH
+    nextSocket = old;
+#else
+    newsocket = (getpid() & 32767);
+    if (ghoststart)
+	nextSocket = old;
+    while (newsocket < 2048 || newsocket == old) {
+	newsocket = (newsocket + 10687) & 32767;
+    }
+    sockPack.type = CP_SOCKET;
+    sockPack.socket = htonl(newsocket);
+    sockPack.version = (char) SOCKVERSION;
+    sockPack.udp_version = (char) UDPVERSION;
+    sendServerPacket((struct player_spacket *) & sockPack);
+    /* Did we get new socket # sent? */
+    if (serverDead)
+	return;
+    nextSocket = newsocket;
+#endif				/* RWATCH */
+}
+
+static void
+handleBadVersion(packet)
+    struct badversion_spacket *packet;
+{
+    switch (packet->why) {
+    case 0:
+	printf("Sorry, this is an invalid client version.\n");
+	printf("You need a new version of the client code.\n");
+	break;
+    default:
+	printf("Sorry, but you cannot play xtrek now.\n");
+	printf("Try again later.\n");
+	break;
+    }
+    EXIT(1);
+}
+
+int
+gwrite(fd, buf, bytes)
+    int     fd;
+    char   *buf;
+    register int bytes;
+{
+    long    orig = bytes;
+    register long n;
+#ifdef RECORDER
+    if (playback)		/* pretend all is well */
+	return (bytes);
+#endif
+    while (bytes) {
+	n = sock_write(fd, buf, bytes);
+	if (n < 0) {
+	    if (fd == udpSock) {
+		fprintf(stderr, "Tried to write %d, 0x%x, %d\n",
+			fd, (unsigned int) buf, bytes);
+		perror("write");
+		printUdpInfo();
+	    }
+	    return (-1);
+	}
+	bytes -= n;
+	buf += n;
+    }
+    return (orig);
+}
+
+int
+sock_read(sock, data, size)
+    int     sock, size;
+    char   *data;
+{
+#ifdef RECORDER
+    if (playback)
+	return readRecorded(sock, data, size);
+#endif
+
+#ifndef AMIGA
+    return read(sock, data, size);
+#else
+#ifdef DNET
+    return DNet_Read(sock, data, size);
+#else
+    /* NET_SOCKETS code here */
+    /* No idea if this works, old version had it: */
+    return recv(sock, data, size, 0);
+#endif				/* DNET  */
+#endif				/* AMIGA */
+}
+
+static void
+handleHostile(packet)
+    struct hostile_spacket *packet;
+{
+    register struct player *pl;
+
+    SANITY_PNUM(packet->pnum);
+
+    pl = &players[packet->pnum];
+    if (pl->p_swar != packet->war ||
+	pl->p_hostile != packet->hostile) {
+	/* FAT: prevent redundant player update & redraw */
+	pl->p_swar = packet->war;
+	pl->p_hostile = packet->hostile;
+	/* updatePlayer[packet->pnum]=1; why? */
+	redrawPlayer[packet->pnum] = 1;
+    }
+}
+
+static void
+handlePlyrLogin(packet)
+    struct plyr_login_spacket *packet;
+{
+    register struct player *pl;
+
+    SANITY_PNUM(packet->pnum);
+
+#ifdef PLPROF
+    printf("Got handlPlyrLogin for %d\n", packet->pnum);
+#endif				/* PLPROF */
+    updatePlayer[packet->pnum] |= ALL_UPDATE;
+    pl = &players[packet->pnum];
+
+    strcpy(pl->p_name, packet->name);
+    strcpy(pl->p_monitor, packet->monitor);
+    strcpy(pl->p_login, packet->login);
+    pl->p_stats.st_rank = packet->rank;
+    if (packet->pnum == me->p_no) {
+	/* This is me.  Set some stats */
+	if (lastRank == -1) {
+	    if (loggedIn) {
+		lastRank = packet->rank;
+	    }
+	} else {
+	    if (lastRank != packet->rank) {
+		lastRank = packet->rank;
+		promoted = 1;
+	    }
+	}
+    }
+}
+
+static void
+handleStats(packet)
+    struct stats_spacket *packet;
+{
+    register struct player *pl;
+
+    SANITY_PNUM(packet->pnum);
+
+#ifdef PLPROF
+    printf("Got handleStats for %d\n", packet->pnum);
+#endif				/* PLPROF */
+    updatePlayer[packet->pnum] |= LARGE_UPDATE;
+    if (infomapped && infotype == PLAYERTYPE &&
+	((struct player *) infothing)->p_no == packet->pnum)
+	infoupdate = 1;
+    pl = &players[packet->pnum];
+    pl->p_stats.st_tkills = ntohl(packet->tkills);
+    pl->p_stats.st_tlosses = ntohl(packet->tlosses);
+    pl->p_stats.st_kills = ntohl(packet->kills);
+    pl->p_stats.st_losses = ntohl(packet->losses);
+    pl->p_stats.st_tticks = ntohl(packet->tticks);
+    pl->p_stats.st_tplanets = ntohl(packet->tplanets);
+    pl->p_stats.st_tarmsbomb = ntohl(packet->tarmies);
+    pl->p_stats.st_sbkills = ntohl(packet->sbkills);
+    pl->p_stats.st_sblosses = ntohl(packet->sblosses);
+    pl->p_stats.st_armsbomb = ntohl(packet->armies);
+    pl->p_stats.st_planets = ntohl(packet->planets);
+    pl->p_stats.st_maxkills = ntohl(packet->maxkills) / 100.0;
+    pl->p_stats.st_sbmaxkills = ntohl(packet->sbmaxkills) / 100.0;
+}
+
+static void
+handlePlyrInfo(packet)
+    struct plyr_info_spacket *packet;
+{
+    register struct player *pl;
+    static int lastship = -1;
+
+    SANITY_PNUM(packet->pnum);
+
+#ifdef PLPROF
+    printf("Got PlyrInfo for %d\n", packet->pnum);
+#endif				/* PLPROF */
+    updatePlayer[packet->pnum] |= ALL_UPDATE;
+    if (infomapped && infotype == PLAYERTYPE &&
+	((struct player *) infothing)->p_no == packet->pnum)
+	infoupdate = 1;
+    pl = &players[packet->pnum];
+    pl->p_ship = getship(packet->shiptype);
+    if (packet->pnum == me->p_no && currentship != packet->shiptype) {
+	currentship = packet->shiptype;
+	/* sendOptionsPacket(); */
+    }
+    pl->p_teami = mask_to_idx(packet->team);
+    pl->p_mapchars[0] = teaminfo[pl->p_teami].letter;
+    /* printf("team: %d, letter: %c\n",pl->p_teami,pl->p_mapchars[0]); */
+    pl->p_mapchars[1] = shipnos[pl->p_no];
+    if (me == pl && lastship != currentship) {
+	lastship = currentship;
+	redrawTstats();
+	calibrate_stats();
+	redrawStats();		/* tsh */
+    }
+    redrawPlayer[packet->pnum] = 1;
+}
+
+void
+sendUpdatePacket(speed)
+    long    speed;
+{
+    struct updates_cpacket packet;
+
+    packet.type = CP_UPDATES;
+    timerDelay = speed;
+    packet.usecs = htonl(speed);
+    sendServerPacket((struct player_spacket *) & packet);
+#ifdef DEBUG
+    printf("sent request for an update every %d microseconds (%d/sec)\n",speed,1000000/speed);
+#endif
+}
+
+static void
+handlePlanetLoc(packet)
+    struct planet_loc_spacket *packet;
+{
+    struct planet *pl;
+
+    SANITY_PLANNUM(packet->pnum);
+
+    pl = &planets[packet->pnum];
+    pl_update[packet->pnum].plu_x = pl->pl_x;
+    pl_update[packet->pnum].plu_y = pl->pl_y;
+
+    if (pl_update[packet->pnum].plu_update != -1) {
+	pl_update[packet->pnum].plu_update = 1;
+	/*
+	   printf("update: %s, old (%d,%d) new (%d,%d)\n", pl->pl_name,
+	   pl->pl_x, pl->pl_y, ntohl(packet->x),ntohl(packet->y));
+	*/
+    } else {
+	pl_update[packet->pnum].plu_update = 0;
+	pl_update[packet->pnum].plu_x = ntohl(packet->x);
+	pl_update[packet->pnum].plu_y = ntohl(packet->y);
+    }
+    pl->pl_x = ntohl(packet->x);
+    pl->pl_y = ntohl(packet->y);
+    strcpy(pl->pl_name, packet->name);
+    pl->pl_namelen = strlen(packet->name);
+    pl->pl_flags |= PLREDRAW;
+    if (infomapped && infotype == PLANETTYPE &&
+	((struct planet *) infothing)->pl_no == packet->pnum)
+	infoupdate = 1;
+    reinitPlanets = 1;
+    if (pl->pl_x > blk_gwidth) {
+	blk_gwidth = 200000;
+	blk_windgwidth = ((float) WINSIDE) / blk_gwidth;
+    }
+#ifdef ROTATERACE
+    if (rotate) {
+	rotate_gcenter(&pl->pl_x, &pl->pl_y);
+    }
+#endif
+}
+
+#if 0
+
+static void
+handleReserved(packet)
+    struct reserved_spacket *packet;
+{
+    struct reserved_cpacket response;
+
+#ifndef RWATCH
+    encryptReservedPacket(packet, &response, serverName, me->p_no);
+    sendServerPacket((struct player_spacket *) & response);
+#endif				/* RWATCH */
+}
+
+#else
+
+
+static void
+handleReserved(packet)
+    struct reserved_spacket *packet;
+{
+#ifdef AUTHORIZE
+    struct reserved_cpacket response;
+
+    response.type = CP_RESERVED;
+    if (RSA_Client) {		/* can use -o option for old blessing */
+	warning(RSA_VERSION);
+	strncpy((char *)response.resp, RSA_VERSION, RESERVED_SIZE);
+	memcpy(response.data, packet->data, RESERVED_SIZE);
+    } else {
+#if 0
+	/*
+	   if we ever go back to reserved.c checking, we'll reactivate this
+	   code.  However, our reserved.c module hasn't done any real
+	   computation since paradise 1.
+	*/
+	encryptReservedPacket(packet, &response, serverName, me->p_no);
+#else
+	memcpy(response.data, packet->data, 16);
+	memcpy(response.resp, packet->data, 16);
+#endif
+    }
+    sendServerPacket((struct player_spacket *) & response);
+#endif
+}
+
+static void
+handleRSAKey(packet)
+    struct rsa_key_spacket *packet;
+{
+#ifdef AUTHORIZE
+    struct rsa_key_cpacket response;
+#ifndef DNET
+    struct sockaddr_in saddr;
+#endif
+    unsigned char *data;
+    int     len;
+
+#ifdef GATEWAY
+    extern unsigned long netaddr;
+    extern int serv_port;
+#endif
+
+#ifndef DNET
+#ifdef GATEWAY
+    /* if we didn't get it from -H, go ahead and query the socket */
+    if (netaddr == 0) {
+	len = sizeof(saddr);
+	if (getpeername(sock, (struct sockaddr *) & saddr, &len) < 0) {
+	    perror("getpeername(sock)");
+	    exit(1);
+	}
+    } else {
+	saddr.sin_addr.s_addr = netaddr;
+	saddr.sin_port = htons(serv_port);
+    }
+#else				/* GATEWAY */
+    /* query the socket to determine the remote host (ATM) */
+    len = sizeof(saddr);
+    if (getpeername(sock, (struct sockaddr *) & saddr, &len) < 0) {
+	perror("getpeername(sock)");
+	exit(1);
+    }
+#endif				/* GATEWAY */
+
+    data = packet->data;
+    bcopy(&saddr.sin_addr.s_addr, data, sizeof(saddr.sin_addr.s_addr));
+    data += sizeof(saddr.sin_addr.s_addr);
+    bcopy(&saddr.sin_port, data, sizeof(saddr.sin_port));
+#else				/* DNET */
+    {
+	extern long netrek_server_addr;
+	extern unsigned short netrek_server_port;
+
+	data = packet->data;
+	bcopy(&netrek_server_addr, data, sizeof(netrek_server_addr));
+	data += sizeof(netrek_server_addr);
+	bcopy(&netrek_server_port, data, sizeof(netrek_server_port));
+    }
+#endif				/* DNET */
+
+#ifdef DEBUG
+    {
+	struct timeval start, end;
+	gettimeofday(&start, NULL);
+#endif
+	rsa_black_box(response.resp, packet->data,
+		      response.public, response.global);
+#ifdef DEBUG
+	gettimeofday(&end, NULL);
+	printf("rsa_black_box took %d ms.\n",
+	       (1000 * (end.tv_sec - start.tv_sec) +
+		(end.tv_usec - start.tv_usec) / 1000));
+    }
+#endif
+    response.type = CP_RSA_KEY;
+
+    sendServerPacket((struct player_spacket *) & response);
+#ifdef DEBUG
+    printf("RSA verification requested.\n");
+#endif
+#endif				/* AUTHORIZE */
+}
+
+#endif
+
+#ifdef INCLUDE_SCAN
+static void
+handleScan(packet)
+    struct scan_spacket *packet;
+{
+    struct player *pp;
+
+    SANITY_PNUM(packet->pnum);
+
+    if (packet->success) {
+	pp = &players[packet->pnum];
+	pp->p_fuel = ntohl(packet->p_fuel);
+	pp->p_armies = ntohl(packet->p_armies);
+	pp->p_shield = ntohl(packet->p_shield);
+	pp->p_damage = ntohl(packet->p_damage);
+	pp->p_etemp = ntohl(packet->p_etemp);
+	pp->p_wtemp = ntohl(packet->p_wtemp);
+	informScan(packet->pnum);
+    }
+}
+
+static void
+informScan(p)
+    int     p;
+{
+}
+
+#endif				/* INCLUDE_SCAN */
+
+/*
+ * UDP stuff
+ */
+void
+sendUdpReq(req)
+    int     req;
+{
+    struct udp_req_cpacket packet;
+#ifdef RWATCH
+    return;
+#endif				/* RWATCH */
+
+    packet.type = CP_UDP_REQ;
+    packet.request = req;
+
+    if (req >= COMM_MODE) {
+	packet.request = COMM_MODE;
+	packet.connmode = req - COMM_MODE;
+	sendServerPacket((struct player_spacket *) & packet);
+	return;
+    }
+    if (req == COMM_UPDATE) {
+#ifdef SHORT_PACKETS
+	if (recv_short) {	/* not necessary */
+/* Let the client do the work, and not the network :-) */
+	    register int i;
+	    for (i = 0; i < nplayers * ntorps; i++)
+		torps[i].t_status = TFREE;
+
+	    for (i = 0; i < nplayers * nplasmas; i++)
+		plasmatorps[i].pt_status = PTFREE;
+
+	    for (i = 0; i < nplayers; i++) {
+		players[i].p_ntorp = 0;
+		players[i].p_nplasmatorp = 0;
+		phasers[i].ph_status = PHFREE;
+	    }
+	}
+#endif
+	sendServerPacket((struct player_spacket *) & packet);
+	warning("Sent request for full update");
+	return;
+    }
+    if (req == commModeReq) {
+	warning("Request is in progress, do not disturb");
+	return;
+    }
+    if (req == COMM_UDP) {
+	/* open UDP port */
+	if (openUdpConn() >= 0) {
+	    UDPDIAG(("Bound to local port %d on fd %d\n", udpLocalPort, udpSock));
+	} else {
+	    UDPDIAG(("Bind to local port %d failed\n", udpLocalPort));
+	    commModeReq = COMM_TCP;
+	    commStatus = STAT_CONNECTED;
+	    commSwitchTimeout = 0;
+	    if (udpWin)
+		udprefresh(UDP_STATUS);
+	    warning("Unable to establish UDP connection");
+
+	    return;
+	}
+    }
+    /* send the request */
+    packet.type = CP_UDP_REQ;
+    packet.request = req;
+    packet.port = htonl(udpLocalPort);
+#ifdef GATEWAY
+    if (!strcmp(serverName, gw_mach)) {
+	packet.port = htons(gw_serv_port);	/* gw port that server should
+						   call */
+	UDPDIAG(("+ Telling server to contact us on %d\n", gw_serv_port));
+    }
+#endif
+#ifdef USE_PORTSWAP
+    packet.connmode = CONNMODE_PORT;	/* have him send his port */
+#else
+    packet.connmode = CONNMODE_PACKET;	/* we get addr from packet */
+#endif
+    sendServerPacket((struct player_spacket *) & packet);
+
+    /* update internal state stuff */
+    commModeReq = req;
+    if (req == COMM_TCP)
+	commStatus = STAT_SWITCH_TCP;
+    else
+	commStatus = STAT_SWITCH_UDP;
+    commSwitchTimeout = 25;	/* wait 25 updates (about five seconds) */
+
+    UDPDIAG(("Sent request for %s mode\n", (req == COMM_TCP) ?
+	     "TCP" : "UDP"));
+
+#ifndef USE_PORTSWAP
+    if ((req == COMM_UDP) && recvUdpConn() < 0) {
+	UDPDIAG(("Sending TCP reset message\n"));
+	packet.request = COMM_TCP;
+	packet.port = 0;
+	commModeReq = COMM_TCP;
+	sendServerPacket((struct player_spacket *) & packet);
+	/* we will likely get a SWITCH_UDP_OK later; better ignore it */
+	commModeReq = COMM_TCP;
+	commStatus = STAT_CONNECTED;
+	commSwitchTimeout = 0;
+	closeUdpConn();
+    }
+#endif
+
+    if (udpWin)
+	udprefresh(UDP_STATUS);
+}
+
+static void
+handleUdpReply(packet)
+    struct udp_reply_spacket *packet;
+{
+    struct udp_req_cpacket response;
+
+    UDPDIAG(("Received UDP reply %d\n", packet->reply));
+    commSwitchTimeout = 0;
+
+    response.type = CP_UDP_REQ;
+
+    switch (packet->reply) {
+    case SWITCH_TCP_OK:
+	if (commMode == COMM_TCP) {
+	    UDPDIAG(("Got SWITCH_TCP_OK while in TCP mode; ignoring\n"));
+	} else {
+	    commMode = COMM_TCP;
+	    commStatus = STAT_CONNECTED;
+	    warning("Switched to TCP-only connection");
+	    closeUdpConn();
+	    UDPDIAG(("UDP port closed\n"));
+	    if (udpWin) {
+		udprefresh(UDP_STATUS);
+		udprefresh(UDP_CURRENT);
+	    }
+	}
+	break;
+    case SWITCH_UDP_OK:
+	if (commMode == COMM_UDP) {
+	    UDPDIAG(("Got SWITCH_UDP_OK while in UDP mode; ignoring\n"));
+	} else {
+	    /* the server is forcing UDP down our throat? */
+	    if (commModeReq != COMM_UDP) {
+		UDPDIAG(("Got unsolicited SWITCH_UDP_OK; ignoring\n"));
+	    } else {
+#ifdef USE_PORTSWAP
+		udpServerPort = ntohl(packet->port);
+#ifdef nodef			/* simulate calvin error */
+		/* XXX TMP */
+		udpServerPort = 3333;
+#endif
+		if (connUdpConn() < 0) {
+		    UDPDIAG(("Unable to connect, resetting\n"));
+		    warning("Connection attempt failed");
+		    commModeReq = COMM_TCP;
+		    commStatus = STAT_CONNECTED;
+		    if (udpSock >= 0)
+			closeUdpConn();
+		    if (udpWin) {
+			udprefresh(UDP_STATUS);
+			udprefresh(UDP_CURRENT);
+		    }
+		    response.request = COMM_TCP;
+		    response.port = 0;
+		    goto send;
+		}
+#else
+		/* this came down UDP, so we MUST be connected */
+		/* (do the verify thing anyway just for kicks) */
+#endif
+		UDPDIAG(("Connected to server's UDP port\n"));
+		commStatus = STAT_VERIFY_UDP;
+		if (udpWin)
+		    udprefresh(UDP_STATUS);
+		response.request = COMM_VERIFY;	/* send verify request on UDP */
+		response.port = 0;
+		commSwitchTimeout = 25;	/* wait 25 updates */
+#ifdef USE_PORTSWAP
+	send:
+#endif				/* USE_PORTSWAP */
+		sendServerPacket((struct player_spacket *) & response);
+	    }
+	}
+	break;
+    case SWITCH_DENIED:
+	if (ntohs(packet->port)) {
+	    UDPDIAG(("Switch to UDP failed (different version)\n"));
+	    warning("UDP protocol request failed (bad version)");
+	} else {
+	    UDPDIAG(("Switch to UDP denied\n"));
+	    warning("UDP protocol request denied");
+	}
+	commModeReq = commMode;
+	commStatus = STAT_CONNECTED;
+	commSwitchTimeout = 0;
+	if (udpWin)
+	    udprefresh(UDP_STATUS);
+	if (udpSock >= 0)
+	    closeUdpConn();
+	break;
+    case SWITCH_VERIFY:
+	UDPDIAG(("Received UDP verification\n"));
+	break;
+    default:
+	fprintf(stderr, "netrek: Got funny reply (%d) in UDP_REPLY packet\n",
+		packet->reply);
+	break;
+    }
+}
+
+#define MAX_PORT_RETRY  10
+static int
+openUdpConn()
+{
+#ifndef DNET
+    struct sockaddr_in addr;
+    struct hostent *hp;
+    int     attempts;
+
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+    if (udpSock >= 0) {
+	fprintf(stderr, "netrek: tried to open udpSock twice\n");
+	return (0);		/* pretend we succeeded (this could be bad) */
+    }
+    if ((udpSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	perror("netrek: unable to create DGRAM socket");
+	return (-1);
+    }
+#ifdef nodef
+    set_udp_opts(udpSock);
+#endif				/* nodef */
+
+    if(UdpLocalPort == 0) {
+	UdpLocalPort = intDefault("baseUdpLocalPort", 0);
+	UDPDIAG(("using base port %d\n", UdpLocalPort));
+    }
+
+    addr.sin_addr.s_addr = INADDR_ANY;
+    addr.sin_family = AF_INET;
+
+    errno = 0;
+    udpLocalPort = (getpid() & 32767) + (random() % 256);
+    for (attempts = 0; attempts < MAX_PORT_RETRY; attempts++) {
+	if(UdpLocalPort){
+	    /* force UDP to be starting at a base address */
+	    udpLocalPort = UdpLocalPort + attempts;
+	} else while (udpLocalPort < 2048) {
+	    udpLocalPort = (udpLocalPort + 10687) & 32767;
+	}
+#ifdef GATEWAY
+	/* we need the gateway to know where to find us */
+	if (!strcmp(serverName, gw_mach)) {
+	    UDPDIAG(("+ gateway test: binding to %d\n", gw_local_port));
+	    udpLocalPort = gw_local_port;
+	}
+#endif
+	addr.sin_port = htons(udpLocalPort);
+	if (bind(udpSock, (struct sockaddr *) & addr, sizeof(addr)) >= 0)
+	    break;
+    }
+    if (attempts == MAX_PORT_RETRY) {
+	perror("netrek: bind");
+	UDPDIAG(("Unable to find a local port to bind to\n"));
+	close(udpSock);
+	udpSock = -1;
+	return (-1);
+    }
+    UDPDIAG(("Local port is %d\n", udpLocalPort));
+    if(UdpLocalPort) {
+	fprintf(stdout, "Local UDP port is %d\n", udpLocalPort);
+    }
+
+    /* determine the address of the server */
+    if (!serveraddr) {
+	if ((addr.sin_addr.s_addr = inet_addr(serverName)) == -1) {
+	    if ((hp = gethostbyname(serverName)) == NULL) {
+		printf("Who is %s?\n", serverName);
+#ifdef AUTOKEY
+		if (autoKey)
+		    W_AutoRepeatOn();
+#endif
+
+		EXIT(0);
+	    } else {
+		addr.sin_addr.s_addr = *(long *) hp->h_addr;
+	    }
+	}
+	serveraddr = addr.sin_addr.s_addr;
+	UDPDIAG(("Found serveraddr == 0x%x\n", (unsigned int) serveraddr));
+    }
+    return (0);
+#else				/* DNET */
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+    return DNetOpenUDPConn(serverName);
+#endif				/* DNET */
+}
+
+#ifdef USE_PORTSWAP
+static int
+connUdpConn()
+{
+#ifndef DNET
+    struct sockaddr_in addr;
+    int     len;
+
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+    addr.sin_addr.s_addr = serveraddr;
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(udpServerPort);
+
+    UDPDIAG(("Connecting to host 0x%x on port %d\n", serveraddr, udpServerPort));
+    if (connect(udpSock, &addr, sizeof(addr)) < 0) {
+	fprintf(stderr, "Error %d: ");
+	perror("netrek: unable to connect UDP socket");
+	printUdpInfo();		/* debug */
+	return (-1);
+    }
+#ifdef nodef
+    len = sizeof(addr);
+    if (getsockname(udpSock, &addr, &len) < 0) {
+	perror("netrek: unable to getsockname(UDP)");
+	UDPDIAG(("Can't get our own socket; connection failed\n"));
+	close(udpSock);
+	udpSock = -1;
+	return -1;
+    }
+    printf("udpLocalPort %d, getsockname port %d\n",
+	   udpLocalPort, addr.sin_port);
+#endif
+
+    return (0);
+#endif				/* DNET */
+}
+#endif
+
+#ifndef USE_PORTSWAP
+static int
+recvUdpConn()
+{
+#ifndef DNET
+    fd_set  readfds;
+    struct timeval to;
+    struct sockaddr_in from;
+    int     fromlen, res;
+
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+    bzero(&from, sizeof(from));	/* don't get garbage if really broken */
+
+    /* we patiently wait until the server sends a packet to us */
+    /* (note that we silently eat the first one) */
+    UDPDIAG(("Issuing recvfrom() call\n"));
+    printUdpInfo();
+    fromlen = sizeof(from);
+    FD_ZERO(&readfds);
+    FD_SET(udpSock, &readfds);
+    to.tv_sec = 6;		/* wait 3 seconds, then abort */
+    to.tv_usec = 0;
+    if ((res = select(32, &readfds, 0, 0, &to)) <= 0) {
+	if (!res) {
+	    UDPDIAG(("timed out waiting for response"));
+	    warning("UDP connection request timed out");
+	    return (-1);
+	} else {
+	    perror("select() before recvfrom()");
+	    return (-1);
+	}
+    }
+    if (recvfrom(udpSock, buf, BUFSIZ, 0, (struct sockaddr *) & from, &fromlen) < 0) {
+	perror("recvfrom");
+	UDPDIAG(("recvfrom failed, aborting UDP attempt"));
+	return (-1);
+    }
+    if (from.sin_addr.s_addr != serveraddr) {
+	/* safe? */
+	serveraddr = from.sin_addr.s_addr;
+	UDPDIAG(("Warning: from 0x%x, but server is 0x%x\n",
+	   (unsigned int) from.sin_addr.s_addr, (unsigned int) serveraddr));
+    }
+    if (from.sin_family != AF_INET) {
+	UDPDIAG(("Warning: not AF_INET (%d)\n", from.sin_family));
+    }
+    udpServerPort = ntohs(from.sin_port);
+    UDPDIAG(("recvfrom() succeeded; will use server port %d\n", udpServerPort));
+#ifdef GATEWAY
+    if (!strcmp(serverName, gw_mach)) {
+	UDPDIAG(("+ actually, I'm going to use %d\n", gw_port));
+	udpServerPort = gw_port;
+	from.sin_port = htons(udpServerPort);
+    }
+#endif
+
+    if (connect(udpSock, (struct sockaddr *) & from, sizeof(from)) < 0) {
+	perror("netrek: unable to connect UDP socket after recvfrom()");
+	close(udpSock);
+	udpSock = -1;
+	return (-1);
+    }
+    return (0);
+#else				/* DNET */
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+    return DNetRecvUDPConn();
+#endif				/* DNET */
+}
+#endif
+
+int
+closeUdpConn()
+{
+    V_UDPDIAG(("Closing UDP socket\n"));
+#ifdef RECORDER
+    if (playback)
+	return 0;
+#endif
+
+#ifdef DNET
+    DNetCloseUDP();
+    return 0;
+#else
+    if (udpSock < 0) {
+	fprintf(stderr, "netrek: tried to close a closed UDP socket\n");
+	return (-1);
+    }
+    shutdown(udpSock, 2);
+    close(udpSock);
+    udpSock = -1;
+    return 0;
+#endif				/* DNET */
+}
+
+static void
+printUdpInfo()
+{
+#ifndef DNET
+    struct sockaddr_in addr;
+    int     len;
+
+    len = sizeof(addr);
+    if (getsockname(udpSock, (struct sockaddr *) & addr, &len) < 0) {
+/*      perror("printUdpInfo: getsockname");*/
+	return;
+    }
+    UDPDIAG(("LOCAL: addr=0x%x, family=%d, port=%d\n",
+	     (unsigned int) addr.sin_addr.s_addr,
+	     addr.sin_family, ntohs(addr.sin_port)));
+
+    if (getpeername(udpSock, (struct sockaddr *) & addr, &len) < 0) {
+/*      perror("printUdpInfo: getpeername");*/
+	return;
+    }
+    UDPDIAG(("PEER : addr=0x%x, family=%d, port=%d\n",
+	     (unsigned int) addr.sin_addr.s_addr,
+	     addr.sin_family, ntohs(addr.sin_port)));
+#endif
+}
+
+static void
+handleSequence(packet)
+    struct sequence_spacket *packet;
+{
+    static int recent_count = 0, recent_dropped = 0;
+    long    newseq;
+
+    drop_flag = 0;
+    if (chan != udpSock)
+	return;			/* don't pay attention to TCP sequence #s */
+    udpTotal++;
+    recent_count++;
+
+    /* update percent display every 256 updates (~50 seconds usually) */
+    if (!(udpTotal & 0xff))
+	if (udpWin)
+	    udprefresh(UDP_DROPPED);
+
+    newseq = (long) ntohs(packet->sequence);
+/*    printf("read %d - ", newseq);*/
+
+    if (((unsigned short) sequence) > 65000 &&
+	((unsigned short) newseq) < 1000) {
+	/* we rolled, set newseq = 65536+sequence and accept it */
+	sequence = ((sequence + 65536) & 0xffff0000) | newseq;
+    } else {
+	/* adjust newseq and do compare */
+	newseq |= (sequence & 0xffff0000);
+
+	if (!udpSequenceChk) {	/* put this here so that turning seq check */
+	    sequence = newseq;	/* on and off doesn't make us think we lost */
+	    return;		/* a whole bunch of packets. */
+	}
+	if (newseq > sequence) {
+	    /* accept */
+	    if (newseq != sequence + 1) {
+		udpDropped += (newseq - sequence) - 1;
+		udpTotal += (newseq - sequence) - 1;	/* want TOTAL packets */
+		recent_dropped += (newseq - sequence) - 1;
+		recent_count += (newseq - sequence) - 1;
+		if (udpWin)
+		    udprefresh(UDP_DROPPED);
+		UDPDIAG(("sequence=%ld, newseq=%ld, we lost some\n",
+			 sequence, newseq));
+	    }
+	    sequence = newseq;
+	} else {
+	    /* reject */
+	    if (packet->type == SP_SC_SEQUENCE) {
+		V_UDPDIAG(("(ignoring repeat %ld)\n", newseq));
+	    } else {
+		UDPDIAG(("sequence=%ld, newseq=%ld, ignoring transmission\n",
+			 sequence, newseq));
+	    }
+	    /*
+	       the remaining packets will be dropped and we shouldn't count
+	       the SP_SEQUENCE packet either
+	    */
+	    packets_received--;
+	    drop_flag = 1;
+	}
+    }
+/*    printf("newseq %d, sequence %d\n", newseq, sequence);*/
+    if (recent_count > UDP_RECENT_INTR) {
+	/* once a minute (at 5 upd/sec), report on how many were dropped */
+	/* during the last UDP_RECENT_INTR updates                       */
+	udpRecentDropped = recent_dropped;
+	recent_count = recent_dropped = 0;
+	if (udpWin)
+	    udprefresh(UDP_DROPPED);
+    }
+}
+
+
+/*
+static void dumpShip(shipp)
+struct ship *shipp;
+{
+  printf("ship stats:\n");
+  printf("phaser range = %d\n", shipp->s_phaserrange);
+  printf("max speed = %d\n", shipp->s_maxspeed);
+  printf("max shield = %d\n", shipp->s_maxshield);
+  printf("max damage = %d\n", shipp->s_maxdamage);
+  printf("max egntemp = %d\n", shipp->s_maxegntemp);
+  printf("max wpntemp = %d\n", shipp->s_maxwpntemp);
+  printf("max armies = %d\n", shipp->s_maxarmies);
+  printf("type = %d\n", shipp->s_type);
+  printf("torp speed = %d\n", shipp->s_torpspeed);
+  printf("letter = %c\n", shipp->s_letter);
+  printf("desig = %2.2s\n", shipp->s_desig);
+  printf("bitmap = %d\n\n", shipp->s_bitmap);
+}
+*/
+
+static void
+handleShipCap(packet)		/* SP_SHIP_CAP */
+    struct ship_cap_spacket *packet;
+{
+    struct shiplist *temp;
+
+    /*
+       What are we supposed to do?
+    */
+
+    SANITY_SHIPNUM(ntohs(packet->s_type));
+
+    if (packet->operation) {	/* remove ship from list */
+	temp = shiptypes;
+	if (temp->ship->s_type == (int) ntohs(packet->s_type)) {
+	    shiptypes = temp->next;
+	    shiptypes->prev = NULL;
+	}
+	while (temp->next != NULL) {
+	    if (temp->next->ship->s_type == (int) ntohs(packet->s_type)) {
+		temp = temp->next;
+		temp->prev->next = temp->next;
+		if (temp->next)
+		    temp->next->prev = temp->prev;
+		free(temp->ship);
+		free(temp);
+		return;
+	    } else {
+		temp = temp->next;
+	    }
+	}
+    }
+    /*
+       Since we're adding the ship, we need to find out if we already have
+       that ship, and if so, replace it.
+    */
+
+    temp = shiptypes;
+    while (temp != NULL) {
+	if (temp->ship->s_type == (int) ntohs(packet->s_type)) {
+	    temp->ship->s_type = ntohs(packet->s_type);
+	    temp->ship->s_torpspeed = ntohs(packet->s_torpspeed);
+	    temp->ship->s_phaserrange = ntohs(packet->s_phaserrange);
+	    if (temp->ship->s_phaserrange < 200)	/* backward
+							   compatibility */
+		temp->ship->s_phaserrange *= PHASEDIST / 100;
+	    temp->ship->s_maxspeed = ntohl(packet->s_maxspeed);
+	    temp->ship->s_maxfuel = ntohl(packet->s_maxfuel);
+	    temp->ship->s_maxshield = ntohl(packet->s_maxshield);
+	    temp->ship->s_maxdamage = ntohl(packet->s_maxdamage);
+	    temp->ship->s_maxwpntemp = ntohl(packet->s_maxwpntemp);
+	    temp->ship->s_maxegntemp = ntohl(packet->s_maxegntemp);
+	    temp->ship->s_maxarmies = ntohs(packet->s_maxarmies);
+	    temp->ship->s_letter = packet->s_letter;
+	    temp->ship->s_desig[0] = packet->s_desig1;
+	    temp->ship->s_desig[1] = packet->s_desig2;
+	    temp->ship->s_bitmap = ntohs(packet->s_bitmap);
+	    buildShipKeymap(temp->ship);
+/*dumpShip(temp->ship);*/
+	    return;
+	}
+	temp = temp->next;
+    }
+
+    /*
+       Not there, so we need to make a new entry in the list for it.
+    */
+    temp = (struct shiplist *) malloc(sizeof(struct shiplist));
+    temp->next = shiptypes;
+    temp->prev = NULL;
+    if (shiptypes)
+	shiptypes->prev = temp;
+    shiptypes = temp;
+    temp->ship = (struct ship *) malloc(sizeof(struct ship));
+    temp->ship->s_type = ntohs(packet->s_type);
+    temp->ship->s_torpspeed = ntohs(packet->s_torpspeed);
+    temp->ship->s_phaserrange = ntohs(packet->s_phaserrange);
+    temp->ship->s_maxspeed = ntohl(packet->s_maxspeed);
+    temp->ship->s_maxfuel = ntohl(packet->s_maxfuel);
+    temp->ship->s_maxshield = ntohl(packet->s_maxshield);
+    temp->ship->s_maxdamage = ntohl(packet->s_maxdamage);
+    temp->ship->s_maxwpntemp = ntohl(packet->s_maxwpntemp);
+    temp->ship->s_maxegntemp = ntohl(packet->s_maxegntemp);
+    temp->ship->s_maxarmies = ntohs(packet->s_maxarmies);
+    temp->ship->s_letter = packet->s_letter;
+    temp->ship->s_desig[0] = packet->s_desig1;
+    temp->ship->s_desig[1] = packet->s_desig2;
+    temp->ship->s_bitmap = ntohs(packet->s_bitmap);
+    buildShipKeymap(temp->ship);
+/*  dumpShip(temp->ship);*/
+}
+
+static void
+handleMotdPic(packet)		/* SP_SHIP_CAP */
+    struct motd_pic_spacket *packet;
+{
+    int     x, y, page, width, height;
+
+    x = ntohs(packet->x);
+    y = ntohs(packet->y);
+    width = ntohs(packet->width);
+    height = ntohs(packet->height);
+    page = ntohs(packet->page);
+
+    newMotdPic(x, y, width, height, (char *) packet->bits, page);
+}
+
+static void
+handleStats2(packet)
+    struct stats_spacket2 *packet;
+{
+    struct stats2 *p;		/* to hold packet's player's stats2 struct */
+
+    SANITY_PNUM(packet->pnum);
+
+    updatePlayer[packet->pnum] |= LARGE_UPDATE;
+    if (infomapped && infotype == PLAYERTYPE &&
+	((struct player *) infothing)->p_no == packet->pnum)
+	infoupdate = 1;
+    p = &(players[packet->pnum].p_stats2);	/* get player's stats2 struct */
+    p->st_genocides = ntohl(packet->genocides);
+    p->st_tmaxkills = (float) ntohl(packet->maxkills) / 100.0;
+    p->st_di = (float) ntohl(packet->di) / 100.0;
+    p->st_tkills = (int) ntohl(packet->kills);
+    p->st_tlosses = (int) ntohl(packet->losses);
+    p->st_tarmsbomb = (int) ntohl(packet->armsbomb);
+    p->st_tresbomb = (int) ntohl(packet->resbomb);
+    p->st_tdooshes = (int) ntohl(packet->dooshes);
+    p->st_tplanets = (int) ntohl(packet->planets);
+    p->st_tticks = (int) ntohl(packet->tticks);
+    p->st_sbkills = (int) ntohl(packet->sbkills);
+    p->st_sblosses = (int) ntohl(packet->sblosses);
+    p->st_sbticks = (int) ntohl(packet->sbticks);
+    p->st_sbmaxkills = (float) ntohl(packet->sbmaxkills) / 100.0;
+    p->st_wbkills = (int) ntohl(packet->wbkills);
+    p->st_wblosses = (int) ntohl(packet->wblosses);
+    p->st_wbticks = (int) ntohl(packet->wbticks);
+    p->st_wbmaxkills = (float) ntohl(packet->wbmaxkills) / 100.0;
+    p->st_jsplanets = (int) ntohl(packet->jsplanets);
+    p->st_jsticks = (int) ntohl(packet->jsticks);
+    if (p->st_rank != (int) ntohl(packet->rank) ||
+	p->st_royal != (int) ntohl(packet->royal)) {
+	p->st_rank = (int) ntohl(packet->rank);
+	p->st_royal = (int) ntohl(packet->royal);
+	updatePlayer[packet->pnum] |= ALL_UPDATE;
+    }
+}
+
+static void
+handleStatus2(packet)
+    struct status_spacket2 *packet;
+{
+    updatePlayer[me->p_no] |= LARGE_UPDATE;
+    if (infomapped && infotype == PLAYERTYPE &&
+	((struct player *) infothing)->p_no == me->p_no)
+	infoupdate = 1;
+    status2->tourn = packet->tourn;
+    status2->dooshes = ntohl(packet->dooshes);
+    status2->armsbomb = ntohl(packet->armsbomb);
+    status2->resbomb = ntohl(packet->resbomb);
+    status2->planets = ntohl(packet->planets);
+    status2->kills = ntohl(packet->kills);
+    status2->losses = ntohl(packet->losses);
+    status2->sbkills = ntohl(packet->sbkills);
+    status2->sblosses = ntohl(packet->sblosses);
+    status2->sbtime = ntohl(packet->sbtime);
+    status2->wbkills = ntohl(packet->wbkills);
+    status2->wblosses = ntohl(packet->wblosses);
+    status2->wbtime = ntohl(packet->wbtime);
+    status2->jsplanets = ntohl(packet->jsplanets);
+    status2->jstime = ntohl(packet->jstime);
+    status2->time = ntohl(packet->time);
+    status2->timeprod = ntohl(packet->timeprod);
+}
+
+static void
+handlePlanet2(packet)
+    struct planet_spacket2 *packet;
+{
+    SANITY_PLANNUM(packet->pnum);
+
+    planets[packet->pnum].pl_owner = packet->owner;
+    planets[packet->pnum].pl_info = packet->info;
+    planets[packet->pnum].pl_flags = ntohl(packet->flags);
+    planets[packet->pnum].pl_timestamp = ntohl(packet->timestamp);
+    planets[packet->pnum].pl_armies = ntohl(packet->armies);
+    planets[packet->pnum].pl_flags |= PLREDRAW;
+    pl_update[packet->pnum].plu_update = 1;
+    pl_update[packet->pnum].plu_x = planets[packet->pnum].pl_x;
+    pl_update[packet->pnum].plu_y = planets[packet->pnum].pl_y;
+    if (infomapped && infotype == PLANETTYPE &&
+	((struct planet *) infothing)->pl_no == packet->pnum)
+	infoupdate = 1;
+}
+
+static void 
+handleTerrainInfo2(pkt)
+  struct terrain_info_packet2 *pkt;
+{
+#ifdef ZDIAG2
+    fprintf( stderr, "Receiving terrain info packet\n" );
+    fprintf( stderr, "Terrain dims: %d x %d\n", ntohs(pkt->xdim), ntohs(pkt->ydim) );
+#endif
+    received_terrain_info = TERRAIN_STARTED;
+    terrain_x = ntohs(pkt->xdim);
+    terrain_y = ntohs(pkt->ydim);
+} 
+
+static void
+handleTerrain2(pkt)
+    struct terrain_packet2 *pkt;
+{
+    static int curseq = 0, totbytes = 0, done = 0;
+    int i, status;
+    unsigned long dlen;
+#ifdef ZDIAG2
+    static unsigned char sum = 0;
+    static unsigned numnz = 0;
+#endif
+    static unsigned char *gzipTerrain = NULL, *orgTerrain = NULL;
+    
+#ifdef ZDIAG2
+    fprintf( stderr, "Receiving Terrain packet.  This should be %d.\n", curseq+1 );
+#endif
+
+    if( (done == TERRAIN_DONE) && (received_terrain_info == TERRAIN_STARTED ) ){
+      /* receiving new terrain info */
+      free( gzipTerrain );
+      free( orgTerrain );
+      free( terrainInfo );
+      gzipTerrain = orgTerrain = NULL;
+      terrainInfo = NULL;
+      curseq = done = totbytes = 0;
+    }
+      
+    curseq++;
+    if( (curseq != pkt->sequence) || !(received_terrain_info) ){
+      /* Should fill in a list of all packets missed */
+      /* or request header packet from server */
+      fprintf( stderr, "Blech!  Received terrain packet before terrain_info\n" );
+      return;
+    }
+#ifdef ZDIAG2
+    fprintf( stderr, "Receiving packet %d out of %d\n", curseq, pkt->total_pkts );
+#endif
+    if( !gzipTerrain ){
+      gzipTerrain = (unsigned char *)malloc( pkt->total_pkts << 7 );
+#if defined(ZDIAG) || defined(ZDIAG2)
+      fprintf( stderr, "Allocating %d bytes for gzipTerrain.\n", pkt->total_pkts << 7 );
+#endif
+		/* another yukko constant */
+    }
+    if( !orgTerrain ){
+      orgTerrain = (unsigned char *)malloc( terrain_x*terrain_y );
+      dlen = terrain_x * terrain_y;
+#if defined(ZDIAG) || defined(ZDIAG2)
+      fprintf( stderr, "Allocating %d bytes for orgTerrain.\n", dlen );
+#endif
+    }
+    for( i = 0; i < pkt->length; i++ ){
+#ifdef ZDIAG2
+      if( !(i%10) ){
+        fprintf( stderr, "Params: %d, %d\n", ((curseq-1)<<7)+i, i );
+      }
+#endif
+      gzipTerrain[((curseq-1)<<7)+i] = pkt->terrain_type[i];
+    }
+    totbytes += pkt->length;
+    if( curseq == pkt->total_pkts ){
+#if defined(ZDIAG) || defined(ZDIAG2)
+      status = uncompress( orgTerrain, &dlen, gzipTerrain, totbytes );
+      if( status != Z_OK ){
+        if( status == Z_BUF_ERROR ){
+          fprintf( stderr, "Unable to uncompress -- Z_BUF_ERROR.\n" );
+        }
+        if( status == Z_MEM_ERROR ){
+          fprintf( stderr, "Unable to uncompress -- Z_MEM_ERROR.\n" );
+        }
+        if( status = Z_DATA_ERROR ){
+          fprintf( stderr, "Unable to uncompress -- Z_DATA_ERROR!\n" );
+        }
+      }
+      else{
+        fprintf( stderr, "Total zipped terrain received: %d bytes\n", totbytes );
+      }
+#else
+      uncompress( orgTerrain, &dlen, gzipTerrain, totbytes );
+#endif
+      terrainInfo = (struct t_unit *)malloc( dlen * sizeof( struct t_unit ) );
+      for( i = 0; i < dlen; i++ ){
+        terrainInfo[i].types = orgTerrain[i];
+#ifdef ZDIAG2
+	sum |= orgTerrain[i];
+        if( orgTerrain[i] != 0 ){
+          numnz++;
+        }
+#endif
+      }
+      done = received_terrain_info = TERRAIN_DONE;
+#ifdef ZDIAG2
+      fprintf( stderr, "Sum = %d, numnz = %d\n", sum, numnz );
+#endif
+    }
+}    
+
+static void
+handleTempPack(packet)		/* SP_SHIP_CAP */
+    struct obvious_packet *packet;
+{
+    struct obvious_packet reply;
+    /* printf("New MOTD info available\n"); */
+    erase_motd();
+    reply.type = CP_ASK_MOTD;
+    sendServerPacket((struct player_spacket *) & reply);
+}
+
+/* handlers for the extension1 packet */
+
+int
+compute_extension1_size(pkt)
+    char   *pkt;
+{
+    if (pkt[0] != SP_PARADISE_EXT1)
+	return -1;
+
+    switch (pkt[1]) {
+    case SP_PE1_MISSING_BITMAP:
+	return sizeof(struct pe1_missing_bitmap_spacket);
+    case SP_PE1_NUM_MISSILES:
+	return sizeof(struct pe1_num_missiles_spacket);
+    default:
+	return -1;
+    }
+}
+
+static void
+handleExtension1(packet)
+    struct paradiseext1_spacket *packet;
+{
+    switch (packet->subtype) {
+    case SP_PE1_MISSING_BITMAP:
+	{
+	    struct pe1_missing_bitmap_spacket *pkt =
+	    (struct pe1_missing_bitmap_spacket *) packet;
+
+	    newMotdPic(ntohs(pkt->x),
+		       ntohs(pkt->y),
+		       ntohs(pkt->width),
+		       ntohs(pkt->height),
+		       0,
+		       ntohs(pkt->page));
+	}
+	break;
+    case SP_PE1_NUM_MISSILES:
+	me->p_totmissiles = ntohs(((struct pe1_num_missiles_spacket *) packet)->num);
+	/* printf("updated totmissiles to %d\n",me->p_totmissiles); */
+	if (me->p_totmissiles < 0)
+	    me->p_totmissiles = 0;	/* SB/WB have -1 */
+	break;
+    default:
+	printf("unknown paradise extension packet 1 subtype = %d\n",
+	       packet->subtype);
+    }
+}