001 #exe {FramePtrAdd("OLD_DIR",__DIR__);Cd(__DIR__);};
002 #exe { // useful for dynamic includes, eg CrossNetShims
003   Bool a,e;
004   Bool _FindDef(U8 *nam,U8 *fmt,...) {
005     Bool ret;
006     U8 *s=StrPrintJoin(NULL,fmt,argc,argv);
007     if (ret=!!HashFind(nam,Fs->hash_table,HTT_DEFINE_STR))
008       StreamPrint("%s;;\n",s);
009     Free(s);
010     return ret;
011   }
012   a=_FindDef("__AIWNIOS__","\"Running on Aiwnios\\n\";\n");
013   e=_FindDef("__EXODUS","\"Running on Exodus\\n\";\n");
014   if (!a && !e) {
015     StreamPrint("\"Possibly stock TempleOS\\n\";\n");
016     StreamPrint("#include \"CrossNetShims/Generic.HC\";;\n");
017   } else if(a) {
018     StreamPrint("#include \"CrossNetShims/Aiwnios2.HC\";;\n");
019   } else if(e) {
020     StreamPrint("#include \"CrossNetShims/EXODUS.HC\";;\n");
021   }
022 };;
023 #exe{
024   Cd(FramePtr("OLD_DIR"));
025   FramePtrDel("OLD_DIR");
026 }
027 I64 ForceSend(I64 sock,U8 *buf,I64 len,U64 ul=0) {
028   I64 sent;
029   I64 olen=len;
030   while(len>0) {
031     sent=send(sock,buf,len,ul);
032      if(sent<0) {
033       return -1;
034     }
035     buf+=sent;
036     len-=sent;
037     if(len)
038       Yield;
039   }
040   return olen;
041 }
042 I64 ForceRecv(I64 sock,U8 *buf,I64 len,U64 ul=0) {
043   I64 got;
044   I64 olen=len;
045   while(len>0) {
046     got=recv(sock,buf,len,ul);
047     if(got<0) {
048       return -1;
049     }
050     buf+=got;
051     len-=got;
052     if(len)
053       Yield;
054   }
055   return olen;
056 }
057 CTask *slim_prox_task=Fs;
058 class CSlimProxSock {
059   I64 proxy,lock;
060   CSlimProxSock *parent;
061   union {
062     CFifoU8 *read_fifo;
063     CFifoI64 *accept_fifo;
064   };
065   CFifoU8 *write_fifo;
066   CI64Set *children;
067   Bool closed;
068 //is_dumb is for SlimProxDumbCreateConnection()
069   Bool is_dumb;
070 };
071 #define SLIM_PROX_WRITE 1
072 #define SLIM_PROX_ACCEPT 2
073 #define SLIM_PROX_DISCONNECT 3
074 I64 class CSlimProxHeader {
075   U8 ident;
076   U8 pad;
077   U16 who;
078   U32 size;
079 };
080 U0 SlimProxTaskRead(CSlimProxSock *root_sock) {
081   CSlimProxHeader hdr;
082   CSlimProxSock **socks,*who;
083   I64 cnt=0,got;
084   U8 buf[0x20000],*ptr;
085   while(TRUE) {
086     got=ForceRecv(root_sock->proxy,&hdr,sizeof(CSlimProxHeader),0);
087     if(sizeof(CSlimProxHeader)==got) {
088       cnt=hdr.size;
089       switch(hdr.ident) {
090         case SLIM_PROX_DISCONNECT: {
091           if(hdr.who<root_sock->children->cnt) {
092             who=root_sock->children->body[hdr.who];
093             if(who) {
094               who->closed=TRUE;
095             }
096           }
097         }
098         break;
099         case SLIM_PROX_ACCEPT: {
100           who=CAlloc(sizeof(CSlimProxSock),Fs->parent_task);
101           if(FifoI64Ins(root_sock->accept_fifo,who)) {
102             who->parent=root_sock;
103             who->children=I64SetNew();
104             who->write_fifo=FifoU8New(1<<20,Fs->parent_task);
105             who->read_fifo=FifoU8New(1<<20,Fs->parent_task);
106             I64SetAdd(root_sock->children,who);
107           } else {
108             Free(who);
109           }
110         }
111         break;
112         case SLIM_PROX_WRITE: {
113           if(hdr.who<root_sock->children->cnt) {
114             who=root_sock->children->body[hdr.who];
115             if(who)
116              while(cnt>0) {
117               got=ForceRecv(root_sock->proxy,buf,MinI64(cnt,0x20000),0);
118               if(got<=0)
119                 goto fin;
120               if(got>0) 
121                 cnt-=got;
122               ptr=buf;
123               while(--got>=0) {
124                 while(!FifoU8Ins(who->read_fifo,*ptr))
125                   Sleep(1);
126                 ++ptr;
127               } 
128             }
129           }
130         }
131         break;
132         default:
133         goto fin;
134         break;
135       }
136     } else
137         break;
138   }
139 fin:;
140   if(ptr=FramePtr("SLIM_PROX_EXIT_CB")) {
141     ExePutS(ptr);
142   }
143 }
144 U0 SlimProxTaskWrite(CSlimProxSock *root_sock) {
145   I64 cnt=0;
146   CSlimProxSock **socks;
147   U8 buf[0x20000],*ptr;
148   CSlimProxHeader hdr;
149   while(TRUE) {
150 again:
151     if(root_sock->children) {
152       cnt=root_sock->children->cnt;
153       socks=root_sock->children->body;
154       while(--cnt>=0) {
155         if(!socks[cnt]->closed&&!socks[cnt]->is_dumb) {
156           ptr=buf;
157           while(FifoU8Rem(socks[cnt]->write_fifo,ptr)) {
158             ptr++;
159           }
160           if(ptr!=&buf) {
161             hdr.ident=SLIM_PROX_WRITE;
162             hdr.who=cnt;
163             hdr.size=ToI64(ptr)-ToI64(&buf);
164             ForceSend(root_sock->proxy,&hdr,sizeof(CSlimProxHeader),0);
165             ForceSend(root_sock->proxy,buf,hdr.size,0);
166           }
167         }
168       }
169     }
170     Sleep(1);
171   }
172 }
173 
174 I64 SlimProxDumbCreateConnection() {
175 again:;
176   CSlimProxSock *root_sock=FramePtr("DUMB_SLIM_PROX_ROOT",adam_task),*who;
177   if(!root_sock) {
178     Sleep(1); 
179     goto again;
180   }
181   FramePtrAdd("SLIM_PROX",1);
182   FramePtrAdd("SLIM_PROX_IS_DUMB",1);
183   who=CAlloc(sizeof(CSlimProxSock));
184   who->is_dumb=TRUE;
185   who->parent=root_sock;
186   who->children=I64SetNew();
187   who->write_fifo=FifoU8New(1<<20,Fs->parent_task);
188   who->read_fifo=FifoU8New(1<<20,Fs->parent_task);
189   I64SetAdd(root_sock->children,who);
190   FifoI64Ins(root_sock->accept_fifo,who);
191   return who;
192 }
193 
194 
195 
196 CSlimProxSock *SlimProxCreateConnection(U8 *at,I64 port) {
197   if(FramePtr("SLIM_PROX_USE_DUMB_SOCK"))
198     return SlimProxDumbCreateConnection;
199   if(FramePtr("SLIM_PROX")) {
200     "Only servers use slim-proxy,clients connect throug tha main server.\n";
201     throw('AssPony');
202   }
203   return create_connection(at,port);
204 }
205 U0 ServerCleanup() {
206   FramePtrDel("DUMB_SLIM_PROX_ROOT",adam_task);
207   Exit;
208 }
209 CSlimProxSock *SlimProxCreateServer(U8 *at,I64 port,I64 bl) {
210   if(!FramePtr("SLIM_PROX"))
211     return create_server(at,port,bl);
212   if(!FramePtr("SLIM_PROX_SOCK")) 
213     throw('SlimProx');
214   CSlimProxSock *root_sock=CAlloc(sizeof CSlimProxSock);
215   root_sock->proxy=FramePtr("SLIM_PROX_SOCK");
216   root_sock->children=I64SetNew();
217   root_sock->accept_fifo=FifoI64New(0x10,Fs->parent_task);
218   root_sock->write_fifo=FifoU8New(0x10,Fs->parent_task);
219   Spawn(&SlimProxTaskRead,root_sock,,,Fs);
220   Spawn(&SlimProxTaskWrite,root_sock,,,Fs);
221   FramePtrAdd("DUMB_SLIM_PROX_ROOT",root_sock,adam_task);
222   Fs->task_end_cb=&ServerCleanup;
223   return root_sock;
224 }
225 
226 
227 #define SLIM_PROX_START_PORT 7001
228 #define SLIM_PROX_END_PORT 7100
229 U8 used_ports[SLIM_PROX_END_PORT-SLIM_PROX_START_PORT+1];
230 MemSet(used_ports,FALSE,SLIM_PROX_END_PORT-SLIM_PROX_START_PORT+1);
231 
232 
233 
234 
235 U0 SlimProxServerReadTask(I64 sock) {
236   I64 who=FramePtr("ToSock");
237   I64 new,idx;
238   I64 *avail=FramePtr("AvailSocks");
239   CArcCompress head,*load;
240   CSlimProxHeader hdr;
241   for(idx=0;idx!=0x10;idx++) 
242     if(avail[idx]==sock)
243       break;
244   while(sizeof(CArcCompress)==ForceRecv(sock,&head,sizeof(CArcCompress),0)) {
245     if(head.compressed_size<1<<20) {
246       load=CAlloc(head.compressed_size);
247       MemCpy(load,&head,sizeof CArcCompress); 
248       if(0>ForceRecv(sock,load+1,head.compressed_size-sizeof(CArcCompress),0)) {
249         Free(load);
250         break;
251       }
252     } else
253         break;
254     hdr.ident=SLIM_PROX_WRITE;
255     hdr.size=load->compressed_size;
256     hdr.who=idx;
257     ForceSend(who,&hdr,sizeof(CSlimProxHeader),0);
258     ForceSend(who,load,load->compressed_size,0);
259     Free(load);
260   }
261   hdr.ident=SLIM_PROX_DISCONNECT;
262   hdr.size=0;
263   hdr.who=idx;
264   ForceSend(who,&hdr,sizeof(CSlimProxHeader),0);
265   close(sock);
266 }
267 
268 U0 SlimProxServerAcceptTask(I64) {
269   I64 who=FramePtr("ToSock");
270   I64 server=FramePtr("ServerSock");
271   I64 new,idx;
272   I64 *avail=FramePtr("AvailSocks");
273   U8 *tmp;
274   CSlimProxHeader hdr;
275   while(new=accept(server,NULL,0)) {
276     if(new==-1)
277       break;
278     for(idx=0;idx!=0x10;idx++) {
279       if(!avail[idx]) {
280         avail[idx]=new;
281         hdr.ident=SLIM_PROX_ACCEPT;
282         hdr.size=0;
283         hdr.who=idx;
284         ForceSend(who,&hdr,sizeof(CSlimProxHeader),0);
285         Spawn(&SlimProxServerReadTask,new,,,Fs);
286         goto next;
287       }
288     }
289 //Not enough open holes
290     close(new);
291 next:;
292   }
293   if(tmp=FramePtr("SLIM_PROX_EXIT_CB")) {
294     ExePutS(tmp);
295   }
296   close(server);
297   
298 }
299 U0 SlimProxServerTask(I64 sock,I64 *port=NULL) {
300 //No need to lock as we are 21 Savage runnin' on core 0
301   I64 use_port=SLIM_PROX_START_PORT;
302   I64 server_sock,cnt;
303   I64 avail_socks[0x10];
304   CSlimProxHeader hdr;
305   U8 buf[0x10000*2],*tmp;
306   MemSetI64(avail_socks,NULL,0x10);
307   while(use_port<SLIM_PROX_END_PORT) {
308     if(!used_ports[use_port])
309       break;
310     use_port++;
311   }
312 //No availbe ports
313   if(use_port==SLIM_PROX_END_PORT) {
314 fail:;
315     close(sock);
316     return;
317   }
318   server_sock=create_server("0.0.0.0",use_port,0x10);
319   if(port) *port=use_port;
320   FramePtrAdd("ServerSock",server_sock);
321   FramePtrAdd("ToSock",sock);
322   FramePtrAdd("AvailSocks",avail_socks);
323   if(server_sock<=0)
324      goto fail;
325   Spawn(&SlimProxServerAcceptTask,0,,,Fs);
326   while(TRUE) {
327     cnt=ForceRecv(sock,&hdr,sizeof(CSlimProxHeader),0);
328     if(cnt<0) {
329       break;
330     }
331     if(hdr.ident==SLIM_PROX_WRITE) {
332       if(avail_socks[hdr.who]) {
333         while(hdr.size>0) {
334           cnt=ForceRecv(sock,&buf,MinI64(hdr.size,0x10000*2),0);
335           if(cnt) ForceSend(avail_socks[hdr.who],buf,cnt,0);
336           hdr.size-=cnt;
337         }
338       }
339     } else if(hdr.ident==SLIM_PROX_DISCONNECT) {
340       if(cnt=avail_socks[hdr.who])
341         close(cnt);
342       if(0<=hdr.who<0x10)
343         avail_socks[hdr.who]=NULL;
344     }
345     Sleep(1);
346   }
347   if(tmp=FramePtr("SLIM_PROX_EXIT_CB")) {
348     ExePutS(tmp);
349   }
350 Beep(10);
351   close(server_sock);
352   close(sock);
353 }  
354 U0 SlimProxClose(I64 sock) {
355   if(!FramePtr("SLIM_PROX")) {
356     close(sock);
357   } else {
358     CSlimProxSock *sp=sock,*p;
359     if(p=sp->parent) {
360       I64SetRem(p->children,p);
361     }
362     sp->closed=TRUE;
363   }
364 }
365 I64 SlimProxAccept(I64 sock,U8 *who,I64 ul) {
366   if(!FramePtr("SLIM_PROX"))
367     return accept(sock,who,ul);
368   CSlimProxSock *sp=sock,ret;
369   if(sp->closed) return -1;
370   while(!FifoI64Cnt(sp->accept_fifo)) {
371     if(sp->closed) return -1;
372     Sleep(1);
373   }
374   FifoI64Rem(sp->accept_fifo,&ret);
375   return ret;
376 }
377 
378 I64 SlimProxReceive(I64 sock,U8 *buf,I64 len,I64 ul) {
379   if(!FramePtr("SLIM_PROX"))
380     return ForceRecv(sock,buf,len,ul);
381   I64 ate;
382   CSlimProxSock *sp=sock; 
383   CFifoU8 *use_fifo;
384   if(sp->closed) return -1;
385 //Swap read/write for "DUMB"
386   if(FramePtr("SLIM_PROX_IS_DUMB")) {
387     use_fifo=sp->write_fifo;
388   } else
389     use_fifo=sp->read_fifo;
390   while(FifoU8Cnt(use_fifo)<len) {
391     if(sp->closed) {
392       return -1;
393     }
394     Sleep(1);
395   }
396   U8 *o=buf;
397   ate=len;
398   while(--len>=0)
399     FifoU8Rem(use_fifo,buf++);
400   return ate;
401 }
402 I64 SlimProxSend(I64 sock,U8 *buf,I64 len,I64 ul) {
403   I64 sent;
404   if(!FramePtr("SLIM_PROX")) {
405     ForceSend(sock,buf,len);
406     return len;
407   }
408   I64 ate=len;
409   CSlimProxSock *sp=sock; 
410   CFifoU8 *use_fifo;
411   U8 *o=buf;
412   if(sp->closed) return -1;
413   while(LBts(&sp->lock,1))
414     Yield;
415 //Swap read/write for "DUMB"
416   if(FramePtr("SLIM_PROX_IS_DUMB")) {
417     use_fifo=sp->read_fifo;
418   } else
419     use_fifo=sp->write_fifo;
420   while(--len>=0) {
421     while(!FifoU8Ins(use_fifo,*buf)) {
422       if(sp->closed) {
423         LBtr(&sp->lock,1);
424         return -1;
425       }
426       Sleep(1);
427     }
428     buf++;
429   }
430   LBtr(&sp->lock,1);
431   return ate;
432 }