Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff src/socket.c @ 6:8c6d5731234d
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:04 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/socket.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,4607 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <netdb.h> +#include <math.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <zlib.h> +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" +#include "path.h" +#include "gppackets.h" + +#ifdef OOPS +#ifdef MIPSEL +#ifndef htonl + +#define htonl(x) ((u_long) (((u_long) x << 24) | (((u_long) x & 0xff00) << 8) | \ + (((u_long) x & 0xff0000) >> 8) | ((u_long) x >> 24))) +#define ntohl(x) htonl(x) +#define htons(x) ((u_short) (((u_short) x << 8) | ((u_short) x >> 8))) +#define ntohs(x) htons(x) + +#endif /* htonl */ +#endif /* MIPSEL */ +#endif /* OOPS */ + +extern void (*r_signal()) (); + +/* #define DOUBLE_UDP /* comment this out to disable it */ + +/* #define BROKEN /* for local stress testing; drops 20% of packets */ +/* #define HOSED /* combine with BROKEN; drops 90% of packets */ + +void handleTorpReq(), handlePhasReq(), handleSpeedReq(); +void handleDirReq(), handleShieldReq(), handleRepairReq(), handleOrbitReq(); +void handlePractrReq(), handleBombReq(), handleBeamReq(), handleCloakReq(); +void handleDetTReq(), handleCopilotReq(); +void handleOutfit(), handleLoginReq(); +void handlePlasmaReq(), handleWarReq(), handlePlanlockReq(); +void handlePlaylockReq(), handleDetMReq(); +void handleTractorReq(), handleRepressReq(); +void handleCoupReq(), handleRefitReq(), handleMessageReq(); +void handleQuitReq(), handleOptionsPacket(); +void handleSocketReq(), handleByeReq(); +void handleDockingReq(), handleReset(); +void handleUpdatesReq(), handleReserved(); +void handleScan(); +void handleUdpReq(), handleSequence(); +void handleAskMOTD(); +void handleRSAKey(); +void handlePingResponse(); +#ifdef SHORT_PACKETS +void handleShortReq(), handleThresh(), handleSMessageReq(); +#endif +#ifdef FEATURE +void handleFeature(), sendFeature(); /* in feature.c */ +#endif + +static int remoteaddr = -1; /* inet address in net format */ +extern int errno; + +struct packet_handler handlers[] = { + {0}, /* record 0 */ + {handleMessageReq}, /* CP_MESSAGE */ + {handleSpeedReq}, /* CP_SPEED */ + {handleDirReq}, /* CP_DIRECTION */ + {handlePhasReq}, /* CP_PHASER */ + {handlePlasmaReq}, /* CP_PLASMA */ + {handleTorpReq}, /* CP_TORP */ + {handleQuitReq}, /* CP_QUIT */ + {handleLoginReq}, /* CP_LOGIN */ + {handleOutfit}, /* CP_OUTFIT */ + {handleWarReq}, /* CP_WAR */ + {handlePractrReq}, /* CP_PRACTR */ + {handleShieldReq}, /* CP_SHIELD */ + {handleRepairReq}, /* CP_REPAIR */ + {handleOrbitReq}, /* CP_ORBIT */ + {handlePlanlockReq}, /* CP_PLANLOCK */ + {handlePlaylockReq}, /* CP_PLAYLOCK */ + {handleBombReq}, /* CP_BOMB */ + {handleBeamReq}, /* CP_BEAM */ + {handleCloakReq}, /* CP_CLOAK */ + {handleDetTReq}, /* CP_DET_TORPS */ + {handleDetMReq}, /* CP_DET_MYTORP */ + {handleCopilotReq}, /* CP_COPLIOT */ + {handleRefitReq}, /* CP_REFIT */ + {handleTractorReq}, /* CP_TRACTOR */ + {handleRepressReq}, /* CP_REPRESS */ + {handleCoupReq}, /* CP_COUP */ + {handleSocketReq}, /* CP_SOCKET */ + {handleOptionsPacket}, /* CP_OPTIONS */ + {handleByeReq}, /* CP_BYE */ + {handleDockingReq}, /* CP_DOCKPERM */ + {handleUpdatesReq}, /* CP_UPDATES */ + {handleReset}, /* CP_RESETSTATS */ + {handleReserved}, /* CP_RESERVED */ + {handleScan}, /* CP_SCAN (ATM) */ + {handleUdpReq}, /* CP_UDP_REQ */ + {handleSequence}, /* CP_SEQUENCE */ + {handleRSAKey}, /* CP_RSA_KEY */ + {handleAskMOTD}, /* CP_ASK_MOTD */ + {0}, + {0}, + {0}, + {handlePingResponse}, /* CP_PING_RESPONSE */ +#ifdef SHORT_PACKETS + {handleShortReq}, /* CP_S_REQ */ + {handleThresh}, /* CP_S_THRS */ + {handleSMessageReq}, /* CP_S_MESSAGE */ + {0}, /* CP_S_RESERVED */ + {0}, /* CP_S_DUMMY */ +#else + {0}, + {0}, + {0}, + {0}, + {0}, +#endif + {0}, /* 48 */ + {0}, /* 49 */ + {0}, /* 50 */ + {0}, /* 51 */ + {0}, /* 52 */ + {0}, /* 53 */ + {0}, /* 54 */ + {0}, /* 55 */ + {0}, /* 56 */ + {0}, /* 57 */ + {0}, /* 58 */ + {0}, /* 59 */ + {handleFeature}, /* CP_FEATURE */ + {0} +}; +#define NUM_PACKETS (sizeof(handlers) / sizeof(*handlers) - 1) + +int size_of_spacket(); +int size_of_cpacket(); + +int packetsReceived[256] = {0}; +int packetsSent[256] = {0}; + +int clientDead = 0; + +static int udpLocalPort = 0; +static int udpClientPort = 0; +int udpMode = MODE_SIMPLE; /* what kind of UDP trans we want */ + +/* this stuff is used for Fat UDP */ +typedef void *PTR; /* adjust this if you lack (void *) */ +typedef struct fat_node_t +{ + PTR packet; + int pkt_size; + struct fat_node_t *prev; + struct fat_node_t *next; +} FAT_NODE; + +/* needed for fast lookup of semi-critical fat nodes */ +extern FAT_NODE fat_kills[MAXPLAYER]; +extern FAT_NODE fat_torp_info[MAXPLAYER * MAXTORP]; +extern FAT_NODE fat_thingy_info[TOTALTHINGIES]; +extern FAT_NODE fat_phaser[MAXPLAYER]; +extern FAT_NODE fat_plasma_info[MAXPLAYER * MAXPLASMA]; +extern FAT_NODE fat_you; +#if 0 +extern FAT_NODE fat_status; +extern FAT_NODE fat_planet[MAXPLANETS]; +#else +extern FAT_NODE fat_status2; +extern FAT_NODE fat_planet2[MAXPLANETS]; +#endif +extern FAT_NODE fat_flags[MAXPLAYER]; +extern FAT_NODE fat_hostile[MAXPLAYER]; + +struct plyr_info_spacket clientPlayersInfo[MAXPLAYER]; +struct plyr_login_spacket clientLogin[MAXPLAYER]; +struct hostile_spacket clientHostile[MAXPLAYER]; +struct stats_spacket clientStats[MAXPLAYER]; +struct player_spacket clientPlayers[MAXPLAYER]; +struct kills_spacket clientKills[MAXPLAYER]; +struct flags_spacket clientFlags[MAXPLAYER]; +struct pstatus_spacket clientPStatus[MAXPLAYER]; +int msgCurrent; +struct torp_info_spacket clientTorpsInfo[MAXPLAYER * MAXTORP]; +struct torp_spacket clientTorps[MAXPLAYER * MAXTORP]; +struct thingy_info_spacket clientThingysInfo[TOTALTHINGIES]; +struct thingy_spacket clientThingys[TOTALTHINGIES]; +int clientThingyStatus[TOTALTHINGIES]; +struct phaser_spacket clientPhasers[MAXPLAYER]; +struct you_spacket clientSelf; +struct pe1_num_missiles_spacket clientMissiles; +#if 0 +struct status_spacket clientStatus; +struct planet_spacket clientPlanets[MAXPLANETS]; +#endif +struct planet_loc_spacket clientPlanetLocs[MAXPLANETS]; +struct plasma_info_spacket clientPlasmasInfo[MAXPLAYER * MAXPLASMA]; +struct plasma_spacket clientPlasmas[MAXPLAYER * MAXPLASMA]; +int mustUpdate[MAXPLAYER]; +struct status_spacket2 clientStatus2; /* new stats packets */ +struct stats_spacket2 clientStats2[MAXPLAYER]; +struct planet_spacket2 clientPlanets2[MAXPLANETS]; + +#ifdef SHORT_PACKETS + +struct youss_spacket clientSelfShip; +struct youshort_spacket clientSelfShort; + +/* HW */ +static unsigned char clientVPlanets[MAXPLANETS * sizeof(struct planet_s_spacket) + 2 + 6]; +static int clientVPlanetCount; +static int vtsize[9] = {4, 8, 8, 12, 12, 16, 20, 20, 24}; /* How big is the + * SP_S_TORP packet */ +static int vtdata[9] = {0, 3, 5, 7, 9, 12, 14, 16, 18}; /* How big is Torpdata */ +static int mustsend; /* Flag to remind me that i must send + * SP_S_TORP */ + +static unsigned char clientVTorps[40]; + +static unsigned char clientVTorpsInfo[16]; + +static unsigned char clientVPlayers[MAXPLAYER * VPLAYER_SIZE + 16]; +#if MAXPLAYER > 32 +static unsigned char clientVXPlayers[33 * 4]; +#endif +static int clientVPlayerCount; +static int clientVXPlayerCount; +static int big, small; + +static int send_threshold = 0; /* infinity */ +static int send_short = 0; +static int send_mesg = 1; +static int send_kmesg = 1; +static int send_warn = 1; +static int numupdates = 5; /* For threshold */ +static int actual_threshold = 0;/* == send_threshold / numupdates */ +static int spk_update_sall = 0; /* Small Update: Only weapons, Kills and + * Planets */ +static int spk_update_all = 0; /* Full Update minus SP_STATS */ + +#define SPK_VOFF 0 /* variable packets off */ +#define SPK_VON 1 /* variable packets on */ +#define SPK_MOFF 2 /* message packets off */ +#define SPK_MON 3 /* message packets on */ +#define SPK_M_KILLS 4 +#define SPK_M_NOKILLS 5 +#define SPK_THRESHOLD 6 +#define SPK_M_WARN 7 +#define SPK_M_NOWARN 8 +#define SPK_SALL 9 /* only planets,kills and weapons */ +#define SPK_ALL 10 /* Full Update - SP_STATS */ + +#endif + + +extern long unsigned int inet_addr( /* ??? */ ); +void initClientData(); +void updateTorpInfos(); +void short_updateTorps(), updateTorps(); +void updateMissiles(); +void updateThingies(); +void updatePlasmas(); +void updateStatus(); +void updateSelf(); +void updatePhasers(); +void updateShips(); +void updatePlanets(); +void updateTerrain(); +void updateMessages(); +void sendMissileNum(); +extern void updateWarnings(); /* warning.c */ +void sendClientSizedPacket(); +void sendClientPacket(); +void flushSockBuf(); +void updateMOTD(); +int parseQuery(); +void bounce(); +int gwrite(); +void printUdpInfo(); +int closeUdpConn(); +void updateFat(); +int fatten(); +void fatMerge(); +int doRead(); +extern int read(); +extern void perror(); +void logmessage(); +extern int ntorp(); +extern int phaser(); +extern int set_speed(); +extern int set_course(); +extern int shield_up(); +extern int shield_down(); +extern int repair(); +extern int orbit(); +extern pid_t fork(); +extern int execl(); +extern int bomb_planet(); +extern int beam_up(); +extern int beam_down(); +extern int cloak_on(); +extern int cloak_off(); +extern void detothers(); +extern void fire_missile_dir(); +extern int nplasmatorp(); +extern int lock_planet(); +extern int lock_player(); +extern int do_refit(); +extern int pmessage2(); +extern int parse_command_mess(); +extern int write(); +extern int setitimer(); +extern int gethostname(); +extern int decryptRSAPacket(); +extern int makeRSAPacket(); +extern int encryptReservedPacket(); +void forceUpdate(); +int connUdpConn(); +extern int sendMotd(); +void dequeue(); +void enqueue(); +extern int pmessage(); + +int +connectToClient(machine, port) + char *machine; + int port; +{ + int ns; + struct sockaddr_in addr; + struct hostent *hp; + /* int len,cc; */ + /* char buf[BUFSIZ]; */ + /* int i; */ + + if (sock != -1) + { + shutdown(sock, 2); + sock = -1; + } + /* printf("Connecting to %s through %d\n", machine, port); */ + + if ((ns = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("I cannot create a socket\n"); + exit(2); + } + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (remoteaddr != -1) + { + addr.sin_addr.s_addr = remoteaddr; + } + else if ((addr.sin_addr.s_addr = inet_addr(machine)) == -1) + { + if ((hp = gethostbyname(machine)) == NULL) + { + printf("I cannot get host name\n"); + close(ns); + exit(1); + } + else + { +#if 1 + memcpy((char *) &addr.sin_addr, hp->h_addr, hp->h_length); +#else + addr.sin_addr.s_addr = *(long *) hp->h_addr; +#endif + } + } + remoteaddr = addr.sin_addr.s_addr; + + if (connect(ns, (struct sockaddr *) & addr, sizeof(addr)) < 0) + { + /* printf("I cannot connect through port %d\n", port); */ + close(ns); + return (0); + } + sock = ns; + initClientData(); + testtime = -1; + return (1); +} + +/* + * Check the socket to read it's inet addr for possible future use. + */ +void +checkSocket() +{ + struct sockaddr_in sin; + int length; + + length = sizeof(sin); + if (getpeername(sock, (struct sockaddr *) & sin, &length) < 0) + { + /* A bad thing. */ + return; + } + remoteaddr = sin.sin_addr.s_addr; +} + +void +initClientData() +/* invalidates all data, so it is all sent to the client */ +{ + int i; + + clientDead = 0; + clientMissiles.num = 0; + for (i = 0; i < MAXPLAYER; i++) + { + clientHostile[i].hostile = -1; + clientStats[i].losses = -1; + clientLogin[i].rank = -1; + clientPlayersInfo[i].shiptype = -1; + clientPStatus[i].status = -1; + clientPlayers[i].x = htonl(-1); + clientPhasers[i].status = -1; + clientKills[i].kills = htonl(-1); + clientFlags[i].flags = htonl(-1); + mustUpdate[i] = 0; + + fat_hostile[i].packet = (PTR) & clientHostile[i]; + fat_hostile[i].pkt_size = sizeof(struct hostile_spacket); + fat_hostile[i].prev = fat_hostile[i].next = (FAT_NODE *) NULL; + fat_phaser[i].packet = (PTR) & clientPhasers[i]; + fat_phaser[i].pkt_size = sizeof(struct phaser_spacket); + fat_phaser[i].prev = fat_phaser[i].next = (FAT_NODE *) NULL; + fat_kills[i].packet = (PTR) & clientKills[i]; + fat_kills[i].pkt_size = sizeof(struct kills_spacket); + fat_kills[i].prev = fat_kills[i].next = (FAT_NODE *) NULL; + fat_flags[i].packet = (PTR) & clientFlags[i]; + fat_flags[i].pkt_size = sizeof(struct flags_spacket); + fat_flags[i].prev = fat_flags[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLAYER * MAXTORP; i++) + { + clientTorpsInfo[i].status = -1; + clientTorps[i].x = -1; + + fat_torp_info[i].packet = (PTR) & clientTorpsInfo[i]; + fat_torp_info[i].pkt_size = sizeof(struct torp_info_spacket); + fat_torp_info[i].prev = fat_torp_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < TOTALTHINGIES; i++) + { + clientThingysInfo[i].shape = htons(-1); + clientThingysInfo[i].owner = htons(i / NPTHINGIES); + clientThingys[i].x = htonl(-1); + + fat_thingy_info[i].packet = (PTR) & clientThingysInfo[i]; + fat_thingy_info[i].pkt_size = sizeof(struct torp_info_spacket); + fat_thingy_info[i].prev = fat_thingy_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLAYER * MAXPLASMA; i++) + { + clientPlasmasInfo[i].status = -1; + clientPlasmas[i].x = -1; + + fat_plasma_info[i].packet = (PTR) & clientPlasmasInfo[i]; + fat_plasma_info[i].pkt_size = sizeof(struct plasma_info_spacket); + fat_plasma_info[i].prev = fat_plasma_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLANETS; i++) + { + clientPlanets2[i].armies = htonl(-1); + clientPlanetLocs[i].x = htonl(-1); + +#if 0 + fat_planet[i].packet = (PTR) & clientPlanets[i]; + fat_planet[i].pkt_size = sizeof(struct planet_spacket); + fat_planet[i].prev = fat_planet[i].next = (FAT_NODE *) NULL; +#else + fat_planet2[i].packet = (PTR) & clientPlanets2[i]; + fat_planet2[i].pkt_size = sizeof(struct planet_spacket2); + fat_planet2[i].prev = fat_planet2[i].next = (FAT_NODE *) 0; +#endif + } + msgCurrent = (mctl->mc_current + 1) % MAXMESSAGE; + clientSelf.pnum = -1; + + fat_you.packet = (PTR) & clientSelf; + fat_you.pkt_size = sizeof(struct you_spacket); + fat_you.prev = fat_you.next = (FAT_NODE *) NULL; +#if 0 + fat_status.packet = (PTR) & clientStatus; + fat_status.pkt_size = sizeof(struct status_spacket); + fat_status.prev = fat_status.next = (FAT_NODE *) NULL; +#else + fat_status2.packet = (PTR) & clientStatus2; + fat_status2.pkt_size = sizeof(struct status_spacket2); + fat_status2.prev = fat_status2.next = (FAT_NODE *) 0; +#endif + + reset_fat_list(); +} + +int +isClientDead() +{ + return (clientDead); +} + +void +updateClient() +{ + int i; + + for (i = 0; i < MAXPLAYER; i++) + { + mustUpdate[i] = 0; + } + updateShips(); +#ifdef SHORT_PACKETS + if (send_short) + { + short_updateTorps(); + } + else +#endif + { + updateTorps(); + updateTorpInfos(); + } + + if (weaponsallowed[WP_MISSILE] || + weaponsallowed[WP_FIGHTER]) + updateMissiles(); + updateThingies(); + sendMissileNum(me->p_ship.s_missilestored); + updatePlasmas(); + updateStatus(); + updateSelf(); + updatePhasers(); + updatePlanets(); + updateTerrain(); /* for galaxy reset */ + updateMessages(); + updateWarnings(); /* warning.c */ + + /* + * these checks are here to make sure we don't ping from the updateClient + * call in death(). The reason is that savestats() can take > 100ms, + * invalidating the next ping lag calc + */ + /* Also, don't ping while in verification stage */ + + if (ping + && (repCount % efticks(5 * configvals->ping_period) == 0) + && me->p_status != PDEAD + && me->p_status != POUTFIT + /* && me->p_status != PTQUEUE */ +#ifdef AUTHORIZE + && testtime <= 0 +#endif + ) + sendClientPing(); /* ping.c */ + + if (buffersEmpty()) + { + /* We sent nothing! We better send something to wake him */ + sendClientPacket((struct player_spacket *) & clientSelf); + } + flushSockBuf(); + repCount++; +} + +void +briefUpdateClient() +{ + updateMessages(); + updateMOTD(); + updateWarnings(); + + flushSockBuf(); + repCount++; +} + +void +updateStatus() +{ + if (repCount % efticks(75) == 0 && + ((ntohl(clientStatus2.timeprod) != status->timeprod) || + (clientStatus2.tourn != status->tourn))) + { + clientStatus2.type = SP_STATUS2; + clientStatus2.tourn = status->tourn; + clientStatus2.dooshes = htonl(status->dooshes); + clientStatus2.armsbomb = htonl(status->armsbomb); + clientStatus2.resbomb = htonl(status->resbomb); + clientStatus2.planets = htonl(status->planets); + clientStatus2.kills = htonl(status->kills); + clientStatus2.losses = htonl(status->losses); + clientStatus2.sbkills = htonl(status->sbkills); + clientStatus2.sblosses = htonl(status->sblosses); + clientStatus2.sbtime = htonl(status->sbtime); + clientStatus2.wbkills = htonl(status->wbkills); + clientStatus2.wblosses = htonl(status->wblosses); + clientStatus2.wbtime = htonl(status->wbtime); + clientStatus2.jsplanets = htonl(status->jsplanets); + clientStatus2.jstime = htonl(status->jstime); + clientStatus2.time = htonl(status->time); + clientStatus2.timeprod = htonl(status->timeprod); + sendClientPacket((struct player_spacket *) & clientStatus2); + } +} + +struct player * +maybe_watching(p) + struct player *p; +{ + struct player *tg = &players[me->p_playerl]; + return (p == me + && me->p_status == POBSERVE + && (me->p_flags & PFPLOCK) + && (me->p_teamspy & tg->p_team) + && tg->p_spyable) ? + tg : p; +} + +struct planet * +maybe_watching_planet() +{ + return (me->p_status == POBSERVE && (me->p_flags & PFPLLOCK)) ? + &planets[me->p_planet] : 0; +} + +void +updateSelf() +{ + struct player *watched = maybe_watching(me); + int armies = maybe_watching_planet() + ? maybe_watching_planet()->pl_armies + : watched->p_armies; + int damage; + + damage = watched->p_damage + + shipvals[watched->p_ship.s_type].s_maxdamage + - watched->p_ship.s_maxdamage; + + if (ntohl(clientSelf.fuel) != watched->p_fuel || + ntohl(clientSelf.shield) != watched->p_shield || + ntohl(clientSelf.damage) != damage || + ntohs(clientSelf.etemp) != watched->p_etemp || + ntohs(clientSelf.wtemp) != watched->p_wtemp || + ntohl(clientSelf.flags) != watched->p_flags || + clientSelf.armies != armies || + clientSelf.swar != watched->p_swar || + ntohs(clientSelf.whydead) != watched->p_whydead || + ntohs(clientSelf.whodead) != watched->p_whodead || + clientSelf.pnum != me->p_no) + { + + /* we want to send it, but how? */ + clientSelf.type = SP_YOU; + + if (commMode == COMM_UDP) + { + if (ntohl(clientSelf.flags) != watched->p_flags || + clientSelf.armies != armies || + clientSelf.swar != watched->p_swar) + { + clientSelf.type = SP_YOU | 0x40; /* mark as semi-critical */ + } + if (ntohs(clientSelf.whydead) != watched->p_whydead || + ntohs(clientSelf.whodead) != watched->p_whodead || + clientSelf.pnum != me->p_no) + { + clientSelf.type = SP_YOU | 0x80; /* mark as critical */ + } + } + clientSelf.pnum = me->p_no; + clientSelf.flags = htonl(watched->p_flags); + clientSelf.swar = watched->p_swar; + clientSelf.hostile = watched->p_hostile; + clientSelf.armies = armies; + clientSelf.shield = htonl(watched->p_shield); + clientSelf.fuel = htonl(watched->p_fuel); + clientSelf.etemp = htons(watched->p_etemp); + clientSelf.wtemp = htons(watched->p_wtemp); + clientSelf.whydead = htons(watched->p_whydead); + clientSelf.whodead = htons(watched->p_whodead); + clientSelf.damage = htonl(damage); + /* ATM - visible tractor */ + clientSelf.tractor = (char) watched->p_tractor | 0x40; + + clientSelf.pad2 = (unsigned char) (status->clock & 0xFF); + clientSelf.pad3 = (unsigned char) ((status->clock & 0xFF00) >> 8); + sendClientPacket((struct player_spacket *) & clientSelf); + } +} + +extern int ignored[]; + +void +updateShips() +{ + register int i; + register struct player *pl; + register struct plyr_info_spacket *cpli; + register struct player_spacket *cpl; + register struct kills_spacket *kills; + register struct flags_spacket *flags; + register struct pstatus_spacket *pstatus; + register struct plyr_login_spacket *login; + register struct hostile_spacket *hostile; +#if 0 + struct stats_spacket ms_stats; +#endif + register struct stats_spacket2 *stats; + int update; + int x, y; + /* + * #define FLAGMASK + * (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFD + * OCK|PFTRACT|PFPRESS|PFDOCKOK) atm mask + */ + + /* + * #define FLAGMASK + * (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFD + * OCK|PFTRACT|PFPRESS|PFDOCKOK) aieee, too much. 7/27/91 TC + */ + +#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) +#define INVISOMASK (PFCLOAK|PFROBOT|PFPRACTR|PFDOCKOK) + + /* Please excuse the ugliness of this loop declaration */ + for (i = 0, pl = players, cpli = clientPlayersInfo, cpl = clientPlayers, kills = clientKills, flags = clientFlags, pstatus = clientPStatus, login = clientLogin, hostile = clientHostile, stats = clientStats2; + i < MAXPLAYER; + i++, pl++, cpli++, cpl++, kills++, flags++, pstatus++, login++, hostile++, stats++) + { + update = 0; + if (strcmp(pl->p_name, login->name) != 0 || + pl->p_stats.st_rank != login->rank || + strcmp(pl->p_monitor, login->monitor) != 0) + { + strncpy(login->name, pl->p_name, 15); + strncpy(login->monitor, pl->p_monitor, 15); + strncpy(login->login, pl->p_login, 15); + login->name[15] = 0; + login->monitor[15] = 0; + login->login[15] = 0; + login->type = SP_PL_LOGIN; + login->pnum = i; + login->rank = pl->p_stats.st_rank; + sendClientPacket((struct player_spacket *) login); + } + if ((pl != me && (pl->p_swar & me->p_team) != hostile->war) || + (pl != me && (pl->p_hostile & me->p_team) != hostile->hostile) || + (pl == me && pl->p_swar != hostile->war) || + (pl == me && pl->p_hostile != hostile->hostile)) + { + hostile->type = SP_HOSTILE; + if (pl == me) + { + hostile->war = pl->p_swar; + hostile->hostile = pl->p_hostile; + } + else + { + hostile->war = (pl->p_swar & me->p_team); + hostile->hostile = (pl->p_hostile & me->p_team); + } + hostile->pnum = i; + sendClientPacket((struct player_spacket *) hostile); + } + /* + * Send stat packets once per five updates. But, only send one. We will + * cycle through them all eventually. + */ + /* + * Also, update if status chages (i.e., entered game, died, tq'ed, etc) + */ + + if (pl->p_status != pstatus->status || + (repCount % (MAXPLAYER * efticks(5)) == i * efticks(5) && + (stats->di != htonl(pl->p_stats.st_di) || + stats->kills != htonl(pl->p_stats.st_tkills) || + stats->losses != htonl(pl->p_stats.st_tlosses) || + stats->armsbomb != htonl(pl->p_stats.st_tarmsbomb) || + stats->resbomb != htonl(pl->p_stats.st_tresbomb) || + stats->dooshes != htonl(pl->p_stats.st_tdooshes) || + stats->planets != htonl(pl->p_stats.st_tplanets) || + stats->sbkills != htonl(pl->p_stats.st_sbkills) || + stats->sblosses != htonl(pl->p_stats.st_sblosses) || + stats->wbkills != htonl(pl->p_stats.st_wbkills) || + stats->wblosses != htonl(pl->p_stats.st_wblosses) || + stats->jsplanets != htonl(pl->p_stats.st_jsplanets) || + stats->rank != htonl(pl->p_stats.st_rank) || + stats->royal != htonl(pl->p_stats.st_royal)))) + { + + stats->genocides = htonl(pl->p_stats.st_genocides); + stats->maxkills = htonl((int) (pl->p_stats.st_tmaxkills * 100)); + stats->di = htonl((int) (pl->p_stats.st_di * 100)); + stats->kills = htonl(pl->p_stats.st_tkills); + stats->losses = htonl(pl->p_stats.st_tlosses); + stats->armsbomb = htonl(pl->p_stats.st_tarmsbomb); + stats->resbomb = htonl(pl->p_stats.st_tresbomb); + stats->dooshes = htonl(pl->p_stats.st_tdooshes); + stats->planets = htonl(pl->p_stats.st_tplanets); + stats->tticks = htonl(pl->p_stats.st_tticks); + stats->sbkills = htonl(pl->p_stats.st_sbkills); + stats->sblosses = htonl(pl->p_stats.st_sblosses); + stats->sbticks = htonl(pl->p_stats.st_sbticks); + stats->sbmaxkills = htonl((int) (pl->p_stats.st_sbmaxkills * 100)); + stats->wbkills = htonl(pl->p_stats.st_wbkills); + stats->wblosses = htonl(pl->p_stats.st_wblosses); + stats->wbticks = htonl(pl->p_stats.st_wbticks); + stats->wbmaxkills = htonl((int) (pl->p_stats.st_wbmaxkills * 100)); + stats->jsplanets = htonl(pl->p_stats.st_jsplanets); + stats->jsticks = htonl(pl->p_stats.st_jsticks); + stats->rank = htonl(pl->p_stats.st_rank); + stats->royal = htonl(pl->p_stats.st_royal); + stats->type = SP_STATS2; + stats->pnum = i; + /* if (blk_metaserver == 0) */ + sendClientPacket((struct player_spacket *) stats); +#if 0 + else + { + ms_stats.type = SP_STATS; + ms_stats.pnum = i; + ms_stats.tkills = htonl(pl->p_stats.st_tkills); + ms_stats.tlosses = htonl(pl->p_stats.st_tlosses); + ms_stats.kills = htonl(1); + ms_stats.losses = htonl(1); + ms_stats.tticks = htonl(pl->p_stats.st_tticks); + ms_stats.tplanets = htonl(pl->p_stats.st_tplanets); + ms_stats.tarmies = htonl(pl->p_stats.st_tarmsbomb); + ms_stats.sbkills = htonl(pl->p_stats.st_sbkills); + ms_stats.sblosses = htonl(pl->p_stats.st_sblosses); + ms_stats.armies = htonl(1); + ms_stats.planets = htonl(1); + ms_stats.maxkills = htonl((long) (pl->p_stats.st_tmaxkills * 100)); + ms_stats.sbmaxkills = htonl((long) (pl->p_stats.st_sbmaxkills * 100)); + sendClientPacket((struct player_spacket *) & ms_stats); + } +#endif + } + if (maybe_watching(pl)->p_ship.s_type != cpli->shiptype || + pl->p_team != cpli->team) + { + cpli->type = SP_PLAYER_INFO; + cpli->pnum = i; + cpli->shiptype = maybe_watching(pl)->p_ship.s_type; + cpli->team = pl->p_team; + sendClientPacket((struct player_spacket *) cpli); + /* + * if (!blk_flag) cpli->shiptype=pl->p_ship.s_type; + */ + } + if (kills->kills != htonl((int) (maybe_watching(pl)->p_kills * 100))) + { + kills->type = SP_KILLS; + kills->pnum = i; + kills->kills = htonl((int) (maybe_watching(pl)->p_kills * 100)); + sendClientPacket((struct player_spacket *) kills); + } + { + int plstat = pl->p_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && pl->p_team != me->p_team) + plstat = PFREE; /* enemies are invisible when the game is + * paused */ +#endif + + if (pstatus->status != plstat) + { + /* + * We update the location of people whose status has changed. (like + * if they just re-entered...) + */ + update = 1; + pstatus->type = SP_PSTATUS; + pstatus->pnum = i; + pstatus->status = plstat; + if (pl->p_status == PFREE) + { + /* + * I think this will turn off ignores for players that leave. + * 7/24/91 TC + */ + ignored[i] = 0; + } + sendClientPacket((struct player_spacket *) pstatus); + } + } + + /* Used to send flags here, see below 8/7/91 TC */ + + if (!configvals->hiddenenemy || pl->p_team == me->p_team || + (maybe_watching(pl)->p_flags & PFSEEN) || (status->tourn == 0) || + (maybe_watching(pl)->p_flags & PFROBOT)) + { /* a bot never has its PFSEEN bit set */ + + x = maybe_watching(pl)->p_x; + y = maybe_watching(pl)->p_y; + if (me != pl && flags->flags != + htonl(FLAGMASK & maybe_watching(pl)->p_flags)) + { + flags->type = SP_FLAGS; + flags->pnum = i; + flags->flags = htonl(FLAGMASK & maybe_watching(pl)->p_flags); + flags->tractor = (char) maybe_watching(pl)->p_tractor | 0x40; /* ATM - visible tractor */ + sendClientPacket((struct player_spacket *) flags); + } + } + else + { + /* A hack to make him inviso */ + x = -100000; + y = -100000; + + /* reduce flag info if he's inviso 8/7/91 TC */ + + if (me != pl && flags->flags != htonl(INVISOMASK & pl->p_flags)) + { + flags->type = SP_FLAGS; + flags->pnum = i; + flags->flags = htonl(INVISOMASK & pl->p_flags); + sendClientPacket((struct player_spacket *) flags); + } + } + if (x != ntohl(cpl->x) || y != ntohl(cpl->y) || + maybe_watching(pl)->p_dir != cpl->dir || + maybe_watching(pl)->p_speed != cpl->speed) + { + /* + * We update the player if: 1) haven't updated him for 9 intervals. 2) + * he is on the screen 3) he was on the screen recently. + */ + if (!update && repCount % efticks(9) != 0 && + (ntohl(cpl->x) < me->p_x - SCALE * WINSIDE / 2 || + ntohl(cpl->x) > me->p_x + SCALE * WINSIDE / 2 || + ntohl(cpl->y) > me->p_y + SCALE * WINSIDE / 2 || + ntohl(cpl->y) < me->p_y - SCALE * WINSIDE / 2) && + (y > me->p_y + SCALE * WINSIDE / 2 || + x > me->p_x + SCALE * WINSIDE / 2 || + x < me->p_x - SCALE * WINSIDE / 2 || + y < me->p_y - SCALE * WINSIDE / 2)) + continue; + /* + * If the guy is cloaked, give information only occasionally, and make + * it slightly inaccurate. Also, we don't give a direction. The client + * has no reason to know. + */ + if ((pl->p_flags & PFCLOAK) && + (pl->p_cloakphase == (CLOAK_PHASES - 1)) && + (maybe_watching(me) != pl) && !mustUpdate[i]) + { + if (repCount % efticks(9) != 0) + continue; + cpl->type = SP_PLAYER; + cpl->pnum = i; + cpl->x = htonl(x + (lrand48() % 2000) - 1000); + cpl->y = htonl(y + (lrand48() % 2000) - 1000); + sendClientPacket(cpl); + continue; + } + cpl->type = SP_PLAYER; + cpl->pnum = i; + cpl->x = htonl(x); + cpl->y = htonl(y); + cpl->speed = maybe_watching(pl)->p_speed; + cpl->dir = maybe_watching(pl)->p_dir; + sendClientPacket(cpl); + } + } +} + +void +updateTorpInfos() +{ + register struct torp *torp; + register int i; + register struct torp_info_spacket *tpi; + + for (i = 0, torp = torps, tpi = clientTorpsInfo; + i < MAXPLAYER * MAXTORP; + i++, torp++, tpi++) + { + if (torp->t_owner == me->p_no) + { + if (torp->t_war != tpi->war || + torp->t_status != tpi->status) + { + tpi->type = SP_TORP_INFO; + tpi->war = torp->t_war; + tpi->status = torp->t_status; + tpi->tnum = htons(i); + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* Someone else's torp... */ + if (torp->t_y > me->p_y + SCALE * WINSIDE / 2 || + torp->t_x > me->p_x + SCALE * WINSIDE / 2 || + torp->t_x < me->p_x - SCALE * WINSIDE / 2 || + torp->t_y < me->p_y - SCALE * WINSIDE / 2 || + torp->t_status == TFREE) + { + if (torp->t_status == TFREE && tpi->status == TEXPLODE) + { + tpi->status = TFREE; + continue; + } + if (tpi->status != TFREE) + { + tpi->status = TFREE; + tpi->tnum = htons(i); + tpi->type = SP_TORP_INFO; + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* in view */ + enum torp_status_e tstatus = torp->t_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused + && players[torp->t_owner].p_team != me->p_team) + tstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + if (tstatus != tpi->status || + (torp->t_war & me->p_team) != tpi->war) + { + /* Let the client fade away the explosion on its own */ + tpi->war = torp->t_war & me->p_team; + tpi->type = SP_TORP_INFO; + tpi->tnum = htons(i); + tpi->status = tstatus; + sendClientPacket((struct player_spacket *) tpi); + } + } + } + } +} + + + +void +updateTorps() +{ + register struct torp *torp; + register int i; + register struct torp_spacket *tp; + + for (i = 0, torp = torps, tp = clientTorps; + i < MAXPLAYER * MAXTORP; + i++, torp++, tp++) + { + if (torp->t_owner == me->p_no) + { + + if (tp->x != htonl(torp->t_x) || + tp->y != htonl(torp->t_y)) + { + tp->type = SP_TORP; + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + tp->dir = torp->t_dir; + tp->tnum = htons(i); + sendClientPacket((struct player_spacket *) tp); + } + } + else + { /* Someone else's torp... */ + if (torp->t_y > me->p_y + SCALE * WINSIDE / 2 || + torp->t_x > me->p_x + SCALE * WINSIDE / 2 || + torp->t_x < me->p_x - SCALE * WINSIDE / 2 || + torp->t_y < me->p_y - SCALE * WINSIDE / 2 || + torp->t_status == TFREE) + { + /* do nothing */ + } + else + { /* in view */ + enum torp_status_e tstatus = torp->t_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused + && players[torp->t_owner].p_team != me->p_team) + tstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + if (tstatus == TFREE) + continue; /* no need to transmit position */ + + if (tp->x != htonl(torp->t_x) || + tp->y != htonl(torp->t_y)) + { + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + tp->dir = torp->t_dir; + tp->tnum = htons(i); + tp->type = SP_TORP; + sendClientPacket((struct player_spacket *) tp); + } + } + } + } +} + +#ifdef SHORT_PACKETS + +#define NIBBLE() *(*data)++ = (torp->t_war & 0xf) | (torp->t_status << 4) + +int +encode_torp_status(torp, pnum, data, tpi, tp, mustsend) + struct torp *torp; + int pnum; + char **data; + struct torp_info_spacket *tpi; + struct torp_spacket *tp; + int *mustsend; +{ + if (pnum != me->p_no) + { + int dx, dy; + int i = SCALE * WINSIDE / 2; + dx = me->p_x - torp->t_x; + dy = me->p_y - torp->t_y; + if (dx < -i || dx > i || dy < -i || dy > i || torp->t_status == TFREE) + { + if (torp->t_status == TFREE && tpi->status == TEXPLODE) + tpi->status = TFREE; + else if (tpi->status != TFREE) + { + tpi->status = TFREE; + *mustsend = 1; + } + return 0; + } + } + + if (torp->t_war != tpi->war) + { + tpi->war = torp->t_war; + tpi->status = torp->t_status; + NIBBLE(); + return 1; + } + else if (torp->t_status != tpi->status) + { + switch (torp->t_status) + { + case TFREE: + { + int rval = 0; + if (tpi->status == TEXPLODE) + { + NIBBLE(); + rval = 1; + } + else + *mustsend = 1; + tpi->status = torp->t_status; + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + return rval; + } + break; + case TMOVE: + case TSTRAIGHT: + tpi->status = torp->t_status; + break; + default: + NIBBLE(); + tpi->status = torp->t_status; + return 1; + break; + } + } + return 0; +} + +#define TORP_INVISIBLE(tstatus) ( \ + (tstatus)== TFREE || \ + (tstatus) == TOFF || \ + (tstatus) == TLAND) + +int +encode_torp_position(torp, pnum, data, shift, cache) + struct torp *torp; + int pnum; + char **data; + int *shift; + struct torp_spacket *cache; +{ + int x, y; + + if (htonl(torp->t_x) == cache->x && + htonl(torp->t_y) == cache->y) + return 0; + + cache->x = htonl(torp->t_x); + cache->y = htonl(torp->t_y); + + if (TORP_INVISIBLE(torp->t_status) +#ifdef LEAGUE_SUPPORT + || (status2->paused && + players[pnum].p_team != me->p_team) +#endif + ) + return 0; + + x = torp->t_x / SCALE - me->p_x / SCALE + WINSIDE / 2; + y = torp->t_y / SCALE - me->p_y / SCALE + WINSIDE / 2; + + if (x < 0 || x >= WINSIDE || + y < 0 || y >= WINSIDE) + { + if (pnum != me->p_no) + return 0; + x = y = 501; + } + + **data |= x << *shift; + *(++(*data)) = (0x1ff & x) >> (8 - *shift); + (*shift)++; + **data |= y << *shift; + *(++(*data)) = (0x1ff & y) >> (8 - *shift); + (*shift)++; + if (*shift == 8) + { + *shift = 0; + *(++(*data)) = 0; + } + return 1; +} + +void +short_updateTorps() +{ + register int i; + + for (i = 0; i <= (MAXPLAYER * MAXTORP - 1) / 8; i++) + { + struct torp *torp = &torps[i * 8]; + int j; + char packet[2 /* packet type and player number */ + + 1 /* torp mask */ + + 1 /* torp info mask */ + + 18 /* 2*8 9-bit numbers */ + + 8 /* 8 torp info bytes */ + ]; + char *data = packet + 4; + char info[8]; + char *ip = info; + int shift = 0; + int torppos_mask = 0; + int torpinfo_mask = 0; + int mustsend; + + /* encode screen x and y coords */ + data[0] = 0; +#define TIDX (j+i*8) +#define PNUM ((int)((j+i*8)/MAXTORP)) + for (j = 0; j < 8 && TIDX < MAXPLAYER * MAXTORP; j++) + { + torpinfo_mask |= encode_torp_status + (&torp[j], PNUM, &ip, &clientTorpsInfo[TIDX], &clientTorps[TIDX], &mustsend) << j; + torppos_mask |= encode_torp_position + (&torp[j], PNUM, &data, &shift, &clientTorps[TIDX]) << j; + } + + /* + * if (!torppos_mask) continue; + */ + + if (torpinfo_mask) + { + if (shift) + data++; + for (j = 0; j < 8 && &info[j] < ip; j++) + data[j] = info[j]; + packet[0] = SP_S_TORP_INFO; + packet[1] = torppos_mask; + packet[2] = i; + packet[3] = torpinfo_mask; + sendClientSizedPacket(packet, (data - packet + j)); + } + else if (torppos_mask == 0xff) + { + /* what a disgusting hack */ + packet[2] = SP_S_8_TORP; + packet[3] = i; + sendClientSizedPacket(packet + 2, 20); + } + else if (mustsend || torppos_mask != 0) + { + packet[1] = SP_S_TORP; + packet[2] = torppos_mask & 0xff; + packet[3] = i; + sendClientSizedPacket(packet + 1, (data - (packet + 1) + (shift != 0))); + } + } +#undef PNUM +#undef TIDX +} + + +#endif + + +void +updateMissiles() +{ + register struct missile *missile; + register int i; + register struct thingy_info_spacket *dpi; + register struct thingy_spacket *dp; + + for (i = 0, missile = missiles, dpi = clientThingysInfo, dp = clientThingys; + i < MAXPLAYER * NPTHINGIES; + i++, missile++, dpi++, dp++) + { + enum torp_status_e msstatus = missile->ms_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && + players[missile->ms_owner].p_team != me->p_team) + msstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + switch (msstatus) + { + case TFREE: + case TLAND: + case TOFF: + dpi->shape = htons(SHP_BLANK); + break; + case TMOVE: + case TRETURN: + case TSTRAIGHT: + dpi->shape = htons((missile->ms_type == FIGHTERTHINGY) + ? SHP_FIGHTER + : SHP_MISSILE); + break; + case TEXPLODE: + case TDET: + dpi->shape = htons(SHP_PBOOM); + break; + } + + dpi->type = SP_THINGY_INFO; + dpi->tnum = htons(i); + + dp->type = SP_THINGY; + dp->tnum = htons(i); + dp->dir = missile->ms_dir; + + if (missile->ms_owner == me->p_no) + { + if (missile->ms_war != dpi->war || + msstatus != clientThingyStatus[i]) + { + dpi->war = missile->ms_war; + clientThingyStatus[i] = msstatus; + sendClientPacket((struct player_spacket *) dpi); + } + if (dp->x != htonl(missile->ms_x) || + dp->y != htonl(missile->ms_y)) + { + dp->x = htonl(missile->ms_x); + dp->y = htonl(missile->ms_y); + /* printf("missile at %d,%d\n", dp->x, dp->y); */ + sendClientPacket((struct player_spacket *) dp); + } + } + else + { /* Someone else's missile... */ + if (msstatus == TFREE || + missile->ms_y > me->p_y + SCALE * WINSIDE / 2 || + missile->ms_x > me->p_x + SCALE * WINSIDE / 2 || + missile->ms_x < me->p_x - SCALE * WINSIDE / 2 || + missile->ms_y < me->p_y - SCALE * WINSIDE / 2) + { + if (msstatus == TFREE && clientThingyStatus[i] == TEXPLODE) + { + clientThingyStatus[i] = TFREE; + continue; + } + if (clientThingyStatus[i] != TFREE) + { + clientThingyStatus[i] = TFREE; + dpi->shape = htons(SHP_BLANK); + sendClientPacket((struct player_spacket *) dpi); + } + } + else + { /* in view */ + if (dp->x != htonl(missile->ms_x) || + dp->y != htonl(missile->ms_y)) + { + dp->x = htonl(missile->ms_x); + dp->y = htonl(missile->ms_y); + sendClientPacket((struct player_spacket *) dp); + } + if (msstatus != clientThingyStatus[i] || + (missile->ms_war & me->p_team) != dpi->war) + { + /* Let the client fade away the explosion on its own */ + dpi->war = missile->ms_war & me->p_team; + clientThingyStatus[i] = msstatus; + sendClientPacket((struct player_spacket *) dpi); + } + } + } + } +} + +static void +fill_thingy_info_packet(thing, packet) + struct thingy *thing; + struct thingy_info_spacket *packet; +{ + switch (thing->type) + { + case TT_NONE: + packet->war = 0; + packet->shape = htons(SHP_BLANK); + packet->owner = 0; + break; + case TT_WARP_BEACON: + packet->war = 0; + if (thing->u.wbeacon.owner == me->p_team) + { + packet->shape = htons(SHP_WARP_BEACON); + packet->owner = htons(thing->u.wbeacon.owner); + } + else + { + packet->shape = htons(SHP_BLANK); + packet->owner = 0; + } + break; + default: + printf("Unknown thingy type: %d\n", (int) thing->type); + break; + } +} + +static void +fill_thingy_packet(thing, packet) + struct thingy *thing; + struct thingy_spacket *packet; +{ + switch (thing->type) + { + case TT_NONE: + packet->dir = 0; + packet->x = packet->y = htonl(0); + break; + case TT_WARP_BEACON: + packet->dir = 0; + if (thing->u.wbeacon.owner == me->p_team) + { + packet->x = htonl(thing->u.wbeacon.x); + packet->y = htonl(thing->u.wbeacon.y); + } + else + { + packet->x = packet->y = htonl(0); + } + break; + default: + printf("Unknown thingy type: %d\n", (int) thing->type); + break; + } +} + +void +updateThingies() +{ + struct thingy *thing; + struct thingy_info_spacket *tip; + struct thingy_spacket *tp; + int i; + + for (i = 0; i < NGTHINGIES; i++) + { + struct thingy_info_spacket ti1; + struct thingy_spacket t2; + + thing = &thingies[i]; + tip = &clientThingysInfo[i + MAXPLAYER * NPTHINGIES]; + tp = &clientThingys[i + MAXPLAYER * NPTHINGIES]; + + ti1.type = SP_THINGY_INFO; + ti1.tnum = htons(i + MAXPLAYER * NPTHINGIES); + fill_thingy_info_packet(thing, &ti1); + + if (0 != memcmp((char *) tip, (char *) &ti1, sizeof(ti1))) + { + memcpy(tip, &ti1, sizeof(ti1)); + sendClientPacket((struct player_spacket *) tip); + } + + if (tip->shape != htons(SHP_BLANK)) + { + t2.type = SP_THINGY; + t2.tnum = htons(i + MAXPLAYER * NPTHINGIES); + fill_thingy_packet(thing, &t2); + + if (0 != memcmp(tp, &t2, sizeof(t2))) + { + memcpy(tp, &t2, sizeof(t2)); + sendClientPacket((struct player_spacket *) tp); + } + } + } + +} + +void +updatePlasmas() +{ + register struct plasmatorp *torp; + register int i; + register struct plasma_info_spacket *tpi; + register struct plasma_spacket *tp; + + for (i = 0, torp = plasmatorps, tpi = clientPlasmasInfo, tp = clientPlasmas; + i < MAXPLAYER * MAXPLASMA; + i++, torp++, tpi++, tp++) + { + if (torp->pt_owner == me->p_no) + { + if (torp->pt_war != tpi->war || + torp->pt_status != tpi->status) + { + tpi->type = SP_PLASMA_INFO; + tpi->war = torp->pt_war; + tpi->status = torp->pt_status; + tpi->pnum = htons(i); + sendClientPacket((struct player_spacket *) tpi); + } + if (tp->x != htonl(torp->pt_x) || + tp->y != htonl(torp->pt_y)) + { + tp->type = SP_PLASMA; + tp->x = htonl(torp->pt_x); + tp->y = htonl(torp->pt_y); + tp->pnum = htons(i); + sendClientPacket((struct player_spacket *) tp); + } + } + else + { /* Someone else's torp... */ + enum torp_status_e ptstatus = torp->pt_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && + players[torp->pt_owner].p_team != me->p_team) + ptstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + if (torp->pt_y > me->p_y + SCALE * WINSIDE / 2 || + torp->pt_x > me->p_x + SCALE * WINSIDE / 2 || + torp->pt_x < me->p_x - SCALE * WINSIDE / 2 || + torp->pt_y < me->p_y - SCALE * WINSIDE / 2 || + ptstatus == PTFREE) + { + if (ptstatus == PTFREE && tpi->status == PTEXPLODE) + { + tpi->status = PTFREE; + continue; + } + if (tpi->status != PTFREE) + { + tpi->status = PTFREE; + tpi->pnum = htons(i); + tpi->type = SP_PLASMA_INFO; + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* in view */ + /* Send torp (we assume it moved) */ + tp->x = htonl(torp->pt_x); + tp->y = htonl(torp->pt_y); + tp->pnum = htons(i); + tp->type = SP_PLASMA; + sendClientPacket((struct player_spacket *) tp); + if (ptstatus != tpi->status || + (torp->pt_war & me->p_team) != tpi->war) + { + tpi->war = torp->pt_war & me->p_team; + tpi->type = SP_PLASMA_INFO; + tpi->pnum = htons(i); + tpi->status = ptstatus; + sendClientPacket((struct player_spacket *) tpi); + } + } + } + } +} + +void +updatePhasers() +{ + register int i; + register struct phaser_spacket *ph; + register struct phaser *phase; + register struct player *pl; + + for (i = 0, ph = clientPhasers, phase = phasers, pl = players; + i < MAXPLAYER; i++, ph++, phase++, pl++) + { + if (pl->p_y > me->p_y + SCALE * WINSIDE / 2 || + pl->p_x > me->p_x + SCALE * WINSIDE / 2 || + pl->p_x < me->p_x - SCALE * WINSIDE / 2 || + pl->p_y < me->p_y - SCALE * WINSIDE / 2) + { + if (ph->status != PHFREE) + { + ph->pnum = i; + ph->type = SP_PHASER; + ph->status = PHFREE; + sendClientPacket((struct player_spacket *) ph); + } + } + else + { + if (phase->ph_status == PHHIT) + { + mustUpdate[phase->ph_target] = 1; + } + if (ph->status != phase->ph_status || + ph->dir != phase->ph_dir || + ph->target != htonl(phase->ph_target)) + { + ph->pnum = i; + ph->type = SP_PHASER; + ph->status = phase->ph_status; + ph->dir = phase->ph_dir; + ph->x = htonl(phase->ph_x); + ph->y = htonl(phase->ph_y); + ph->target = htonl(phase->ph_target); + sendClientPacket((struct player_spacket *) ph); + } + } + } +} + + +#define PLFLAGMASK (PLRESMASK|PLATMASK|PLSURMASK|PLPARADISE|PLTYPEMASK) + +void +updatePlanets() +{ + register int i; + register struct planet *plan; + register struct planet_loc_spacket *pll; +#if 0 + register struct planet_spacket *mspl; +#endif + register struct planet_spacket2 *pl; + int dx, dy; + int d2x, d2y; + char *name; + + for (i = 0, pl = clientPlanets2, plan = planets, pll = clientPlanetLocs; + i < MAXPLANETS; + i++, pl++, plan++, pll++) + { + /* + * Send him info about him not having info if he doesn't but thinks he + * does. Also send him info on every fifth cycle if the planet needs to + * be redrawn. + */ + if (((plan->pl_hinfo & me->p_team) == 0) && (pl->info & me->p_team)) + { + pl->type = SP_PLANET2; + pl->pnum = i; + pl->info = 0; + pl->flags = PLPARADISE; + sendClientPacket((struct player_spacket *) pl); + } + else + { + struct teaminfo temp, *ptr; + if (configvals->durablescouting) + { + temp.owner = plan->pl_owner; + temp.armies = plan->pl_armies; + temp.flags = plan->pl_flags; + temp.timestamp = status->clock; + ptr = &temp; + } + else + ptr = &plan->pl_tinfo[me->p_team]; + + if (pl->info != plan->pl_hinfo || + pl->armies != htonl(ptr->armies) || + pl->owner != ptr->owner || + pl->flags != htonl(ptr->flags & PLFLAGMASK) + || ((pl->timestamp != htonl(ptr->timestamp)) + && (me->p_team != plan->pl_owner))) + { + pl->type = SP_PLANET2; + pl->pnum = (char) i; + pl->info = (char) plan->pl_hinfo; + pl->flags = htonl(ptr->flags & PLFLAGMASK); + pl->armies = htonl(ptr->armies); + pl->owner = (char) ptr->owner; + pl->timestamp = htonl(ptr->timestamp); + sendClientPacket((struct player_spacket *) pl); + } + } + /* Assume that the planet only needs to be updated once... */ + + /* Odd, changes in pl_y not supported. 5/31/92 TC */ + + dx = ntohl(pll->x) - plan->pl_x; + if (dx < 0) + dx = -dx; + dy = ntohl(pll->y) - plan->pl_y; + if (dy < 0) + dy = -dy; + + d2x = plan->pl_x - me->p_x; + d2y = plan->pl_y - me->p_y; + if (d2x < 0) + d2x = -d2x; + if (d2y < 0) + d2y = -d2y; + + if (1 || plan->pl_hinfo & me->p_team) + name = plan->pl_name; + else + name = " "; + /* + * if ((pll->x != htonl(plan->pl_x)) || (pll->y != htonl(plan->pl_y))) { + */ + if (strcmp(pll->name, name) || + ((dx > 400 || dy > 400) || + ((dx >= 20 || dy >= 20) && (d2x < 10000 && d2y < 10000)))) + { + pll->x = htonl(plan->pl_x); + pll->y = htonl(plan->pl_y); + pll->pnum = i; + if (plan->pl_system == 0) + pll->pad2 = 255; + else + pll->pad2 = (char) stars[plan->pl_system]; + strcpy(pll->name, name); + pll->type = SP_PLANET_LOC; + sendClientPacket((struct player_spacket *) pll); + } + } +} + +void +updateMessages() +{ + int i; + struct message *cur; + struct mesg_spacket msg; + + for (i = msgCurrent; i != (mctl->mc_current + 1) % MAXMESSAGE; i = (i + 1) % MAXMESSAGE) + { + if (i == MAXMESSAGE) + i = 0; + cur = &messages[i]; + + if (cur->m_flags & MVALID && + (cur->m_flags & MALL || + (cur->m_flags & MTEAM && cur->m_recpt == me->p_team) || + (cur->m_flags & MINDIV && cur->m_recpt == me->p_no) || + (cur->m_flags & MGOD && cur->m_from == me->p_no))) + { + msg.type = SP_MESSAGE; + strncpy(msg.mesg, cur->m_data, 80); + msg.mesg[79] = '\0'; + msg.m_flags = cur->m_flags; + msg.m_recpt = cur->m_recpt; + msg.m_from = cur->m_from; + + if ((cur->m_from < 0) + || (cur->m_from > MAXPLAYER) + || (cur->m_flags & MGOD && cur->m_from == me->p_no) + || (cur->m_flags & MALL && !(ignored[cur->m_from] & MALL)) + || (cur->m_flags & MTEAM && !(ignored[cur->m_from] & MTEAM))) + sendClientPacket((struct player_spacket *) & msg); + else if (cur->m_flags & MINDIV) + { + + /* session stats now parsed here. parseQuery == true */ + /* means eat message 4/17/92 TC */ + + if (!parseQuery(&msg)) + if (ignored[cur->m_from] & MINDIV) + bounce("That player is currently ignoring you.", + cur->m_from); + else + sendClientPacket((struct player_spacket *) & msg); + } + } + msgCurrent = (msgCurrent + 1) % MAXMESSAGE; + } +} + +/* Asteroid/Nebulae socket code (5/16/95 rpg) */ + +#define DIM (MAX_GWIDTH/TGRID_GRANULARITY) + +void +updateTerrain() +{ + int i; + int j, maxfor; + int status; + int npkts; + struct terrain_packet2 tpkt; + struct terrain_info_packet2 tinfo_pkt; + unsigned long olen = DIM * DIM, dlen = DIM * DIM / 1000 + DIM * DIM + 13; +#if defined(T_DIAG) || defined(T_DIAG2) + char buf[80]; +#endif + unsigned char origBuf[DIM * DIM]; + unsigned char gzipBuf[DIM * DIM / 1000 + + DIM * DIM + 13]; + /* + * Don't ask me. The compression libs need (original size + 0.1% + 12 + * bytes). + */ + /* + * Note - this will have to be RADICALLY changed if alt1/alt2 are sent as + * well. + */ + + /* check to see if client can handle the terrain data first */ + if (F_terrain) + { + if (galaxyValid[me->p_no]) + return; + +#if defined(T_DIAG) || defined(T_DIAG2) + { + char buf[80]; + sprintf(buf, "pno: %d gIsense: %d", me->p_no, galaxyValid[me->p_no]); + pmessage(buf, 0, MALL, MSERVA); + } +#endif + galaxyValid[me->p_no] = 1; + /* Send initial packet. */ + tinfo_pkt.type = SP_TERRAIN_INFO2; + tinfo_pkt.xdim = htons(DIM); + tinfo_pkt.ydim = htons(DIM); + sendClientPacket((struct player_spacket *) & tinfo_pkt); + for (i = 0; i < DIM * DIM; i++) + { + origBuf[i] = terrain_grid[i].types; /* pack types field into + * array */ + } +#if defined(T_DIAG) || defined(T_DIAG2) + status = compress(gzipBuf, &dlen, origBuf, olen); + if (status != Z_OK) + { + pmessage("TERRAIN: Cannot gzip terrain grid.", 0, MALL, MSERVA); + return; + } + else + { + sprintf(buf, "TERRAIN: Original length %d, compressed length %d", DIM * DIM, dlen); + pmessage(buf, 0, MALL, MSERVA); + } +#else + compress(gzipBuf, &dlen, origBuf, olen); +#endif + npkts = (dlen >> LOG2NTERRAIN); + if (dlen & TERRAIN_MASK) + { + npkts++; /* require a partial packet */ + } + for (i = 1; i <= npkts; i++) + { + tpkt.type = SP_TERRAIN2; + tpkt.sequence = (unsigned char) i; + tpkt.total_pkts = (unsigned char) npkts; + if (i < npkts) + { + maxfor = tpkt.length = NTERRAIN; + } + else + { + maxfor = tpkt.length = (dlen & TERRAIN_MASK); + } + for (j = 0; j < maxfor; j++) + { + tpkt.terrain_type[j] = gzipBuf[((i - 1) << LOG2NTERRAIN) + j]; + } + /* ok, packet is filled in, send it */ +#ifdef T_DIAG2 + sprintf(buf, "Sending terrain packet %d of %d", tpkt.sequence, tpkt.total_pkts); + pmessage(buf, 0, MALL, MSERVA); +#endif + sendClientPacket((struct player_spacket *) & tpkt); + } + } +#ifdef FEATURE_DIAG + else + { + pmessage("Mis-timed terrain data (F_terrain = 0)!", 0, MALL, MSERVA); + } +#endif +} + +void +updateMOTD() +{ + static int spinner = 0; + + if (--spinner < 0) + { + static struct stat oldstat; + static int firsttime = 1; + + char *path; + struct stat newstat; + struct obvious_packet pkt; + + spinner = 10; + + if (!firsttime) + { + path = build_path(MOTD); + stat(path, &newstat); + if (newstat.st_ino == oldstat.st_ino && + newstat.st_mtime == oldstat.st_mtime) + return; + oldstat.st_ino = newstat.st_ino; + oldstat.st_mtime = newstat.st_mtime; + + pkt.type = SP_NEW_MOTD; + sendClientPacket((struct player_spacket *) & pkt); + } + else + { + sendMotd(); /* can't build_path before this */ + path = build_path(MOTD); + stat(path, &oldstat); + /* printf("%s: %d, %d\n", path, oldstat.st_ino, oldstat.st_mtime); */ + firsttime = 0; + } + } +} + +void +sendQueuePacket(pos) + short int pos; +{ + struct queue_spacket qPacket; + + qPacket.type = SP_QUEUE; + qPacket.pos = htons(pos); + sendClientPacket((struct player_spacket *) & qPacket); + flushSockBuf(); +} + +void +sendClientPacket(packet) + struct player_spacket *packet; +{ + sendClientSizedPacket(packet, -1); +} + +void +sendClientSizedPacket(packet, size) +/* Pick a random type for the packet */ + struct player_spacket *packet; + int size; +{ + int orig_type; + int issc; + static int oldStatus = POUTFIT; + +#if 0 + if (blk_metaserver) +#endif +#ifdef SHOW_PACKETS + { + FILE *logfile; + char *paths; + paths = build_path("logs/metaserver.log"); + logfile = fopen(paths, "a"); + if (logfile) + { + fprintf(logfile, "Sending packet type %d\n", (int) packet->type); + fclose(logfile); + } + + } +#endif + +#ifdef T_DIAG2 + if ((packet->type == SP_TERRAIN2) || (packet->type == SP_TERRAIN_INFO2)) + { + pmessage("Sending TERRAIN packet\n", 0, MALL, MSERVA); + } +#endif + + orig_type = packet->type; +#if 0 + packet->type &= ~(0x40 | 0x80); /* clear special flags */ +#else + packet->type &= (char) 0x3f; /* above doesn't work? 4/18/92 TC */ +#endif +#ifdef MAYBE + /* + * If we're dead, dying, or just born, we definitely want the transmission + * to get through (otherwise we can get stuck). I don't think this will be + * a problem for anybody, though it might hang for a bit if the TCP + * connection is bad. + */ + /* Okay, now I'm not so sure. Whatever. */ + if (oldStatus != PALIVE || (me != NULL && me->p_status != PALIVE)) + orig_type = packet->type | 0x80; /* pretend it's critical */ +#endif + + /* if we're not given the size, calculate it */ + if (size < 0) + { + if (size_of_spacket(packet) == 0) + { + printf("Attempt to send strange packet %d\n", packet->type); + return; + } + size = size_of_spacket(packet); + } + else + { + /* pad to 32-bits */ + size = ((size - 1) / 4 + 1) * 4; + } + + packetsSent[packet->type]++; + + + if (commMode == COMM_TCP + || (commMode == COMM_UDP && udpMode == MODE_TCP)) + { + switch (orig_type) + { + case SP_MOTD: + case SP_MOTD_PIC: + /* these can afford to be delayed */ + sendTCPdeferred((void *) packet, size); + break; + + default: + /* business as usual, TCP */ + sendTCPbuffered((void *) packet, size); + break; + } + } + else + { + /* + * do UDP stuff unless it's a "critical" packet (note that both kinds get + * a sequence number appended) (FIX) + */ + issc = 0; + switch (orig_type) + { + case SP_KILLS: + case SP_TORP_INFO: + case SP_THINGY_INFO: + case SP_PHASER: + case SP_PLASMA_INFO: + case SP_YOU | 0x40: /* ??? what is this? */ + case SP_STATUS: + case SP_STATUS2: + case SP_PLANET: + case SP_PLANET2: + case SP_FLAGS: + case SP_HOSTILE: + /* + * these are semi-critical; flag as semi-critical and fall through + */ + issc = 1; + + case SP_PLAYER: + case SP_TORP: +#ifdef SHORT_PACKETS + case SP_S_TORP: + case SP_S_8_TORP: +#endif + case SP_THINGY: + case SP_YOU: + case SP_PLASMA: + case SP_STATS: + case SP_STATS2: + /* case SP_SCAN: */ + case SP_PING: + case SP_UDP_REPLY: /* only reply when COMM_UDP is SWITCH_VERIFY */ + /* these are non-critical updates; send them via UDP */ + V_UDPDIAG(("Sending type %d\n", packet->type)); + packets_sent++; + sendUDPbuffered(issc, (void *) packet, size); + break; + + case SP_MOTD: + case SP_MOTD_PIC: + sendTCPdeferred((void *) packet, size); + break; + + default: + sendTCPbuffered((void *) packet, size); + break; + } + } + + if (me != NULL) + oldStatus = me->p_status; +} + +/* + * flushSockBuf, socketPause, socketWait were here + */ + +/* Find out if client has any requests */ +int +readFromClient() +{ + struct timeval timeout; + fd_set readfds, writefds; + int retval = 0; + + if (clientDead) + return (0); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + build_select_masks(&readfds, &writefds); + + if (select(32, &readfds, &writefds, (fd_set *) 0, &timeout) != 0) + { + /* Read info from the xtrek client */ + if (FD_ISSET(sock, &readfds)) + { + retval += doRead(sock); + } + if (udpSock >= 0 && FD_ISSET(udpSock, &readfds)) + { + V_UDPDIAG(("Activity on UDP socket\n")); + retval += doRead(udpSock); + } + if (retval == 0 && /* no other traffic */ + FD_ISSET(sock, &writefds)) + { + flushDeferred(); /* we have an eye in the packet hurricane */ + } + } + return (retval != 0); /* convert to 1/0 */ +} + +static int +input_allowed(packettype) + int packettype; +{ + switch (packettype) + { + case CP_MESSAGE: + case CP_SOCKET: + case CP_OPTIONS: + case CP_BYE: + case CP_UPDATES: + case CP_RESETSTATS: + case CP_RESERVED: + case CP_RSA_KEY: + case CP_ASK_MOTD: + case CP_PING_RESPONSE: + case CP_UDP_REQ: +#ifdef FEATURE + case CP_FEATURE: +#endif +#ifdef SHORT_PACKETS + case CP_S_MESSAGE: +#endif + return 1; + default: + if (!me) + return; + + if (me->p_status == PTQUEUE) + return (packettype == CP_OUTFIT + ); + else if (me->p_status == POBSERVE) + return (packettype == CP_QUIT + || packettype == CP_PLANLOCK + || packettype == CP_PLAYLOCK + || packettype == CP_SCAN + || packettype == CP_SEQUENCE /* whatever this is */ + ); + + if (inputMask >= 0 && inputMask != packettype) + return 0; + if (me == NULL) + return 1; + if (!(me->p_flags & (PFWAR | PFREFITTING))) + return 1; + + return 0; + } +} + +static int rsock; /* ping stuff */ + +/* ripped out of above routine */ +int +doRead(asock) + int asock; +{ + struct timeval timeout; + /* int readfds; */ + fd_set readfds; + char buf[BUFSIZ * 2]; + char *bufptr; + int size; + int count; + int temp; + + rsock = asock; /* need the socket in the ping handler + * routine */ + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + /* readfds = 1<<asock; */ + FD_ZERO(&readfds); + FD_SET(asock, &readfds); + /* Read info from the xtrek server */ + count = read(asock, buf, BUFSIZ * 2); + if (count <= 0) + { +#if DEBUG + /* (this happens when the client hits 'Q') */ + fprintf(stderr, "1) read() failed in doRead (%d, error %d)\n", + count, errno); + fprintf(stderr, "asock=%d, sock=%d\n", asock, sock); +#endif + if (asock == udpSock) + { + if (errno == ECONNREFUSED) + { + struct sockaddr_in addr; + + UDPDIAG(("Hiccup(%d)! Reconnecting\n", errno)); + addr.sin_addr.s_addr = remoteaddr; + addr.sin_port = htons(udpClientPort); + addr.sin_family = AF_INET; + if (connect(udpSock, (struct sockaddr *) & addr, sizeof(addr)) < 0) + { + perror("hiccup connect"); + UDPDIAG(("Unable to reconnect\n")); + /* and fall through to disconnect */ + } + else + { + UDPDIAG(("Reconnect successful\n")); + return (0); + } + } + UDPDIAG(("*** UDP disconnected (res=%d, err=%d)\n", + count, errno)); + printUdpInfo(); + closeUdpConn(); + commMode = COMM_TCP; + return (0); + } + clientDead = 1; + return (0); + } + bufptr = buf; + while (bufptr < buf + count) + { + if (*bufptr < 1 || + (unsigned char) *bufptr > NUM_PACKETS || + size_of_cpacket((void *) bufptr) == 0) + { + printf("Unknown packet type: %d, aborting...\n", *bufptr); + return (0); + } + size = size_of_cpacket(bufptr); + while (size > count + (buf - bufptr)) + { + /* + * We wait for up to twenty seconds for rest of packet. If we don't get + * it, we assume the client died. + */ + timeout.tv_sec = 20; + timeout.tv_usec = 0; + /* readfds=1<<asock; */ + FD_ZERO(&readfds); + FD_SET(asock, &readfds); + if (select(32, &readfds, 0, 0, &timeout) == 0) + { + logmessage("Died while waiting for packet..."); + fprintf(stderr, "1a) read() failed (%d, error %d)\n", + count, errno); + clientDead = 1; + return (0); + } + temp = read(asock, buf + count, size - (count + (buf - bufptr))); + if (temp <= 0) + { + if (errno != EINTR) + { + sprintf(buf, "Died in second read(), return=%d", temp); + logmessage(buf); + fprintf(stderr, "2) read() failed (%d, error %d)\n", + count, errno); + clientDead = 1; + return (0); + } + } + else + count += temp; + } + /* + * Check to see if the handler is there and the request is legal. The + * code is a little ugly, but it isn't too bad to worry about yet. + */ +#if 0 + { + FILE *logfile; + char *paths; + if (blk_metaserver) + { + paths = build_path("logs/metaserver.log"); + logfile = fopen(paths, "a"); + if (logfile) + { + fprintf(logfile, "Receiving packet type %d\n", (int) *bufptr); + fclose(logfile); + } + } + } +#endif + packetsReceived[(unsigned char) *bufptr]++; + + if (asock == udpSock) + packets_received++; + + if (handlers[(unsigned char) *bufptr].handler != NULL) + { + if (input_allowed(*bufptr)) + { + if (me && me->p_flags & PFSELFDEST + && *bufptr != CP_PING_RESPONSE) + { + me->p_flags &= ~PFSELFDEST; + warning("Self Destruct has been canceled"); + } + (*(handlers[(unsigned char) *bufptr].handler)) (bufptr); + } + /* Otherwise we ignore the request */ + } + else + { + printf("Handler for packet %d not installed...\n", *bufptr); + } + bufptr += size; + if (bufptr > buf + BUFSIZ) + { + memcpy(buf, buf + BUFSIZ, BUFSIZ); + if (count == BUFSIZ * 2) + { + /* readfds = 1<<asock; */ + FD_ZERO(&readfds); + FD_SET(asock, &readfds); + if (select(32, &readfds, 0, 0, &timeout)) + { + temp = read(asock, buf + BUFSIZ, BUFSIZ); + count = BUFSIZ + temp; + if (temp <= 0) + { + sprintf(buf, "Died in third read(), return=%d", temp); + fprintf(stderr, "3) read() failed (%d, error %d)\n", + count, errno); + logmessage(buf); + clientDead = 1; + return (0); + } + } + else + { + count = BUFSIZ; + } + } + else + { + count -= BUFSIZ; + } + bufptr -= BUFSIZ; + } + } + return (1); +} + +void +handleTorpReq(packet) + struct torp_cpacket *packet; +{ + ntorp((CARD8) packet->dir, (int) TMOVE); +} + +void +handlePhasReq(packet) + struct phaser_cpacket *packet; +{ + phaser(packet->dir); +} + +void +handleSpeedReq(packet) + struct speed_cpacket *packet; +{ + set_speed(packet->speed, 1); +} + +void +handleDirReq(packet) + struct dir_cpacket *packet; +{ + me->p_flags &= ~(PFPLOCK | PFPLLOCK); + set_course(packet->dir); +} + +void +handleShieldReq(packet) + struct shield_cpacket *packet; +{ + if (packet->state) + { + shield_up(); + } + else + { + shield_down(); + } +} + +void +handleRepairReq(packet) + struct repair_cpacket *packet; +{ + if (packet->state) + { + repair(); + } + else + { + me->p_flags &= ~(PFREPAIR); + } +} + +void +handleOrbitReq(packet) + struct orbit_cpacket *packet; +{ + if (packet->state) + { + orbit(); + } + else + { + me->p_flags &= ~PFORBIT; +#if 0 + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + if (me->p_flags & PFDOCK) + { + if (players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to disengage from bases while over warp 4."); + return; + } + else + undock_player(me); + } + } +} + +/*-----------------------------PRACTICE_ROBOT-----------------------------*/ +/* + * Send in a practice robot. You can only bring i a practice robot if no + * other players are in the game. + */ + +static void +practice_robo() +{ + char *paths; /* to hold dot dir path */ + char *arg1; + register int i; /* looping var */ + register struct player *j; /* to point to players */ + static struct timeval space = {0, 0}; + + if (!temporally_spaced(&space, 1000000)) /* damn auto-repeating... */ + return; + + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + if (j->p_status != PALIVE) /* if payer not alive, that's ok */ + continue; + if (j == me) /* ignore myself */ + continue; + warning("Can't send in practice robot with other players in the game."); + return; /* another player discovered--out of here */ + } + + if (fork() == 0) + { /* do if fork successful */ + (void) r_signal(SIGALRM, SIG_DFL); + (void) close(0); + (void) close(1); + (void) close(2); + switch (me->p_team) + { /* decide which teaem robot is on */ + case FED: + arg1 = "-Tf"; /* fed option */ + break; + case ROM: + arg1 = "-Tr"; /* rom option */ + break; + case KLI: + arg1 = "-Tk"; /* klingon option */ + break; + case ORI: + arg1 = "-To"; /* orion option */ + break; + default: + arg1 = "-Ti"; /* in case something screwy happens */ + break; + } + + paths = build_path(ROBOT); + + execl(paths, "robot", arg1, "-p", "-f", "-h", 0); + _exit(1); /* failure :( died at birth */ + } +} + +/*--------------------------------------------------------------------------*/ + +/* ARGSUSED */ +void +handlePractrReq(packet) + struct practr_cpacket *packet; +{ + practice_robo(); +} + +void +handleBombReq(packet) + struct bomb_cpacket *packet; +{ + if (packet->state) + { + bomb_planet(); + } + else + { + me->p_flags &= ~(PFBOMB); + } +} + +void +handleBeamReq(packet) + struct beam_cpacket *packet; +{ + if (packet->state == 1) + { + beam_up(); + } + else if (packet->state) + { + beam_down(); + } + else + { + me->p_flags &= ~(PFBEAMUP | PFBEAMDOWN); + } +} + +void +handleCloakReq(packet) + struct cloak_cpacket *packet; +{ + if (packet->state) + { + cloak_on(); + } + else + { + cloak_off(); + } +} + +/* ARGSUSED */ +void +handleDetTReq(packet) + struct det_torps_cpacket *packet; +{ + detothers(); +} + +/* ARGSUSED */ +void +handleCopilotReq(packet) + struct copilot_cpacket *packet; +{ + /* + * Unsupported... if (packet->state) { me->p_flags |= PFCOPILOT; } else { + * me->p_flags &= ~PFCOPILOT; } + */ +} + +void +handleOutfit(packet) + struct outfit_cpacket *packet; +{ + shipPick = packet->ship; + teamPick = packet->team; +} + +void +sendPickokPacket(state) + int state; +{ + struct pickok_spacket pickPack; + + pickPack.type = SP_PICKOK; + pickPack.state = state; + sendClientPacket((struct player_spacket *) & pickPack); +} + +void +handleLoginReq(packet) + struct login_cpacket *packet; +{ + if (packet->pad2 == 0x69) + { + if (packet->pad3 == 0x42) + blk_flag = 1; /* added 1/19/93 KAO */ + if (packet->pad3 == 0x43) + blk_flag = 2; + } + strncpy(namePick, packet->name, 16); + namePick[15] = 0; + strncpy(passPick, packet->password, 16); + passPick[15] = 0; + /* Is this a name query or a login? */ + if (packet->query) + { + passPick[15] = 1; + } + strncpy(login, packet->login, 16); + login[15] = 0; +} + +void +sendClientLogin(stats) + struct stats *stats; +{ + struct login_spacket logPacket; + logPacket.pad2 = 69; + if (configvals->galaxygenerator == 4) + logPacket.pad3 = 88; + else + logPacket.pad3 = 42; + logPacket.type = SP_LOGIN; + if (stats == NULL) + { + logPacket.accept = 0; + } + else + { + logPacket.accept = 1; + logPacket.flags = htonl(stats->st_flags); + } + sendClientPacket((struct player_spacket *) & logPacket); +} + +void +handlePlasmaReq(packet) + struct plasma_cpacket *packet; +{ + if (me->p_specweap & SFNHASMISSILE) + { + fire_missile_dir(packet->dir); + } + else if (me->p_specweap & SFNPLASMAARMED) + { + nplasmatorp(packet->dir, PTMOVE); + } + else + { + warning("This ship is armed with no special weapons"); + } +} + +void +handleWarReq(packet) + struct war_cpacket *packet; +{ + declare_war(packet->newmask); +} + +void +handlePlanlockReq(packet) + struct planlock_cpacket *packet; +{ + lock_planet(packet->pnum); +} + +void +handlePlaylockReq(packet) + struct playlock_cpacket *packet; +{ + lock_player(packet->pnum); +} + +void +handleDetMReq(packet) + struct det_mytorp_cpacket *packet; +{ + struct torp *atorp; + short t; + + /* you can det individual torps */ + t = ntohs(packet->tnum); + if (t < 0) + { + struct missile *dr; + int i, any; + + any = 0; + + for (i = 0; i < MAXTORP; i++) + { + atorp = &torps[me->p_no * MAXTORP + i]; + if (atorp->t_status == TMOVE || atorp->t_status == TSTRAIGHT) + { + atorp->t_status = TOFF; + any = 1; + } + } + + if (any) + return; + + for (i = 0; i < NPTHINGIES; i++) + { + dr = &missiles[me->p_no * NPTHINGIES + i]; + if (dr->ms_status == TMOVE || dr->ms_status == TSTRAIGHT) + { + switch (dr->ms_type) + { + case MISSILETHINGY: + dr->ms_status = TOFF; + break; + case FIGHTERTHINGY: + dr->ms_status = TRETURN; + break; + } + any = 1; + } + } + + /* any ? */ + } + else + { + + if (t < 0 || t >= MAXPLAYER * MAXTORP) + return; + atorp = &torps[t]; + + if (atorp->t_owner != me->p_no) + return; + if (atorp->t_status == TMOVE || atorp->t_status == TSTRAIGHT) + { + atorp->t_status = TOFF; + } + } +} + +void +handleTractorReq(packet) + struct tractor_cpacket *packet; +{ + int target; + struct player *player; + + if (weaponsallowed[WP_TRACTOR] == 0) + { + warning("Tractor beams haven't been invented yet."); + return; + } + target = packet->pnum; + if (packet->state == 0) + { + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFCLOAK) + { + warning("Weapons's Officer: Cannot tractor while cloaked, sir!"); + return; + } + if (target < 0 || target >= MAXPLAYER || target == me->p_no) + return; + player = &players[target]; + if (player->p_flags & PFCLOAK) + return; + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to tractor while docked and moving at a warp greater then 4."); + return; + } + if (ihypot(me->p_x - player->p_x, me->p_y - player->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + undock_player(me); + me->p_flags &= ~PFORBIT; +#if 0 + undock_player(player); /* harmless if they're not docked */ + +#if 0 + if (player->p_flags & PFORBIT) + planets[player->p_planet].pl_torbit &= ~player->p_team; + if (me->p_flags & PFORBIT) + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + player->p_flags &= ~(PFORBIT | PFDOCK); + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = target; + me->p_flags |= PFTRACT; + + } + else + { + warning("Weapon's Officer: Vessel is out of range of our tractor beam."); + } +} + +void +handleRepressReq(packet) + struct repress_cpacket *packet; +{ + int target; + struct player *player; + + if (weaponsallowed[WP_TRACTOR] == 0) + { + warning("Pressor beams haven't been invented yet."); + return; + } + target = packet->pnum; + if (packet->state == 0) + { + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFCLOAK) + { + warning("Weapons's Officer: Cannot pressor while cloaked, sir!"); + return; + } + if (target < 0 || target >= MAXPLAYER || target == me->p_no) + return; + player = &players[target]; + if (player->p_flags & PFCLOAK) + return; + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to pressor while docked and moving at a warp greater then 4."); + return; + } + if (ihypot(me->p_x - player->p_x, me->p_y - player->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + undock_player(me); + me->p_flags &= ~PFORBIT; +#if 0 + undock_player(player); + +#if 0 + if (player->p_flags & PFORBIT) + planets[player->p_planet].pl_torbit &= ~player->p_team; + if (me->p_flags & PFORBIT) + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + player->p_flags &= ~(PFORBIT | PFDOCK); + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = target; + me->p_flags |= (PFTRACT | PFPRESS); + } + else + { + warning("Weapon's Officer: Vessel is out of range of our pressor beam."); + } +} + +void +sendMotdLine(line) + char *line; +{ + struct motd_spacket motdPacket; + + motdPacket.type = SP_MOTD; + strncpy(motdPacket.line, line, 80); + motdPacket.line[79] = '\0'; + sendClientPacket((struct player_spacket *) & motdPacket); +} + +/* ARGSUSED */ +void +handleCoupReq(packet) + struct coup_cpacket *packet; +{ + switch_special_weapon(); +} + +void +handleRefitReq(packet) + struct refit_cpacket *packet; +{ + do_refit(packet->ship); +} + +void +handleMessageReq(packet) + struct mesg_cpacket *packet; +{ + char addrbuf[9]; + static long lasttime = 0 /* , time() */ ; + static int balance = 0; /* make sure he doesn't get carried away */ + long thistime; + + int isCensured(); /* "shut up and play" code 7/21/91 TC */ + int parseIgnore(); /* still more code, 7/24/91 TC */ + + /* + * Some random code to make sure the player doesn't get carried away about + * the number of messages he sends. After all, he could try to jam peoples + * communications if we let him. + */ + + thistime = time(NULL); + if (lasttime != 0) + { + balance = balance - (thistime - lasttime); + if (balance < 0) + balance = 0; + } + lasttime = thistime; + if (balance >= 15) + { + warning("Be quiet"); + balance += 3; + if (balance > time(NULL) + 60) + { + balance = time(NULL) + 60; + } + return; + } + balance += 3; + /* packet->mesg[69] = '\0'; */ + sprintf(addrbuf, " %s->", twoletters(me)); + if (parseIgnore(packet)) + return; /* moved this up 4/6/92 TC */ + if (packet->group & MGOD) + { + strcpy(addrbuf + 5, "GOD"); + } + else if (packet->group & MALL) + { + sprintf(addrbuf + 5, "ALL"); + if (isCensured(me->p_login)) + { + warning("You are censured. Message was not sent."); + return; + } + } + else if (packet->group & MTEAM) + { + if (packet->indiv != FED && packet->indiv != ROM && + packet->indiv != KLI && packet->indiv != ORI) + return; + if (isCensured(me->p_login) && (packet->indiv != me->p_team)) + { + warning("You are censured. Message was not sent."); + return; + } + sprintf(addrbuf + 5, teams[packet->indiv].shortname); + } + else if (packet->group & MINDIV) + { + if (packet->indiv < 0 || packet->indiv >= MAXPLAYER) + return; + if (players[packet->indiv].p_status == PFREE) + return; + if (isCensured(me->p_login) && (players[packet->indiv].p_team != me->p_team)) + { + warning("You are censured. Message was not sent."); + return; + } + if (ignored[packet->indiv] & MINDIV) + { + warning("You are ignoring that player. Message was not sent."); + return; + } + if ((me->p_team != players[packet->indiv].p_team) && + (isCensured(players[packet->indiv].p_login))) + { + warning("That player is censured. Message was not sent."); + return; + } + sprintf(addrbuf + 5, "%s ", twoletters(&players[packet->indiv])); + } + else + { + return; + } +#if 0 + if ((packet->group == MGOD + || me->p_no == packet->indiv && packet->group == MINDIV) + && parse_command_mess(packet->mesg, me->p_no)) + { + /* message parsed. Eat it */ + } + else + { + pmessage2(packet->mesg, packet->indiv, packet->group, addrbuf, me->p_no); + } +#else + /* don't eat the parsed messages */ + pmessage2(packet->mesg, packet->indiv, packet->group, addrbuf, me->p_no); + if (me->p_no == packet->indiv && packet->group == MINDIV) + { + char tmpbuf[sizeof(packet->mesg) + 1]; + strncpy(tmpbuf, packet->mesg, sizeof(packet->mesg)); + tmpbuf[sizeof(packet->mesg)] = 0; + parse_command_mess(tmpbuf, me->p_no); + } +#endif + + /* + * Blech !!! + * + * Don't do this: + * + * if (me->p_no == packet->indiv && packet->mesg[0] == '_') me = &players[0]; + */ +} + +/* ARGSUSED */ +void +handleQuitReq(packet) + struct quit_cpacket *packet; +{ + if (me->p_status == POBSERVE) + { + me->p_status = PTQUEUE; + return; + } + me->p_flags |= PFSELFDEST; + + switch (me->p_ship.s_type) + { + case STARBASE: + case WARBASE: + selfdest = 60; + break; + default: + selfdest = 10; + } + + selfdest = me->p_updates + selfdest * 10; + + warning("Self destruct initiated"); +} + +void +sendMaskPacket(mask) + int mask; +{ + struct mask_spacket maskPacket; + + maskPacket.type = SP_MASK; + maskPacket.mask = mask; + sendClientPacket((struct player_spacket *) & maskPacket); +} + +void +handleOptionsPacket(packet) + struct options_cpacket *packet; +{ + mystats->st_flags = ntohl(packet->flags) | + (mystats->st_flags & ST_CYBORG); /* hacked fix 8/24/91 TC */ + keeppeace = (mystats->st_flags / ST_KEEPPEACE) & 1; +} + +void +handleSocketReq(packet) + struct socket_cpacket *packet; +{ + nextSocket = ntohl(packet->socket); + userVersion = packet->version; + userUdpVersion = packet->udp_version; +} + +/* ARGSUSED */ +void +handleByeReq(packet) + struct bye_cpacket *packet; +{ + noressurect = 1; +} + +int +checkVersion() +{ + struct badversion_spacket packet; + + if (userVersion != SOCKVERSION) + { + packet.type = SP_BADVERSION; + packet.why = 0; + sendClientPacket((struct player_spacket *) & packet); + flushSockBuf(); + return (0); + } + return (1); +} + +void +logEntry() +{ + FILE *logfile; + int curtime; + char *paths; + + paths = build_path(LOGFILENAME); + logfile = fopen(paths, "a"); + if (!logfile) + return; + curtime = time(NULL); + +#ifdef LOG_LONG_INFO /*-[ prints out long info to the log files ]-*/ + + fprintf(logfile, "Joining: %s, (%c) <%s@%s> %s", me->p_name, + shipnos[me->p_no], + me->p_login, /* debug 2/21/92 TMC */ + +#else + + fprintf(logfile, "Joining: %s <%s@%s> %s", me->p_name, me->p_login, + +#endif /*-[ LOG_LONG_INFO ]-*/ + + me->p_full_hostname, + ctime((time_t *) & curtime)); + + fclose(logfile); +} + +/* gwrite was here */ + +void +handleDockingReq(packet) + struct dockperm_cpacket *packet; +{ + int i; + + if (allows_docking(me->p_ship)) + { + if (me->p_speed > 4 && me->p_docked) + { + warning("It's unsafe to disengage other ships while over warp 4."); + return; + } + else + { + for (i = 0; i < me->p_ship.s_numports; i++) + base_undock(me, i); + me->p_docked = 0; + + if (packet->state) + me->p_flags |= PFDOCKOK; + else + me->p_flags &= ~PFDOCKOK; + } + } +} + +void +handleReset(packet) + struct resetstats_cpacket *packet; +{ + extern int startTkills, startTlosses, startTarms, startTplanets, startTticks; + + if (packet->verify != 'Y') + return; + + /* Gee, they seem to want to reset their stats! Here goes... */ +#if 0 + mystats->st_maxkills = 0.0; + mystats->st_kills = 0; + mystats->st_losses = 0; + mystats->st_armsbomb = 0; + mystats->st_planets = 0; + mystats->st_ticks = 0; + mystats->st_tkills = 0; + mystats->st_tlosses = 0; + mystats->st_tarmsbomb = 0; + mystats->st_tplanets = 0; + mystats->st_tticks = 1; + mystats->st_rank = 0; + mystats->st_sbkills = 0; + mystats->st_sblosses = 0; + mystats->st_sbticks = 0; + mystats->st_sbmaxkills = 0.0; + + startTkills = mystats->st_tkills; + startTlosses = mystats->st_tlosses; + startTarms = mystats->st_tarmsbomb; + startTplanets = mystats->st_tplanets; + startTticks = mystats->st_tticks; +#endif + + mystats->st_genocides = 0; + mystats->st_tmaxkills = 0.0; + mystats->st_di = 0.0; + mystats->st_tkills = 0; + mystats->st_tlosses = 0; + mystats->st_tarmsbomb = 0; + mystats->st_tresbomb = 0; + mystats->st_tdooshes = 0; + mystats->st_tplanets = 0; + mystats->st_tticks = 1; + mystats->st_sbkills = 0; + mystats->st_sblosses = 0; + mystats->st_sbmaxkills = 0.0; + mystats->st_sbticks = 1; + mystats->st_wbkills = 0; + mystats->st_wblosses = 0; + mystats->st_wbmaxkills = 0.0; + mystats->st_wbticks = 1; + mystats->st_jsplanets = 0; + mystats->st_jsticks = 1; + mystats->st_rank = 0; + mystats->st_royal = 0; + + startTkills = mystats->st_tkills; + startTlosses = mystats->st_tlosses; + startTarms = mystats->st_tarmsbomb; + startTplanets = mystats->st_tplanets; + startTticks = mystats->st_tticks; +} + +void +handleUpdatesReq(packet) + struct updates_cpacket *packet; +{ + struct itimerval udt; + extern int interrupting; /* main.c */ + int min_delay = me->p_observer + ? configvals->min_observer_upd_delay + : configvals->min_upd_delay; + + timerDelay = ntohl(packet->usecs); + if (timerDelay < min_delay) + timerDelay = min_delay; + if (timerDelay >= 1000000) + timerDelay = 999999; + + if (interrupting) + { /* only setitimer if the ntserv is configured + * to handle it. It's NOT configured to + * handle it in the outfit loop... */ + udt.it_interval.tv_sec = 0; + udt.it_interval.tv_usec = timerDelay; + udt.it_value.tv_sec = 0; + udt.it_value.tv_usec = timerDelay; + setitimer(ITIMER_REAL, &udt, 0); + } + +} + +void +logmessage(string) + char *string; +{ + FILE *fp; + char *paths; + + paths = build_path(LOGFILENAME); + + fp = fopen(paths, "a"); + if (fp) + { + fprintf(fp, "%s\n", string); + fclose(fp); + } +} + +#if 0 +handleReserved(packet) + struct reserved_cpacket *packet; +{ + /* char temp[20]; */ + struct reserved_cpacket mycp; + struct reserved_spacket mysp; + char serverName[64]; /* now get serverName from system 8/2/92 TC */ + + if (testtime == 1) + return; + if (memcmp(packet->data, testdata, 16) != 0) + { + testtime = 1; + return; + } + memcpy(mysp.data, testdata, 16); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); /* 8/2/92 TC */ + encryptReservedPacket(&mysp, &mycp, serverName, me->p_no); + if (memcmp(packet->resp, mycp.resp, 16) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + testtime = 0; +} + +#ifdef ATM_STUFF +void +dummy_() +{ + if ((configvals->binconfirm == 2) && + !strcmp(packet->resp, "Cyborg")) + { + testtime = 0; /* accept */ + cyborg = 1; + if (me->p_name[0] != '+') + { + temp[0] = '+'; /* indicate cyborg */ + strcpy(temp + 1, me->p_name); /* this happens AFTER entry, */ + temp[15] = '\0'; /* so changing enter() isn't */ + strcpy(me->p_name, temp); /* sufficient */ + } + return; + } + + if (memcmp(packet->resp, mycp.resp, 16) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + + testtime = 0; +} + +#endif +#else + +void +handleRSAKey(packet) + struct rsa_key_cpacket *packet; +{ +#ifdef AUTHORIZE + struct rsa_key_spacket mysp; + char serverName[64]; + + if (testtime == 1) + return; + if (RSA_Client != 1) + return; + memcpy(mysp.data, testdata, KEY_SIZE); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); + if (decryptRSAPacket(&mysp, packet, serverName)) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + testtime = 0; +#endif /* AUTHORIZE */ +} + +void +handleReserved(packet) + struct reserved_cpacket *packet; +{ +#ifdef AUTHORIZE + struct reserved_cpacket mycp; + struct reserved_spacket mysp; + struct rsa_key_spacket rsp; + char serverName[64]; /* now get serverName from system 8/2/92 TC */ + + if (testtime == 1) + return; + if (memcmp(packet->data, testdata, RESERVED_SIZE) != 0) + { + testtime = 1; + return; + } + if (!strncmp(packet->resp, RSA_VERSION, 3)) + { + /* This is an RSA type client */ + RSA_Client = 2; + warning(RSA_VERSION); + if (!strncmp(packet->resp, RSA_VERSION, strlen("RSA v??"))) + { + /* This is the right major version */ + RSA_Client = 1; + makeRSAPacket(&rsp); + memcpy(testdata, rsp.data, KEY_SIZE); + sendClientPacket((struct player_spacket *) & rsp); + return; + } + testtime = 1; + return; + } + memcpy(mysp.data, testdata, RESERVED_SIZE); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); /* 8/2/92 TC */ + encryptReservedPacket(&mysp, &mycp, serverName, me->p_no); + if (memcmp(packet->resp, mycp.resp, RESERVED_SIZE) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + /* Use .sysdef CONFIRM flag to allow old style clients. */ + if (configvals->binconfirm == 2) + testtime = 0; + else + testtime = 1; + +#endif /* AUTHORIZE */ +} + +#endif + +void +handleScan(packet) /* ATM */ + struct scan_cpacket *packet; +{ +#if 0 + struct scan_spacket response; + struct player *pp; + + memset(&response, 0, sizeof(struct scan_spacket)); + response.type = SP_SCAN; + response.pnum = packet->pnum; + if (!weaponsallowed[WP_SCANNER]) + { + warning("Scanners haven't been invented yet"); + response.success = 0; + } + else + { + response.success = scan(packet->pnum); + + if (response.success) + { + /fill in all the goodies / + pp = &players[packet->pnum]; + response.p_fuel = htonl(pp->p_fuel); + response.p_armies = htonl(pp->p_armies); + response.p_shield = htonl(pp->p_shield); + response.p_damage = htonl(pp->p_damage); + response.p_etemp = htonl(pp->p_etemp); + response.p_wtemp = htonl(pp->p_wtemp); + } + } + sendClientPacket((struct player_spacket *) & response); +#endif +} + + +void +handlePingResponse(packet) + struct ping_cpacket *packet; +{ + char buf[80]; + /* client requests pings by sending pingme == 1 on TCP socket */ + + if (rsock == sock) + { + if (!ping && packet->pingme == 1) + { + ping = 1; + sprintf(buf, "Server sending ping packets at %d second intervals", + configvals->ping_period); + warning(buf); + return; + } + /* client says stop */ + else if (ping && !packet->pingme) + { + ping = 0; + warning("Server no longer sending ping packets."); + return; + } + } + pingResponse(packet); /* ping.c */ +} + +#ifdef SHORT_PACKETS + +void +handleShortReq(packet) + struct shortreq_cpacket *packet; +{ + struct shortreply_spacket resp; + + switch (packet->req) + { + case SPK_VOFF: + send_short = 0; + warning("Not sending variable and short packets. Back to default."); + if (udpSock >= 0 && udpMode == MODE_FAT) + forceUpdate(); + break; + + case SPK_VON: + if (packet->version != (char) SHORTVERSION) + { + warning("Your SHORT Protocol Version is not right!"); + packet->req = SPK_VOFF; + break; + } + if (!send_short) + warning("Sending variable and short packets. "); /* send only firsttime */ + send_short = 1; + resp.winside = ntohs(WINSIDE); + resp.gwidth = ntohl(GWIDTH); + break; + + case SPK_MOFF: + send_mesg = 1; + warning("Obsolete!"); + packet->req = SPK_MON; + break; + + case SPK_MON: + send_mesg = 1; + warning("All messages sent."); + break; + + case SPK_M_KILLS: + send_kmesg = 1; + warning("Kill messages sent"); + break; + + case SPK_M_NOKILLS: + send_kmesg = 1; + warning("Obsolete!"); + packet->req = SPK_M_KILLS; + break; + + case SPK_M_WARN: + send_warn = 1; + warning("Warn messages sent"); + break; + + case SPK_M_NOWARN: + send_warn = 1; + warning("Obsolete!"); + packet->req = SPK_M_WARN; + break; + + case SPK_SALL: + if (send_short) + { + spk_update_sall = 1; + spk_update_all = 0; + forceUpdate(); + } + else + warning("Activate SHORT Packets first!"); + return; + + case SPK_ALL: + if (send_short) + { + spk_update_sall = 0; + spk_update_all = 1; + forceUpdate(); + } + else + warning("Activate SHORT Packets first!"); + return; + + default: + warning("Unknown short packet code"); + return; + } + + resp.type = SP_S_REPLY; + resp.repl = (char) packet->req; + + sendClientPacket((struct player_spacket *) & resp); +} + +void +handleThresh(packet) + struct threshold_cpacket *packet; +{ + send_threshold = packet->thresh; +#ifdef SHORT_THRESHOLD + if (send_threshold == 0) + { + actual_threshold = 0; + warning("Threshold test deactivated."); + } + else + { + actual_threshold = send_threshold / numupdates; + if (actual_threshold < 60) + { /* my low value */ + actual_threshold = 60; /* means: 1 SP_S_PLAYER+SP_S_YOU + 16 bytes */ + sprintf(buf, "Threshold set to %d . %d / Update(Server limit!)", + numupdates * 60, 60); + warning(buf); + } + else + { + sprintf(buf, "Threshold set to %d . %d / Update", send_threshold, actual_threshold); + warning(buf); + } + } +#else + warning("Server is compiled without Thresholdtesting!"); +#endif +} + +void +handleSMessageReq(packet) + struct mesg_s_cpacket *packet; +{ + /* If someone would delete the hardcoded things in handleMessageReq */ + /* like packet->mesg[69]='\0'; */ + /* we could give handleMessageReq the packet without copying */ + /* But i have no time HW 04/6/93 */ + + struct mesg_cpacket mesPacket; + mesPacket.type = CP_MESSAGE; + mesPacket.group = packet->group; + mesPacket.indiv = packet->indiv; + strcpy(mesPacket.mesg, packet->mesg); + handleMessageReq(&mesPacket); + /* I hope this was it */ +} + + +#endif + +/* + * + * --------------------------------------------------------------------------- + * Strictly UDP from here on + * --------------------------------------------------------------------------- + * */ + +void +handleUdpReq(packet) + struct udp_req_cpacket *packet; +{ + struct udp_reply_spacket response; + int mode; + + response.type = SP_UDP_REPLY; + + if (packet->request == COMM_VERIFY) + { + /* this request should ONLY come through the UDP connection */ + if (commMode == COMM_UDP) + { + UDPDIAG(("Got second verify from %s; resending server verify\n", + me->p_name)); + response.reply = SWITCH_VERIFY; + goto send; + } + UDPDIAG(("Receieved UDP verify from %s\n", me->p_name)); + UDPDIAG(("--- UDP connection established to %s\n", me->p_name)); +#ifdef BROKEN + warning("WARNING: BROKEN mode is enabled"); +#endif + + resetUDPsequence(); /* reset sequence numbers */ + commMode = COMM_UDP; /* at last */ + udpMode = MODE_SIMPLE; /* just send one at a time */ + + /* note that we don't NEED to send a SWITCH_VERIFY packet; the client */ + /* + * will change state when it receives ANY packet on the UDP connection + */ + /* (this just makes sure that it gets one) */ + /* (update: recvfrom() currently tosses the first packet it gets...) */ + response.reply = SWITCH_VERIFY; + goto send; + /* return; */ + } + if (packet->request == COMM_MODE) + { + /* wants to switch modes; mode is in "conmode" */ + mode = packet->connmode; + if (mode < MODE_TCP || mode > MODE_DOUBLE) + { + warning("Server can't do that UDP mode"); + UDPDIAG(("Got bogus request for UDP mode %d from %s\n", + mode, me->p_name)); + } + else + { + /* I don't bother with a reply, though it can mess up the opt win */ + switch (mode) + { + case MODE_TCP: + warning("Server will send with TCP only"); + break; + case MODE_SIMPLE: + warning("Server will send with simple UDP"); + break; + case MODE_FAT: + warning("Server will send with fat UDP; sent full update"); + V_UDPDIAG(("Sending full update to %s\n", me->p_name)); + forceUpdate(); + break; +#ifdef DOUBLE_UDP + case MODE_DOUBLE: + warning("Server will send with double UDP"); + scbufptr = scbuf + sizeof(struct sc_sequence_spacket); + break; +#else + case MODE_DOUBLE: + warning("Request for double UDP DENIED (set to simple)"); + mode = MODE_SIMPLE; + break; +#endif /* DOUBLE_UDP */ + } + + udpMode = mode; + UDPDIAG(("Switching %s to UDP mode %d\n", me->p_name, mode)); + } + return; + } + if (packet->request == COMM_UPDATE) + { + /* client wants a FULL update */ + V_UDPDIAG(("Sending full update to %s\n", me->p_name)); + forceUpdate(); + + return; + } + UDPDIAG(("Received request for %s mode from %s\n", + (packet->request == COMM_TCP) ? "TCP" : "UDP", me->p_name)); + if (packet->request == commMode) + { + /* client asking to switch to current mode */ + if (commMode == COMM_UDP) + { + /* + * client must be confused... whatever the cause, he obviously isn't + * connected to us, so we better drop out end and retry. + */ + UDPDIAG(("Rcvd UDP req from %s while in UDP mode; dropping old\n", + me->p_name)); + closeUdpConn(); + commMode = COMM_TCP; + /* ...and fall thru to the UDP request handler */ + } + else + { + /* + * Again, client is confused. This time there's no damage though. Just + * tell him that he succeeded. Could also happen if the client tried + * to connect to our UDP socket but failed, and decided to back off. + */ + UDPDIAG(("Rcvd TCP req from %s while in TCP mode\n", me->p_name)); + + response.reply = SWITCH_TCP_OK; + sendClientPacket((struct player_spacket *) & response); + + if (udpSock >= 0) + { + closeUdpConn(); + UDPDIAG(("Closed UDP socket\n")); + } + return; + } + } + /* okay, we have a request to change modes */ + if (packet->request == COMM_UDP) + { + udpClientPort = ntohl(packet->port); /* where to connect to */ + if (!configvals->udpAllowed) + { + UDPDIAG(("Rejected UDP request from %s\n", me->p_name)); + response.reply = SWITCH_DENIED; + response.port = htons(0); + goto send; + } + else + { + if (userUdpVersion != UDPVERSION) + { + char buf[80]; + sprintf(buf, "Server UDP is v%.1f, client is v%.1f", + (float) UDPVERSION / 10.0, + (float) userUdpVersion / 10.0); + warning(buf); + UDPDIAG(("%s (rejected %s)\n", buf, me->p_name)); + response.reply = SWITCH_DENIED; + response.port = htons(1); + goto send; + } + if (udpSock >= 0) + { + /* we have a socket open, but the client doesn't seem aware */ + /* (probably because our UDP verify got lost down the line) */ + UDPDIAG(("Receieved second request from %s, reconnecting\n", + me->p_name)); + closeUdpConn(); + } + /* (note no openUdpConn(); we go straight to connect) */ + if (connUdpConn() < 0) + { + response.reply = SWITCH_DENIED; + response.port = 0; + goto send; + } + UDPDIAG(("Connected UDP socket (%d:%d) for %s\n", udpSock, + udpLocalPort, me->p_name)); + + /* we are now connected to the client, but he's merely bound */ + /* don't switch to UDP mode yet; wait until client connects */ + response.reply = SWITCH_UDP_OK; + response.port = htonl(udpLocalPort); + + UDPDIAG(("packet->connmode = %d\n", packet->connmode)); + if (packet->connmode == CONNMODE_PORT) + { + /* send him our port # so he can connect to us */ + goto send; + } + else + { /* send him a packet; he'll get port from + * recvfrom() */ + int t = sizeof(response); + if (gwrite(udpSock, (char *) &response, sizeof(response)) != t) + { + UDPDIAG(("Attempt to send UDP packet failed; using alt\n")); + } + goto send; + } + + } + } + else if (packet->request == COMM_TCP) + { + closeUdpConn(); + commMode = COMM_TCP; + response.reply = SWITCH_TCP_OK; + response.port = 0; + UDPDIAG(("Closed UDP socket for %s\n", me->p_name)); + goto send; + } + else + { + fprintf(stderr, "ntserv: got weird UDP request (%d)\n", + packet->request); + return; + } +send: + sendClientPacket((struct player_spacket *) & response); +} + + +int +connUdpConn() +{ + struct sockaddr_in addr; + int len; + + if (udpSock > 0) + { + fprintf(stderr, "ntserv: tried to open udpSock twice\n"); + return (0); /* pretend we succeeded (this could be bad) */ + } + resetUDPbuffer(); + if ((udpSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("ntserv: unable to create DGRAM socket"); + return (-1); + } + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = remoteaddr; /* addr of our client */ + addr.sin_port = htons(udpClientPort); /* client's port */ + + if (connect(udpSock, (struct sockaddr *) & addr, sizeof(addr)) < 0) + { + perror("ntserv: connect to client UDP port"); + UDPDIAG(("Unable to connect() to %s on port %d\n", me->p_name, + udpClientPort)); + close(udpSock); + udpSock = -1; + return (-1); + } + UDPDIAG(("connect to %s's port %d on 0x%x succeded\n", + me->p_name, udpClientPort, remoteaddr)); + + /* determine what our port is */ + len = sizeof(addr); + if (getsockname(udpSock, (struct sockaddr *) & 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); + } + udpLocalPort = (int) ntohs(addr.sin_port); + + if (configvals->udpAllowed > 2) /* verbose debug mode? */ + printUdpInfo(); + + return (0); +} + +int +closeUdpConn() +{ + V_UDPDIAG(("Closing UDP socket\n")); + if (udpSock < 0) + { + fprintf(stderr, "ntserv: tried to close a closed UDP socket\n"); + return (-1); + } + shutdown(udpSock, 2); /* wham */ + close(udpSock); /* bam */ + udpSock = -1; /* (nah) */ + + return (0); +} + +/* used for debugging */ +void +printUdpInfo() +{ + 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%lx, family=%d, port=%d\n", + (u_long) 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%lx, family=%d, port=%d\n", + (u_long) addr.sin_addr.s_addr, + addr.sin_family, ntohs(addr.sin_port))); +} + +void +handleSequence() +{ + /* we don't currently deal with sequence numbers from clients */ +} + +void +handleAskMOTD() +{ + sendMotd(); +} + + +#ifdef DOUBLE_UDP +/* + * If we're in double-UDP mode, then we need to send a separate semi-critical + * transmission over UDP. We need to give it the same sequence number as the + * previous transmission, but the sequence packet will have type + * SP_CP_SEQUENCE instead of SP_SEQUENCE. + */ +void +sendSC() +{ + struct sequence_spacket *ssp; + struct sc_sequence_spacket *sc_sp; + int cc; + + if (commMode != COMM_UDP || udpMode != MODE_DOUBLE) + { + /* mode not active, keep buffer clear */ + scbufptr = scbuf; + return; + } + if (scbufptr - scbuf <= sizeof(struct sc_sequence_spacket)) + { + /* nothing to send */ + return; + } + /* copy sequence #, send what we got, then reset buffer */ + sc_sp = (struct sc_sequence_spacket *) scbuf; + ssp = (struct sequence_spacket *) udpbuf; + sc_sp->type = SP_SC_SEQUENCE; + sc_sp->sequence = ssp->sequence; + if ((cc = gwrite(udpSock, scbuf, scbufptr - scbuf)) != scbufptr - scbuf) + { + fprintf(stderr, "UDP sc gwrite failed (%d, error %d)\n", cc, errno); + UDPDIAG(("*** UDP diSConnected for %s\n", me->p_name)); + printUdpInfo(); + closeUdpConn(); + commMode = COMM_TCP; + return; + } + scbufptr = scbuf + sizeof(struct sc_sequence_spacket); +} + +#endif + +/* + * This is a truncated version of initClientData(). Note that it doesn't + * explicitly reset all the fat UDP stuff; sendClientData will take care of + * that by itself eventually. + * + * Only semi-critical data is sent, with a few exceptions for non-critical data + * which would be nice to update (stats, kills, player posn, etc). The + * critical stuff can't be lost, so there's no point in resending it. + * + * (Since the fat data begins in an unqueued state, forceUpdate() should be + * called immediately after switching to fat mode. This guarantees that + * every packet will end up on a queue. The only real reason for doing this + * is so that switching to fat mode will clear up your display and keep it + * cleared; otherwise you could have torps floating around forever because + * the packet for them isn't on a queue. Will it reduce the effectiveness of + * fat UDP? No, because as soon as the player hits the "update all" key it's + * gonna happen anyway...) + */ +void +forceUpdate() +{ + static time_t lastone = 0; + time_t now; + int i; + + now = time(0); + if (now - lastone < UDP_UPDATE_WAIT) + { + warning("Update request DENIED (chill out!)"); + return; + } + lastone = now; + + /* clientDead=0; */ + for (i = 0; i < MAXPLAYER; i++) + { + clientHostile[i].hostile = -1; + clientStats[i].losses = -1; /* (non-critical, but nice) */ + /* clientLogin[i].rank= -1; (critical) */ + /* clientPlayersInfo[i].shiptype= -1; (critical) */ + /* clientPStatus[i].status= -1; (critical) */ + clientPlayers[i].x = htonl(-1); /* (non-critical, but nice) */ + clientPhasers[i].status = -1; + clientKills[i].kills = htonl(-1); /* (non-critical, but nice) */ + clientFlags[i].flags = htonl(-1); + mustUpdate[i] = 0; + } + for (i = 0; i < MAXPLAYER * MAXTORP; i++) + { + clientTorpsInfo[i].status = -1; + /* clientTorps[i].x= -1; (non-critical) */ + } + for (i = 0; i < MAXPLAYER * MAXPLASMA; i++) + { + clientPlasmasInfo[i].status = -1; + /* clientPlasmas[i].x= -1; (non-critical) */ + } + for (i = 0; i < TOTALTHINGIES; i++) + { + + clientThingysInfo[i].shape = htons(-1); + /* clientThingys[i].x= -1; (non-critical) */ + } + for (i = 0; i < MAXPLANETS; i++) + { + clientPlanets2[i].armies = htonl(-2); + /* clientPlanetLocs[i].x= htonl(-1); (critical) */ + } + /* msgCurrent=(mctl->mc_current+1) % MAXMESSAGE; */ + clientSelf.pnum = -1; +} + +int +isCensured(s) /* return true if cannot message opponents */ + char *s; +{ + return ( +#if 0 + (strncmp(s, "am4m", 4) == 0) || /* 7/21/91 TC */ + (strncmp(s, "dm3e", 4) == 0) || /* 7/21/91 TC */ + (strncmp(s, "gusciora", 8) == 0) || /* 7/25/91 TC */ + (strncmp(s, "flan", 4) == 0) || /* 4/2/91 TC */ + (strncmp(s, "kc3b", 4) == 0) || /* 4/4/91 TC */ + (strncmp(s, "windom", 6) == 0) || /* 7/20/92 TC */ +#endif + 0 + ); +} + +/* return true if you should eat message */ + +int +parseIgnore(packet) + struct mesg_cpacket *packet; +{ + char *s; + int who; + int what; + char buf[80]; + int noneflag; + + /* if (packet->indiv != me->p_no) return 0; */ + + s = packet->mesg; + + who = packet->indiv; + if ((*s != ':') && (strncmp(s, " ", 5) != 0)) + return 0; + if ((who == me->p_no) || (*s == ' ')) + { /* check for borg call 4/6/92 TC */ + if (configvals->binconfirm) + warning("No cyborgs allowed in the game at this time."); + else + { + char buf[80]; + char buf2[5]; + int i; + int cybflag = 0; + + strcpy(buf, "Possible cyborgs: "); + for (i = 0; i < MAXPLAYER; i++) + if ((players[i].p_status != PFREE) && + (players[i].p_stats.st_flags & ST_CYBORG)) + { + sprintf(buf2, "%s ", twoletters(&players[i])); + strcat(buf, buf2); + cybflag = 1; + } + if (!cybflag) + strcat(buf, "None"); + warning(buf); + } + if (*s != ' ') /* if not a borg call, eat msg 4/6/92 TC */ + return 1; + else + return 0; /* otherwise, send it 4/6/92 TC */ + } + if (packet->group != MINDIV) + return 0; /* below is for indiv only */ + + do + { + what = 0; + switch (*(++s)) + { + case 'a': + case 'A': + what = MALL; + break; + case 't': + case 'T': + what = MTEAM; + break; + case 'i': + case 'I': + what = MINDIV; + break; + case '\0': + what = 0; + break; + default: + what = 0; + break; + } + ignored[who] ^= what; + } while (what != 0); + + strcpy(buf, "Ignore status for this player: "); + noneflag = 1; + if (ignored[who] & MALL) + { + strcat(buf, "All "); + noneflag = 0; + } + if (ignored[who] & MTEAM) + { + strcat(buf, "Team "); + noneflag = 0; + } + if (ignored[who] & MINDIV) + { + strcat(buf, "Indiv "); + noneflag = 0; + } + if (noneflag) + strcat(buf, "None"); + warning(buf); + return 1; +} + +/* give session stats if you send yourself a '?' 2/27/92 TC */ +/* or '!' for ping stats (HAK) */ +/* merged RSA query '#' here, too (HAK) */ +/* return true if you should eat message */ + +int +parseQuery(packet) + struct mesg_spacket *packet; /* was cpacket 4/17/92 TC */ +{ + char buf[80]; + float sessionBombing, sessionPlanets, sessionOffense, sessionDefense; + int deltaArmies, deltaPlanets, deltaKills, deltaLosses, deltaTicks; + + extern int startTkills, startTlosses, startTarms, startTplanets, startTticks; + + /* 0-8 for address, 9 is space */ + + if (packet->mesg[11] != '\0') /* one character only */ + return 0; + + switch (packet->mesg[10]) + { + case '!': + return bouncePingStats(packet); + case '#': + sprintf(buf, "Client: %s", RSA_client_type); + bounce(buf, packet->m_from); + return 1; + case '?': + deltaPlanets = me->p_stats.st_tplanets - startTplanets; + deltaArmies = me->p_stats.st_tarmsbomb - startTarms; + deltaKills = me->p_stats.st_tkills - startTkills; + deltaLosses = me->p_stats.st_tlosses - startTlosses; + deltaTicks = me->p_stats.st_tticks - startTticks; + + if (deltaTicks == 0) + return 1; /* can happen if no tmode */ + + sessionPlanets = (float) deltaPlanets *status->timeprod / + ((float) deltaTicks * status->planets); + + sessionBombing = (float) deltaArmies *status->timeprod / + ((float) deltaTicks * status->armsbomb); + + sessionOffense = (float) deltaKills *status->timeprod / + ((float) deltaTicks * status->kills); + + sessionDefense = (float) deltaTicks *status->losses / + (deltaLosses != 0 ? + ((float) deltaLosses * status->timeprod) : + (status->timeprod)); + + sprintf(buf, "%2s stats: %d planets and %d armies. %d wins/%d losses. %5.2f hours.", + twoletters(me), + deltaPlanets, + deltaArmies, + deltaKills, + deltaLosses, + (float) deltaTicks / 36000.0); + bounce(buf, packet->m_from); + sprintf(buf, "Ratings: Pla: %5.2f Bom: %5.2f Off: %5.2f Def: %5.2f Ratio: %4.2f", + sessionPlanets, + sessionBombing, + sessionOffense, + sessionDefense, + (float) deltaKills / + (float) ((deltaLosses == 0) ? 1 : deltaLosses)); + bounce(buf, packet->m_from); + return 1; + default: + return 0; + } + /* NOTREACHED */ +} + +int +bouncePingStats(packet) + struct mesg_spacket *packet; +{ + char buf[80]; + + if (me->p_avrt == -1) + { + /* client doesn't support it or server not pinging */ + sprintf(buf, "No ping stats available for %s", + twoletters(me)); + } + else + { + sprintf(buf, "%s ping stats: Average: %d ms, Stdv: %d ms, Loss: %d%%", + twoletters(me), + me->p_avrt, + me->p_stdv, + me->p_pkls); + } + bounce(buf, packet->m_from); + + return 1; +} + +/* new code, sends bouncemsg to bounceto from GOD 4/17/92 TC */ +void +bounce(bouncemsg, bounceto) + char *bouncemsg; + int bounceto; +{ + char buf[10]; + + sprintf(buf, "GOD->%s", twoletters(&players[bounceto])); + pmessage(bouncemsg, bounceto, MINDIV, buf); +} + + +/* + */ + +void +sendShipCap() +{ + struct ship_cap_spacket temppack; + struct ship ship; + int i; + + if (!blk_flag) + return; + for (i = 0; i < NUM_TYPES; i++) + { + getship(&ship, i); + temppack.type = SP_SHIP_CAP; + temppack.operation = 0; + temppack.s_type = htons(ship.s_type); + temppack.s_torpspeed = htons(ship.s_torp.speed); +#if 1 + temppack.s_phaserrange = htons(ship.s_phaser.speed); +#else + temppack.s_phaserrange = htons(ship.s_phaser.damage); +#endif + temppack.s_maxspeed = htonl(ship.s_imp.maxspeed); + temppack.s_maxfuel = htonl(ship.s_maxfuel); + temppack.s_maxshield = htonl(ship.s_maxshield); + temppack.s_maxdamage = htonl(ship.s_maxdamage); + temppack.s_maxwpntemp = htonl(ship.s_maxwpntemp); + temppack.s_maxegntemp = htonl(ship.s_maxegntemp); + temppack.s_width = htons(ship.s_width); + temppack.s_height = htons(ship.s_height); + temppack.s_maxarmies = htons(ship.s_maxarmies); + temppack.s_letter = ship.s_letter; + temppack.s_desig1 = ship.s_desig1; + temppack.s_desig2 = ship.s_desig2; + if (blk_flag == 1) + temppack.s_bitmap = htons(ship.s_alttype); + else + temppack.s_bitmap = htons(ship.s_bitmap); + sendClientPacket((struct player_spacket *) & temppack); + } +} + +void +sendMotdPic(x, y, bits, page, width, height) + int x; + int y; + char *bits; + int page; + int width; + int height; +{ + struct motd_pic_spacket temppack; + short sx, sy, sp, sw, sh; + int size; + + size = (width / 8 + (width % 8 != 0)) * height; + sx = x; + sy = y; + sp = page; + sw = width; + sh = height; + temppack.type = SP_MOTD_PIC; + temppack.x = htons(sx); + temppack.y = htons(sy); + temppack.width = htons(sw); + temppack.height = htons(sh); + temppack.page = htons(sp); + memcpy(temppack.bits, bits, size); + + sendClientPacket((struct player_spacket *) & temppack); +} + + +void +sendMotdNopic(x, y, page, width, height) + int x; + int y; + int page; + int width; + int height; +{ + struct pe1_missing_bitmap_spacket temppack; + + temppack.type = SP_PARADISE_EXT1; + temppack.subtype = SP_PE1_MISSING_BITMAP; + temppack.page = htons((short) page); + temppack.x = htons((short) x); + temppack.y = htons((short) y); + temppack.width = htons((short) width); + temppack.height = htons((short) height); + + sendClientPacket((struct player_spacket *) & temppack); +} + +/* tells the client how many missiles carried [BDyess] */ +void +sendMissileNum(num) + int num; +{ + + /* remove the 1 || to enable missile updates [BDyess] */ + if (clientMissiles.num == htons(num)) + return; + + clientMissiles.type = SP_PARADISE_EXT1; + clientMissiles.subtype = SP_PE1_NUM_MISSILES; + clientMissiles.num = htons(num); + + sendClientPacket((struct player_spacket *) & clientMissiles); +} + +#ifdef RSA_EXEMPTION_FILE + +/* + * this code was copied from + * + * portname.c, part of faucet and hose: network pipe utilities Copyright (C) + * 1992 Robert Forsman + * + * He has granted the Paradise project permission to use this code for + * non-profit purposes. + * + */ + +int +convert_hostname(char *name, struct in_addr * addr) +{ + struct hostent *hp; + int len; + + hp = gethostbyname(name); + if (hp != NULL) + memcpy(addr, hp->h_addr, hp->h_length); + else + { + int count; + unsigned int a1, a2, a3, a4; + + count = sscanf(name, "%i.%i.%i.%i%n", &a1, &a2, &a3, &a4, &len); + + if (4 != count || 0 != name[len]) + return 0; + + addr->s_addr = (((((a1 << 8) | a2) << 8) | a3) << 8) | a4; + } + return 1; +} + +/* + * figure out if our client is exempt from RSA authentication. + * + * The host name resolution above doesn't handle gateways, which can have more + * than one internet address :/ + */ + +int +site_rsa_exempt() +{ + FILE *fp; + char buf[256]; + + if (remoteaddr == -1) + { + printf("remote address is not yet available?!\n"); + return 0; /* weird */ + } + + /* hopefully we've got the remote address at this point */ + + fp = fopen(build_path(RSA_EXEMPTION_FILE), "r"); + + if (!fp) + return 0; /* nobody is exempt */ + + while (fgets(buf, sizeof(buf), fp)) + { + char hostname[256]; + char *playername; + int len; + int i; + struct in_addr addr; + + len = strlen(buf); + + if (buf[len - 1] == '\n') + buf[len - 1] = 0; + + for (i = 0; buf[i] && !isspace(buf[i]); i++) + hostname[i] = buf[i]; + + hostname[i] = 0; /* hostname is copied to buffer */ + + while (buf[i] && isspace(buf[i])) + i++; + + playername = buf + i; /* player name is stuff after hostname */ + + if (!(*playername == 0 || strcmp(playername, me->p_name) == 0)) + continue; /* name didn't match */ + + /* + * shit, I gotta parse this crap myself. I'll steal this code from hose + * - RF + */ + if (!convert_hostname(hostname, &addr)) + { + printf("address in %s unparseable `%s'\n", + RSA_EXEMPTION_FILE, hostname); + continue; + } + + if (addr.s_addr == remoteaddr) + return 1; + } /* while (line in rsa-exempt file) */ + + fclose(fp); + + return 0; +} + +#endif /* RSA_EXEMPTION_FILE */