You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

matcher.c 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/uio.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <netdb.h>
  10. #include <sys/timeb.h>
  11. #include <sys/time.h>
  12. #include <time.h>
  13. #include <signal.h>
  14. #include <fcntl.h>
  15. #define MAXMSG 256
  16. #define PORT 5521
  17. #define TIMETOLIVE 600 // seconds
  18. typedef unsigned char uchar;
  19. char logging=0;
  20. unsigned char mesg[MAXMSG];
  21. int lastsize;
  22. int network;
  23. char masterhostname[256];
  24. #define PKT_REGISTER 16
  25. #define PKT_ACK 24
  26. #define PKT_INFO 40
  27. #define PKT_QUERY 32
  28. #define MAXMATCHES 16
  29. struct registration
  30. {
  31. uchar id;
  32. uchar unique[4];
  33. uchar password[4];
  34. uchar version[4];
  35. uchar name[16];
  36. uchar status;
  37. };
  38. struct query
  39. {
  40. uchar id;
  41. uchar password[4];
  42. uchar version[4];
  43. };
  44. struct gamehost
  45. {
  46. struct gamehost *next,*prev;
  47. uchar machine[4];
  48. uchar port[2];
  49. struct registration reg;
  50. long timeout;
  51. };
  52. struct gamehost *freehosts=0,*activehosts=0;
  53. int udpsocket,myport;
  54. struct sockaddr_in myname={0},mastername={0};
  55. socklen_t senderlength;
  56. struct sockaddr_in sender={0};
  57. long longtime(void)
  58. {
  59. struct timeb tb;
  60. ftime(&tb);
  61. return tb.time;
  62. }
  63. char *timestr()
  64. {
  65. static char timestring[80];
  66. time_t t;
  67. int l;
  68. time(&t);
  69. strcpy(timestring,ctime(&t));
  70. l=strlen(timestring);
  71. if(l && timestring[l-1]=='\n') timestring[l-1]=0;
  72. return timestring;
  73. }
  74. int putmsg(struct sockaddr_in *toname,unsigned char *msg,int len)
  75. {
  76. int status;
  77. status=sendto(udpsocket,msg,len,0,
  78. (struct sockaddr *)toname,sizeof(struct sockaddr_in));
  79. return status;
  80. }
  81. void ack()
  82. {
  83. uchar copy[256];
  84. *copy=PKT_ACK;
  85. memmove(copy+1,mesg,lastsize);
  86. putmsg(&sender,copy,lastsize+1);
  87. }
  88. int getmsg(int seconds)
  89. {
  90. int size;
  91. lastsize=-1;
  92. memset(&sender,0,sizeof(sender));
  93. senderlength=sizeof(sender);
  94. if(seconds)
  95. {
  96. struct timeval timeout;
  97. fd_set readfds;
  98. int res;
  99. timeout.tv_sec=seconds;
  100. timeout.tv_usec=0;
  101. FD_ZERO(&readfds);
  102. FD_SET(udpsocket,&readfds);
  103. res=select(udpsocket+1,&readfds,0,0,&timeout);
  104. if(res<=0) return -1;
  105. }
  106. lastsize=size=recvfrom(udpsocket,mesg,MAXMSG,0,
  107. (struct sockaddr *)&sender,&senderlength);
  108. return size;
  109. }
  110. long longind(unsigned char *p)
  111. {
  112. return (p[0]<<24L) | (p[1]<<16L) | (p[2]<<8) | p[3];
  113. }
  114. short shortind(unsigned char *p)
  115. {
  116. return (p[0]<<8L) | p[1];
  117. }
  118. void openport(int portwant)
  119. {
  120. int status;
  121. myport=portwant;
  122. udpsocket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
  123. if(udpsocket==-1)
  124. {
  125. perror("socket()");
  126. exit(1);
  127. }
  128. memset(&myname,0,sizeof(myname));
  129. myname.sin_family=AF_INET;
  130. myname.sin_addr.s_addr=htonl(INADDR_ANY);
  131. myname.sin_port=htons(myport);
  132. status=bind(udpsocket,(struct sockaddr *) &myname,sizeof(myname));
  133. if(status==-1)
  134. {
  135. perror("bind()");
  136. exit(1);
  137. }
  138. }
  139. #define PERBLOCK 512
  140. struct gamehost *newhost()
  141. {
  142. struct gamehost *h,*block;
  143. int i;
  144. if(!freehosts)
  145. {
  146. block=malloc(sizeof(struct gamehost)*PERBLOCK);
  147. if(!block) return 0;
  148. freehosts=block;
  149. i=PERBLOCK-1;
  150. while(i--)
  151. {
  152. block->next=block+1;
  153. ++block;
  154. }
  155. block->next=0;
  156. }
  157. h=freehosts;
  158. freehosts=freehosts->next;
  159. memset(h,0,sizeof(struct gamehost));
  160. return h;
  161. }
  162. void freehost(struct gamehost *h)
  163. {
  164. h->next=freehosts;
  165. freehosts=h;
  166. }
  167. struct gamehost *findmatch(struct registration *key)
  168. {
  169. struct gamehost *h;
  170. h=activehosts;
  171. while(h)
  172. {
  173. if(!memcmp(&h->reg,key,sizeof(struct registration)-1))
  174. return h;
  175. h=h->next;
  176. }
  177. return 0;
  178. }
  179. void insert(struct gamehost *h)
  180. {
  181. if(activehosts)
  182. {
  183. h->next=activehosts;
  184. h->prev=activehosts->prev;
  185. activehosts->prev=h;
  186. activehosts=h;
  187. } else
  188. {
  189. h->next=h->prev=0;
  190. activehosts=h;
  191. }
  192. }
  193. void delete(struct gamehost *h)
  194. {
  195. if(h->prev)
  196. h->prev->next=h->next;
  197. else
  198. activehosts=h->next;
  199. if(h->next)
  200. h->next->prev=h->prev;
  201. freehost(h);
  202. }
  203. void doreg()
  204. {
  205. struct registration *new;
  206. struct gamehost *match;
  207. long now;
  208. new=(struct registration *)mesg;
  209. match=findmatch(new);
  210. if(logging)
  211. {
  212. unsigned addr=ntohl(sender.sin_addr.s_addr);
  213. unsigned short port=ntohs(sender.sin_port);
  214. printf("reg :%s:%d.%d.%d.%d:%d %c%lx '%s'\n",timestr(),
  215. (addr>>24)&255,(addr>>16)&255,(addr>>8)&255,addr&255,port,
  216. new->status ? '+' : '-',(long)match,new->name);
  217. fflush(stdout);
  218. }
  219. if(!match && !new->status) {ack();return;}
  220. if(match && new->status) {ack();return;}
  221. if(!match && new->status)
  222. {
  223. match=newhost();
  224. if(!match) return; // No memory, what can we do?
  225. memmove(match->machine,&sender.sin_addr.s_addr,4);
  226. memmove(match->port,&sender.sin_port,2);
  227. match->reg=*new;
  228. now=longtime();
  229. match->timeout=now+TIMETOLIVE;
  230. ack();
  231. insert(match);
  232. return;
  233. } else // match && !new->status
  234. {
  235. delete(match);
  236. ack();
  237. return;
  238. }
  239. }
  240. void doquery()
  241. {
  242. uchar *password;
  243. uchar *version;
  244. struct gamehost *h;
  245. uchar response[2048],*rput,*countersave;
  246. int counter;
  247. if(logging)
  248. {
  249. unsigned addr=ntohl(sender.sin_addr.s_addr);
  250. unsigned short port=ntohs(sender.sin_port);
  251. printf("query:%s:%d.%d.%d.%d:%d\n",timestr(),
  252. (addr>>24)&255,(addr>>16)&255,(addr>>8)&255,addr&255,port);
  253. fflush(stdout);
  254. }
  255. password=mesg+1;
  256. version=mesg+5;
  257. h=activehosts;
  258. rput=response;
  259. *rput++=PKT_INFO;
  260. memmove(rput,password,4);
  261. rput+=4;
  262. memmove(rput,version,4);
  263. rput+=4;
  264. countersave=rput;
  265. *rput++=0;
  266. *rput++=0;
  267. counter=0;
  268. while(h)
  269. {
  270. if(!memcmp(password,h->reg.password,4) &&
  271. !memcmp(version,h->reg.version,4) && counter<MAXMATCHES)
  272. {
  273. ++counter;
  274. memmove(rput,h->reg.unique,4);
  275. rput+=4;
  276. memmove(rput,h->machine,4);
  277. rput+=4;
  278. memmove(rput,h->port,2);
  279. rput+=2;
  280. memmove(rput,h->reg.name,sizeof(h->reg.name));
  281. rput+=sizeof(h->reg.name);
  282. }
  283. h=h->next;
  284. }
  285. *countersave++=counter>>8;
  286. *countersave++=counter;
  287. putmsg(&sender,response,rput-response);
  288. }
  289. void purge(long cutoff)
  290. {
  291. struct gamehost *h,*h2;
  292. h=activehosts;
  293. while(h)
  294. {
  295. h2=h;
  296. h=h->next;
  297. if(cutoff-h2->timeout>0)
  298. {
  299. delete(h2);
  300. }
  301. }
  302. }
  303. int main(int argc,char **argv)
  304. {
  305. int i;
  306. int want;
  307. int size;
  308. long purgetime;
  309. long now;
  310. want=PORT;
  311. if(argc>1)
  312. {
  313. for(i=1;i<argc;++i)
  314. if(!strncmp(argv[i],"-p",2))
  315. {
  316. if(strlen(argv[i])>2) want=atoi(argv[i]+2);
  317. else if(i+1<argc) want=atoi(argv[i+1]);
  318. }
  319. }
  320. freehosts=0;
  321. openport(want);
  322. purgetime=longtime()+TIMETOLIVE;
  323. for(;;)
  324. {
  325. size=getmsg(10);
  326. if(size>=1)
  327. switch(*mesg)
  328. {
  329. case PKT_REGISTER:
  330. if(size<sizeof(struct registration)) continue;
  331. doreg();
  332. break;
  333. case PKT_QUERY:
  334. if(size<sizeof(struct query)) continue;
  335. doquery();
  336. break;
  337. }
  338. now=longtime();
  339. if(now-purgetime>0) // avoid year 203x bug...
  340. {
  341. purge(purgetime);
  342. purgetime+=TIMETOLIVE;
  343. }
  344. }
  345. }