001 #exe {Cd(__DIR__);};;
002 #include "MainDrawer.HC";
003 U0 PrintI(U8 *s,I64 l) {
004   DbgPrint("%s:%d\n",s,l);
005 }
006 #define GAME_LIST_PORT 7000
007 
008 class CListClient:CQue {
009   I64 socket;
010   I64 host_game_at_port;
011   I64 connected; //This will close da connection
012   U8 host_game_wad[STR_LEN];
013   U8 host_game_desc[STR_LEN];
014 };
015 U0 SendString(I64 sock,U8 *fmt,...) {
016   U32 l;
017   fmt=StrPrintJoin(NULL,fmt,argc,argv);
018   l=StrLen(fmt);
019   send(sock,&l,4,0);
020   send(sock,fmt,l,0);
021   Free(fmt);
022 }
023 U8 *ReceiveString(I64 sock) {
024   U32 len;
025   I64 h=recv(sock,&len,4,0);
026   if(4!=h)
027     return NULL;
028   U8 *ret=CAlloc(len+1);
029   I64 got=recv(sock,ret,len,0);
030   if(len!=got) {
031     Free(ret);
032     return NULL;
033   }
034   return ret;
035 }
036 U0 ServerIncomingTask(CListClient *cl) {
037   U32 len;
038   I64 host_at,wad_hash;
039   U8 *body,*_body,*tmp;
040   U8 command[STR_LEN],*ptr,*ptr2;
041   CListClient *clients=FramePtr("Clients"),*client;
042   while(_body=ReceiveString(cl->socket)) {
043     body=_body;
044     ptr=command;
045     body=StrScan(body,"%s:",&ptr);
046     if(!StrCmp(command,"LIST")) {
047       for(client=clients->next;client!=clients;client=client->next) {
048         if(client->host_game_wad[0]&&client->host_game_at_port) {
049           SendString(cl->socket,"GAME:%s(%s):%d\n",
050                 client->host_game_wad,
051                 client->host_game_desc,
052                 client->host_game_at_port);
053         }
054       }
055       SendString(cl->socket,"DONE:");
056     } else if(!StrCmp(command,"HOST")) {
057       ptr=&cl->host_game_wad;
058       ptr2=&cl->host_game_desc;
059       body=StrScan(body,"%s(%s):%d\n",&ptr,&ptr2,&wad_hash);
060       tmp=MStrPrint("   RemoveHost(0x%X\n);\n",cl);
061       FramePtrAdd("SLIM_PROX_EXIT_CB",tmp);
062       SlimProxServerTask(cl->socket,&cl->host_game_at_port);
063       Free(_body);
064       return;
065     }
066     Free(_body);
067   }
068   QueRem(cl);
069   close(cl->socket);
070   Free(cl);
071 }
072 U0 ServerTaskEnd() {
073   CListClient *clients=FramePtr("Clients"),*client;
074   for(client=clients->next;client!=clients;client=client->next) {
075     close(client->socket);
076   }
077   QueDel(clients);
078   Free(clients);
079   close(FramePtr("ListenSock"));
080   Exit;
081 }
082 U0 ServerTask(U8 *at="0.0.0.0") {
083   I64 listen_sock=create_server("0.0.0.0",GAME_LIST_PORT,21 /* Savage */ );
084   I64 who;
085   CListClient *clients=CAlloc(sizeof CQue),*poo;
086   QueInit(clients);
087   FramePtrAdd("ListenSock",listen_sock);
088   FramePtrAdd("Clients",clients);
089   Fs->task_end_cb=&ServerTaskEnd;
090   while(who=accept(listen_sock,NULL,0)) {
091     if(who>0) {
092       poo=CAlloc(sizeof CListClient);
093       poo->socket=who;
094       QueIns(poo,clients);
095       Spawn(&ServerIncomingTask,poo,,,Fs);
096     }
097     Sleep(3);
098   }
099 }
100 U0 HostGameBrowser(U8 *at="0.0.0.0") {
101   CTask *t=Spawn(&ServerTask,at,,,Fs);
102   "Press a key to stop serving\n";
103   PressAKey;
104   Kill(t,FALSE);
105 }
106 class CHostGameData {
107   U8 game_wad[STR_LEN] format "$DA-P,A=\"DoomWad   :%s\"$\n";
108   U8 game_pwad[STR_LEN] format "$DA-P,A=\"PWad   :%s\"$\n";
109   U8 name[STR_LEN] format "$DA-P,A=\"Name   :%s\"$\n";
110   U8 desc[STR_LEN] format "$DA-P,A=\"Desciption   :%s\"$\n";
111   Bool just_serve format "$CB,\"Just Serve:\"$\n";
112   I64 wad_hash;
113 };
114 U0 RemoveHost(CListClient *cl) {
115   QueRem(cl);
116   Free(cl);
117 }
118 U0 HostGame(I64 sock) {
119   CHostGameData data;
120   CTask *me;
121   U8 *map,*tmp;
122   if(!FramePtr("USE_WAD")) {
123     PopUpOk("Can't find a Doom WAD to use!!\n");
124     throw('Wad');
125   }
126   StrCpy(&data.game_wad,FramePtr("USE_WAD"));
127   StrCpy(&data.name,"Untitled");
128   StrCpy(&data.desc,"");
129   StrCpy(&data.game_pwad,"");
130   data.just_serve=FALSE;
131   data.wad_hash=0;
132   DocForm(&data,,0,"$PURPLE$$TX+C,\"Host a game of Doom.\"$$FD$\n");
133   SendString(sock,"HOST:%s:%s(%s):%d\n",data.game_wad,data.game_pwad,data.name,data.wad_hash);
134   if(W_GetLumpPtrFromName("E1M1")) {
135     map="E1M1";
136   } else if(W_GetLumpPtrFromName("MAP01")) {
137     map="MAP01";
138   } else {
139     PopUpOk("I can't find the first level!!!\n");
140      throw('Wad');
141   }
142   FramePtrAdd("SLIM_PROX",1);
143   FramePtrAdd("SLIM_PROX_SOCK",sock);
144   if(!data.just_serve) {
145     me=User;
146     FramePtrAdd("SLIM_PROX",1,me);
147     FramePtrAdd("SLIM_PROX_USE_DUMB_SOCK",1,me);
148     WinMax(me);
149     XTalk(me,"#include \"%Q/MPClient\";;\n",__DIR__);
150   }
151 //See SlimProx.HC
152   PrintI(" serce",1);
153   ServeGame(map ,4);
154   Beep;
155   close(sock);
156 }
157 U0 DeleteBranch(CDoc *doc,U8 *who) {
158   CDocEntry *br,*st,*en;
159   if(DocTreeFind(doc,who,&br,&st,&en)) {
160     DocCut(doc,br,en);
161   }
162 }
163 //Returns server port
164 I64 ServerBrowser(U8 *server="0.0.0.0") {
165   F64 next_refresh_tS=0;
166   CI64Set *games=I64SetNew;
167   CI64Set *old_games=I64SetNew;
168   CDoc *doc=DocPut;
169   Bool continue=TRUE;
170   I64 msg,m1,m2,idx;
171   I64 listen_sock=create_connection(server,GAME_LIST_PORT);
172   U8 *buf,*_buf;
173   U8 wad[STR_LEN],*ptr,*wad_ptr=wad;
174   U8 pwad[STR_LEN],*pwad_ptr=pwad;
175   U8 desc[STR_LEN],*ptr2,*desc_ptr=desc;
176   I64 port,has_action;
177   DocClear;
178   DocPrint(doc,"$LTPURPLE$$TX+C+H,\"Listing of %Q\"$$FD$\n",server);
179   DocPrint(doc,"\n\n$BT+H+PU,\"Host game\",LM=\"HostGame(%d);\\n\"\n\n$",listen_sock);
180   while(continue) {
181     if(next_refresh_tS<tS) {
182       next_refresh_tS=tS+1.;
183       SendString(listen_sock,"LIST:");
184       old_games->cnt=0;
185       for(idx=0;idx!=games->cnt;idx++) {
186         I64SetAdd(old_games,games->body[idx]);
187       }
188       games->cnt=0;
189       while(buf=ReceiveString(listen_sock)) {
190         _buf=buf;
191         if(!StrNCmp("GAME:",_buf,5)) {
192           buf+=5;
193           ptr=StrNew(buf);
194           for(idx=0;idx!=old_games->cnt;idx++) {
195             if(!StrCmp(ptr,ptr2=old_games->body[idx])) {
196               I64SetRem(old_games,ptr2);
197               Free(ptr2);
198               I64SetAdd(games,ptr);
199               goto skip;
200             }
201           }
202           I64SetAdd(games,ptr);
203           StrScan(buf,"%s:%s(%s):%d\n",&wad_ptr,&pwad_ptr,&desc_ptr,&port);
204           if(!*pwad_ptr)
205             ptr=MStrPrint("%Q:%d/%Q",wad,port,desc);
206           else
207             ptr=MStrPrint("%Q(%Q):%d/%Q",wad,pwad,port,desc);
208 
209           if(!DocTreeFind(doc,ptr)) {
210             DocTreeWrite(doc,ptr,FALSE,"\n\n$BT,\"Join Game\",LM=\"PlayNetworkGame(\\\"%Q\\\",%d);\n;\"$\n\n",server,port);
211             DocCollapse(FALSE,doc);
212           }
213           Free(ptr);
214 skip:
215         } else if(!StrNCmp("DONE:",_buf,5)) {
216           for(idx=0;idx!=old_games->cnt;idx++) {
217             ptr=old_games->body[idx];
218             StrScan(ptr,"%s:%s(%s):%d\n",&wad_ptr,&pwad_ptr,&desc_ptr,&port);
219             if(!*pwad_ptr)
220               ptr2=MStrPrint("%Q:%d/%Q",wad,port,desc);
221             else
222               ptr2=MStrPrint("%Q(%Q):%d/%Q",wad,pwad,port,desc);
223             DeleteBranch(doc,ptr2);
224             Free(ptr2);
225             Free(ptr);
226           }
227           old_games->cnt=0;
228           Free(_buf);
229           break;
230         }
231         Free(_buf);
232       }
233     }
234     if(MSG_KEY_DOWN==ScanMsg(&m1,&m2)) {
235       if(m1==' '||m1=='\n'||m1==CH_ESC) {
236         DocEntryRun(doc,doc->cur_entry,FALSE,&has_action);
237         if(has_action||m1==CH_ESC) {
238           break;
239         }
240       }
241       DocPutKey(doc,m1,m2);
242     }
243     Refresh;
244   }
245   m1=games->cnt;
246   while(--m1>=0)
247     Free(games->body[m1]);
248   I64SetDel(games);
249 }
250 #if __CMD_LINE__
251 ServerBrowser("aiwnios.com");
252 //ServerBrowser("0.0.0.0");
253 #endif