Mercurial > ~darius > hgwebdir.cgi > paradise_client
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); + } +}