/* master.c Quakeworld master server Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ /* afternoon hack (james was here.) FIXME: I coded this outside of the QF tree so it has non-quake stuff like malloc and things... ie, it's POSIX, not quake. */ #include #include #include #include #include #include #include #include #include #if 0 #define S2C_CHALLENGE 'c' #define S2M_HEARTBEAT 'a' #define S2M_SHUTDOWN 'C' #endif #ifndef MASTER_TIMEOUT # define MASTER_TIMEOUT 300 #endif typedef struct { struct sockaddr_in addr; time_t updated; } server_t; int QW_AddHeartbeat(server_t **servers_p, int slen, struct sockaddr_in *addr) { server_t *servers=*servers_p; int freeslot=-1; int i; for (i=0;isin_addr.s_addr && servers[i].addr.sin_port == addr->sin_port ) { time(&servers[i].updated); #if 1 printf("Refreshed %s:%d\n", inet_ntoa(servers[i].addr.sin_addr), ntohs(servers[i].addr.sin_port)); #endif return slen; } else if (freeslot==-1 && servers[i].updated==0) { freeslot=i; } } if (freeslot==-1) { server_t *newservers; newservers=(server_t*)realloc(servers,sizeof(server_t)*(slen+50)); if (newservers==NULL) { return slen; // boo. } for (i=slen;isin_addr.s_addr && servers[i].addr.sin_port == addr->sin_port) { servers[i].updated=0; #if 1 printf("Removed %s:%d\n", inet_ntoa(servers[i].addr.sin_addr), ntohs(servers[i].addr.sin_port)); #endif return; } } } void QW_SendHearts(int sock,struct sockaddr_in *addr, server_t *servers, int serverlen) { unsigned char *out; int count,cpos; int i; count=0; for (i=0;i> 8); p[5]=(unsigned char)(ntohs(servers[i].addr.sin_port) & 0xFF); ++cpos; } } sendto(sock,out,count*6*sizeof(unsigned char),0, (struct sockaddr*)addr,sizeof(struct sockaddr_in)); free(out); } void QW_Master(struct sockaddr_in *addr) { int sock; server_t *servers=(server_t*)malloc(sizeof(server_t)*50); int serverlen=50; int i; if (servers==NULL) return; for (i=0;i<50;i++) { servers[i].updated=0; } sock=socket(AF_INET,SOCK_DGRAM,0); if (sock<0) { return; } if (bind(sock,(struct sockaddr*)addr,sizeof(struct sockaddr_in))!=0) return; listen(sock,4); // probably don't need this. while (1) { char buf[3]; struct sockaddr_in recvaddr; int recvsize; recvfrom(sock,buf,3,0,(struct sockaddr*)&recvaddr,&recvsize); printf("Got 0x%x\n",buf[0]); QW_TimeoutHearts(servers,serverlen); switch (buf[0]) { case S2C_CHALLENGE: QW_SendHearts(sock,&recvaddr,servers,serverlen); break; case S2M_HEARTBEAT: serverlen=QW_AddHeartbeat(&servers,serverlen,&recvaddr); break; case S2M_SHUTDOWN: QW_HeartShutdown(&recvaddr,servers,serverlen); break; } } free(servers); } int main(int argc, char **argv) { int c; struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(27000); while ((c=getopt(argc,argv,"p:"))!=-1) { if (c=='p') { addr.sin_port = htons(atoi(optarg)); } } QW_Master(&addr); return 0; }