d_ipxgate.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <netipx/ipx.h>
  4. #include <errno.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <sys/socket.h>
  8. #include <sys/time.h>
  9. #include <sys/types.h>
  10. #include <netinet/in.h>
  11. #include <arpa/inet.h>
  12. #include "protocol.h"
  13. #define BACKUPTICS 12
  14. #define NCMD_EXIT 0x80000000
  15. #define NCMD_RETRANSMIT 0x40000000
  16. #define NCMD_SETUP 0x20000000
  17. #define NCMD_KILL 0x10000000 // kill game
  18. #define NCMD_CHECKSUM 0x0fffffff
  19. typedef struct
  20. {
  21. short gameid; // so multiple games can setup at once
  22. short drone;
  23. short nodesfound;
  24. short nodeswanted;
  25. } setupdata_t;
  26. typedef struct
  27. a
  28. {
  29. // High bit is retransmit request.
  30. unsigned checksum;
  31. // Only valid if NCMD_RETRANSMIT.
  32. byte retransmitfrom;
  33. byte starttic;
  34. byte player;
  35. byte numtics;
  36. ticcmd_t cmds[BACKUPTICS];
  37. } doomdata_t;
  38. typedef struct
  39. {
  40. signed int tic;
  41. union altu {
  42. setupdata_t s;
  43. unsigned char data[100];
  44. doomdata_t d;
  45. } u;
  46. } ipxpacket_t;
  47. int nodes;
  48. unsigned short port = 0x869b;
  49. int ipx_socket(void) {
  50. int s = socket(PF_IPX,SOCK_DGRAM,0);
  51. struct sockaddr_ipx sa;
  52. if (s == -1) {
  53. fprintf(stderr,"socket(PF_PIPX): %s\n",strerror(errno));
  54. exit(-1);
  55. }
  56. memset(&sa,0,sizeof(sa));
  57. memset(sa.sipx_node,0xff,sizeof(sa.sipx_node));
  58. sa.sipx_port = htons(port);
  59. if (bind(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
  60. fprintf(stderr,"bind(%d): %s\n",port,strerror(errno));
  61. exit(-1);
  62. }
  63. return s;
  64. }
  65. int udp_socket(const char* ip) {
  66. struct sockaddr_in sa;
  67. int s = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
  68. if (s == -1) {
  69. fprintf(stderr,"socket(PF_INET): %s\n", strerror(errno));
  70. exit(-1);
  71. }
  72. sa.sin_family=PF_INET;
  73. inet_aton(ip,&sa.sin_addr);
  74. sa.sin_port = htons(5030);
  75. if (connect(s,(struct sockaddr*)&sa,sizeof sa) == -1) {
  76. fprintf(stderr,"connect(%s:%d): %s\n", ip, 5030, strerror(errno));
  77. exit(-1);
  78. }
  79. return s;
  80. }
  81. static byte ChecksumPacket(const packet_header_t* buffer, size_t len)
  82. {
  83. const byte* p = (void*)buffer;
  84. byte sum = 0;
  85. if (len==0)
  86. return 0;
  87. while (p++, --len)
  88. sum += *p;
  89. return sum;
  90. }
  91. //
  92. // Checksum
  93. //
  94. unsigned NetbufferChecksum (void* p, size_t l)
  95. {
  96. unsigned c;
  97. c = 0x1234567;
  98. l = l/4;
  99. for (int i=0 ; i<l ; i++)
  100. c += ((unsigned *)p)[i] * (i+1);
  101. return c & NCMD_CHECKSUM;
  102. }
  103. int ipxs, udps;
  104. int consoleplayer;
  105. int basetic;
  106. int ExpandTics (int low, int maketic)
  107. {
  108. int delta;
  109. delta = low - (maketic&0xff);
  110. if (delta >= -64 && delta <= 64)
  111. return (maketic&~0xff) + low;
  112. if (delta > 64)
  113. return (maketic&~0xff) - 256 + low;
  114. if (delta < -64)
  115. return (maketic&~0xff) + 256 + low;
  116. fprintf(stderr,"ExpandTics strange value %i at maketic %i\n",low,maketic);
  117. exit(-2);
  118. }
  119. void send_udp_packet(enum packet_type_e type, unsigned tic, void* data, size_t len) {
  120. packet_header_t* p = calloc(sizeof(packet_header_t)+len+1,1);
  121. p->tic = doom_htonl(basetic = tic); p->type = type;
  122. if (!data) {
  123. data = (void*)&consoleplayer; len = 1;
  124. }
  125. memcpy(((char*)p)+sizeof(*p),data,len);
  126. p->checksum = ChecksumPacket(p,sizeof(packet_header_t)+len);
  127. write(udps,p,sizeof(packet_header_t)+len+1);
  128. }
  129. int connected;
  130. int ipxcounter;
  131. void ipx_receive(int s) {
  132. ipxpacket_t buf;
  133. int rc;
  134. struct sockaddr from;
  135. size_t sl = sizeof(from);
  136. rc = recvfrom(s,&buf,sizeof buf,0,&from,&sl);
  137. if (rc == -1) {
  138. fprintf(stderr,"read(ipx): %s\n", strerror(errno));
  139. exit(-2);
  140. }
  141. if (rc > 0) {
  142. if (buf.tic == -1) {
  143. // Setup packet
  144. if (!connected++) {
  145. connect(s,&from,sl);
  146. send_udp_packet(PKT_INIT,0,NULL,0);
  147. }
  148. } else {
  149. if (buf.u.d.checksum & NCMD_SETUP) {
  150. printf("setup packet, dropped\n");
  151. } else if (buf.u.d.checksum & NCMD_EXIT) {
  152. send_udp_packet(PKT_QUIT,buf.u.d.starttic,NULL,0);
  153. exit(0);
  154. } else if ((buf.u.d.checksum & NCMD_CHECKSUM) == buf.u.d.checksum) {
  155. // No flags, normal game packet
  156. char outbuf[100];
  157. int tics;
  158. outbuf[0] = tics = buf.u.d.numtics;
  159. outbuf[1] = buf.u.d.player;
  160. for (int i=0; i< tics; i++)
  161. TicToRaw(outbuf+2+i*sizeof(ticcmd_t),&buf.u.d.cmds[i]);
  162. send_udp_packet(PKT_TICC, ExpandTics(buf.u.d.starttic, basetic), outbuf, 2+tics*sizeof(ticcmd_t));
  163. }
  164. }
  165. }
  166. }
  167. void udp_receive(int s) {
  168. size_t len = 1024;
  169. packet_header_t *p = malloc(len);
  170. int rc;
  171. rc = read(s,p,len);
  172. if (rc < 0) {
  173. fprintf(stderr,"read(udp): %s\n", strerror(errno));
  174. exit(-2);
  175. }
  176. if (rc > 0) {
  177. switch (p->type) {
  178. case PKT_SETUP:
  179. {
  180. struct setup_packet_s *sinfo = (void*)(p+1);
  181. consoleplayer = sinfo->yourplayer;
  182. send_udp_packet(PKT_GO,0,NULL,0);
  183. write(ipxs,"\xff\xff\xff\xff\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00",16);
  184. }
  185. break;
  186. case PKT_GO:
  187. {
  188. ipxpacket_t pkt;
  189. memset(&pkt,0,sizeof(pkt));
  190. pkt.tic = ipxcounter++;
  191. pkt.u.d.player = consoleplayer^1;
  192. pkt.u.d.starttic = 0;
  193. pkt.u.d.numtics = 0;
  194. pkt.u.d.retransmitfrom = 0;
  195. pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, 4);
  196. write(ipxs,&pkt,16);
  197. }
  198. break;
  199. case PKT_TICS:
  200. {
  201. ipxpacket_t pkt;
  202. int tic = doom_ntohl(p->tic);
  203. byte *pp = (void*)(p+1);
  204. int tics = *pp++;
  205. memset(&pkt,0,sizeof(pkt));
  206. size_t len;
  207. pkt.tic = ipxcounter++;
  208. pkt.u.d.starttic = tic;
  209. pkt.u.d.player = (consoleplayer == 0 ? 1 : 0);
  210. pkt.u.d.numtics = tics;
  211. for (int t=0; t<tics; t++) {
  212. int players = *pp++;
  213. for (int i=0; i<players; i++) {
  214. if (*pp++ == pkt.u.d.player)
  215. RawToTic(&pkt.u.d.cmds[t],pp);
  216. pp += sizeof(ticcmd_t);
  217. }
  218. }
  219. pkt.u.d.retransmitfrom = 0;
  220. len = 12+tics*sizeof(ticcmd_t);
  221. len = (len+7)&0xff8; // round up to next 16
  222. pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, len-8);
  223. write(ipxs,&pkt,len);
  224. }
  225. }
  226. }
  227. }
  228. void loop(int ipxs, int udps) {
  229. for (;;) {
  230. struct timeval wt = {60,0};
  231. fd_set fds;
  232. int rc;
  233. FD_ZERO(&fds);
  234. FD_SET(ipxs,&fds);
  235. FD_SET(udps,&fds);
  236. rc = select(ipxs+udps,&fds,NULL,NULL,&wt);
  237. if (rc < 0) {
  238. fprintf(stderr,"select: %s\n", strerror(errno));
  239. exit(-2);
  240. }
  241. if (rc>0) {
  242. if (FD_ISSET(ipxs,&fds))
  243. ipx_receive(ipxs);
  244. if (FD_ISSET(udps,&fds))
  245. udp_receive(udps);
  246. }
  247. }
  248. }
  249. int main(int argc, char**argv) {
  250. ipxs = ipx_socket();
  251. udps = udp_socket(argv[1]);
  252. loop(ipxs,udps);
  253. return 0;
  254. }