123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <netipx/ipx.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include "protocol.h"
- #define BACKUPTICS 12
- #define NCMD_EXIT 0x80000000
- #define NCMD_RETRANSMIT 0x40000000
- #define NCMD_SETUP 0x20000000
- #define NCMD_KILL 0x10000000 // kill game
- #define NCMD_CHECKSUM 0x0fffffff
- typedef struct
- {
- short gameid; // so multiple games can setup at once
- short drone;
- short nodesfound;
- short nodeswanted;
- } setupdata_t;
- typedef struct
- a
- {
- // High bit is retransmit request.
- unsigned checksum;
- // Only valid if NCMD_RETRANSMIT.
- byte retransmitfrom;
- byte starttic;
- byte player;
- byte numtics;
- ticcmd_t cmds[BACKUPTICS];
- } doomdata_t;
-
- typedef struct
- {
- signed int tic;
- union altu {
- setupdata_t s;
- unsigned char data[100];
- doomdata_t d;
- } u;
- } ipxpacket_t;
- int nodes;
- unsigned short port = 0x869b;
- int ipx_socket(void) {
- int s = socket(PF_IPX,SOCK_DGRAM,0);
- struct sockaddr_ipx sa;
- if (s == -1) {
- fprintf(stderr,"socket(PF_PIPX): %s\n",strerror(errno));
- exit(-1);
- }
- memset(&sa,0,sizeof(sa));
- memset(sa.sipx_node,0xff,sizeof(sa.sipx_node));
- sa.sipx_port = htons(port);
- if (bind(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
- fprintf(stderr,"bind(%d): %s\n",port,strerror(errno));
- exit(-1);
- }
- return s;
- }
- int udp_socket(const char* ip) {
- struct sockaddr_in sa;
- int s = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
- if (s == -1) {
- fprintf(stderr,"socket(PF_INET): %s\n", strerror(errno));
- exit(-1);
- }
- sa.sin_family=PF_INET;
- inet_aton(ip,&sa.sin_addr);
- sa.sin_port = htons(5030);
- if (connect(s,(struct sockaddr*)&sa,sizeof sa) == -1) {
- fprintf(stderr,"connect(%s:%d): %s\n", ip, 5030, strerror(errno));
- exit(-1);
- }
- return s;
- }
- static byte ChecksumPacket(const packet_header_t* buffer, size_t len)
- {
- const byte* p = (void*)buffer;
- byte sum = 0;
- if (len==0)
- return 0;
- while (p++, --len)
- sum += *p;
- return sum;
- }
- //
- // Checksum
- //
- unsigned NetbufferChecksum (void* p, size_t l)
- {
- unsigned c;
- c = 0x1234567;
- l = l/4;
- for (int i=0 ; i<l ; i++)
- c += ((unsigned *)p)[i] * (i+1);
- return c & NCMD_CHECKSUM;
- }
- int ipxs, udps;
- int consoleplayer;
- int basetic;
- int ExpandTics (int low, int maketic)
- {
- int delta;
-
- delta = low - (maketic&0xff);
-
- if (delta >= -64 && delta <= 64)
- return (maketic&~0xff) + low;
- if (delta > 64)
- return (maketic&~0xff) - 256 + low;
- if (delta < -64)
- return (maketic&~0xff) + 256 + low;
- fprintf(stderr,"ExpandTics strange value %i at maketic %i\n",low,maketic);
- exit(-2);
- }
- void send_udp_packet(enum packet_type_e type, unsigned tic, void* data, size_t len) {
- packet_header_t* p = calloc(sizeof(packet_header_t)+len+1,1);
- p->tic = doom_htonl(basetic = tic); p->type = type;
- if (!data) {
- data = (void*)&consoleplayer; len = 1;
- }
- memcpy(((char*)p)+sizeof(*p),data,len);
- p->checksum = ChecksumPacket(p,sizeof(packet_header_t)+len);
- write(udps,p,sizeof(packet_header_t)+len+1);
- }
- int connected;
- int ipxcounter;
- void ipx_receive(int s) {
- ipxpacket_t buf;
- int rc;
- struct sockaddr from;
- size_t sl = sizeof(from);
- rc = recvfrom(s,&buf,sizeof buf,0,&from,&sl);
- if (rc == -1) {
- fprintf(stderr,"read(ipx): %s\n", strerror(errno));
- exit(-2);
- }
- if (rc > 0) {
- if (buf.tic == -1) {
- // Setup packet
- if (!connected++) {
- connect(s,&from,sl);
- send_udp_packet(PKT_INIT,0,NULL,0);
- }
- } else {
- if (buf.u.d.checksum & NCMD_SETUP) {
- printf("setup packet, dropped\n");
- } else if (buf.u.d.checksum & NCMD_EXIT) {
- send_udp_packet(PKT_QUIT,buf.u.d.starttic,NULL,0);
- exit(0);
- } else if ((buf.u.d.checksum & NCMD_CHECKSUM) == buf.u.d.checksum) {
- // No flags, normal game packet
- char outbuf[100];
- int tics;
- outbuf[0] = tics = buf.u.d.numtics;
- outbuf[1] = buf.u.d.player;
- for (int i=0; i< tics; i++)
- TicToRaw(outbuf+2+i*sizeof(ticcmd_t),&buf.u.d.cmds[i]);
- send_udp_packet(PKT_TICC, ExpandTics(buf.u.d.starttic, basetic), outbuf, 2+tics*sizeof(ticcmd_t));
- }
- }
- }
- }
- void udp_receive(int s) {
- size_t len = 1024;
- packet_header_t *p = malloc(len);
- int rc;
-
- rc = read(s,p,len);
- if (rc < 0) {
- fprintf(stderr,"read(udp): %s\n", strerror(errno));
- exit(-2);
- }
- if (rc > 0) {
- switch (p->type) {
- case PKT_SETUP:
- {
- struct setup_packet_s *sinfo = (void*)(p+1);
- consoleplayer = sinfo->yourplayer;
- send_udp_packet(PKT_GO,0,NULL,0);
- write(ipxs,"\xff\xff\xff\xff\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00",16);
- }
- break;
- case PKT_GO:
- {
- ipxpacket_t pkt;
- memset(&pkt,0,sizeof(pkt));
- pkt.tic = ipxcounter++;
- pkt.u.d.player = consoleplayer^1;
- pkt.u.d.starttic = 0;
- pkt.u.d.numtics = 0;
- pkt.u.d.retransmitfrom = 0;
- pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, 4);
- write(ipxs,&pkt,16);
- }
- break;
- case PKT_TICS:
- {
- ipxpacket_t pkt;
- int tic = doom_ntohl(p->tic);
- byte *pp = (void*)(p+1);
- int tics = *pp++;
- memset(&pkt,0,sizeof(pkt));
- size_t len;
- pkt.tic = ipxcounter++;
- pkt.u.d.starttic = tic;
- pkt.u.d.player = (consoleplayer == 0 ? 1 : 0);
- pkt.u.d.numtics = tics;
- for (int t=0; t<tics; t++) {
- int players = *pp++;
- for (int i=0; i<players; i++) {
- if (*pp++ == pkt.u.d.player)
- RawToTic(&pkt.u.d.cmds[t],pp);
- pp += sizeof(ticcmd_t);
- }
- }
- pkt.u.d.retransmitfrom = 0;
- len = 12+tics*sizeof(ticcmd_t);
- len = (len+7)&0xff8; // round up to next 16
- pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, len-8);
- write(ipxs,&pkt,len);
- }
- }
- }
- }
- void loop(int ipxs, int udps) {
- for (;;) {
- struct timeval wt = {60,0};
- fd_set fds;
- int rc;
- FD_ZERO(&fds);
- FD_SET(ipxs,&fds);
- FD_SET(udps,&fds);
- rc = select(ipxs+udps,&fds,NULL,NULL,&wt);
- if (rc < 0) {
- fprintf(stderr,"select: %s\n", strerror(errno));
- exit(-2);
- }
- if (rc>0) {
- if (FD_ISSET(ipxs,&fds))
- ipx_receive(ipxs);
- if (FD_ISSET(udps,&fds))
- udp_receive(udps);
- }
- }
- }
- int main(int argc, char**argv) {
- ipxs = ipx_socket();
- udps = udp_socket(argv[1]);
- loop(ipxs,udps);
- return 0;
- }
|