mirror of
https://github.com/id-Software/DOOM-iOS.git
synced 2026-03-19 16:39:48 +01:00
The DOOM Classic for iPhone 1.0 source as released on November 3, 2009
This commit is contained in:
291
code/prboom/d_ipxgate.c
Normal file
291
code/prboom/d_ipxgate.c
Normal file
@@ -0,0 +1,291 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user