001 #exe {Cd(__DIR__);};;
002 #include "Generic.HC";
003 #include "Set.HC";
004 class CNetAddr {
005   U8 *hostname;
006   I64 port;
007 };
008 class CExodusSock:CSocket {
009   I64 sock_num;
010   CI64Set *children;
011   I64 read_cnt,write_cnt,hangup_cnt;
012   U8 *read_base; //Free this
013   U8 *write_ptr,*read_ptr;
014 };
015 CTask *net_task=NULL;
016 CDyadStream *dyad_socks[0x10000];
017 CExodusSock *exodus_socks[0x10000];
018 extern CExodusSock *_Socket(CDyadStream *stream);
019 U0 DyadSocketTaskEnd() {
020   DyadShutdown;  
021   Exit;
022 }
023 U0 DyadSocketTask(I64 s) {
024   DyadInit;
025   net_task=Fs;
026   Fs->task_end_cb=&DyadSocketTaskEnd;
027   MemSetI64(dyad_socks,0,0x10000);
028   MemSetI64(exodus_socks,0,0x10000);
029   while(TRUE) {
030     DyadUpdate;
031     Sleep(10);
032   }
033 }
034 I64 FindFreeSock() {
035   I64 i=0;
036   for(i=0;i!=0x10000;i++)
037     if(!dyad_socks[i])
038       return i;
039   return -1;
040 }
041 I64 DyadSockIdx(CDyadStream *s) {
042   I64 i=0;
043   for(i=0;i!=0x10000;i++) {
044     if(dyad_socks[i]==s)
045       return i;
046   }
047   return -1;
048 }
049 I64 ExodusGetAddrInfo(U8 *node,U8*ul,addrinfo *hints=NULL,addrinfo **res) {
050   sockaddr_in *addr=CAlloc(sizeof sockaddr_in);
051   addrinfo *info=CAlloc(sizeof addrinfo);
052   CNetAddr *new=CAlloc(sizeof CNetAddr);
053   new->hostname=StrNew(node);
054   new->port=0;
055   info->ai_family=AF_INET;
056   info->ai_canonname=StrNew(node);
057   info->ai_addr=addr;
058   info->ai_socktype=SOCK_STREAM;
059   addr->sin_zero[0](U64*)=new;
060   *res=info;
061   return 0;
062 }
063 
064 socket_addr_resolver=CAlloc(sizeof CAddrResolver);
065 socket_addr_resolver->getaddrinfo=&ExodusGetAddrInfo;
066 I64 ExodusAccept(CExodusSock *_s,sockaddr *src_addr,I64 addr_len) {
067   I64 s=_s->sock_num;
068   I64 code;
069   CExodusSock *got;
070   if(_s->read_cnt) {
071     _s->read_cnt--;
072     got=_s->children->body[0];
073     I64SetRem(_s->children,got);
074   } else
075     got=-1;
076   return got;
077 }
078 I64 ExodusClose(CExodusSock *_s) {
079   CDyadStream *ds=dyad_socks[_s->sock_num];
080   dyad_socks[_s->sock_num]=NULL;
081   exodus_socks[_s->sock_num]=NULL;
082   DyadEnd(ds);
083   Free(_s);
084   return 0;
085 }
086 I64 ExodusBind(CExodusSock *_s,sockaddr_in *src_addr,I64 addr_len) {
087   CNetAddr *from=src_addr->sin_zero[0](U64*);
088   DyadListen(dyad_socks[_s->sock_num],htons(src_addr->sin_port),from->hostname);
089   return 0;
090 }
091 I64 ExodusConnect(CExodusSock *_s,sockaddr_in *src_addr,I64 addr_len) {
092   CNetAddr *from=src_addr->sin_zero[0](U64*);
093 //Use port from src_addr
094   DyadConnect(dyad_socks[_s->sock_num],from->hostname,htons(src_addr->sin_port));
095   return 0;
096 }
097 I64 ExodusListen(CExodusSock *_s,I64 backlog) {
098 //See NetBind
099   return 0;
100 }
101 I64 ExodusRecvFrom(CExodusSock *_s,U8 *buf,I64 len,I64 flags,sockaddr *ul,I64 addrlen) {
102 //TODO wherefrom
103 ent:;
104   I64 s=_s->sock_num;
105   I64 buf_len=_s->write_ptr-_s->read_ptr;
106   if(!buf_len) {Sleep(4);goto ent;}
107   if(buf_len>=len) {
108     MemCpy(buf,_s->read_ptr,len);
109     _s->read_ptr+=len;
110     return len;
111   }
112   MemCpy(buf,_s->read_ptr,buf_len);
113   _s->read_ptr+=buf_len;
114   return buf_len;
115 }
116 I64 ExodusSendTo(CExodusSock* _s, U8* buf, I64 len, I64 flags, sockaddr* dest_addr, I64 addrlen) {
117 //TODO whereto
118   I64 s=_s->sock_num;
119   DyadWrite(dyad_socks[s],buf,len);
120   return len;
121 
122 }
123 I64 ExodusSockOpt(CExodusSock* _s, I64 level, I64 optname, U8* optval, I64 optlen) {
124 //Poop taods
125 }
126 static U0 DyadReadCallback(CDyadStream *who,U8 *buf,I64 len,U8 *ud) {
127   CExodusSock *s=ud;
128   I64 buf_len;
129   U8 *copy;
130   buf_len=s->write_ptr-s->read_base;
131   if(!s->read_base) {
132     s->read_base=CAlloc(len+32);
133     s->read_ptr=s->read_base;
134     s->write_ptr=s->read_base;
135   } else if(buf_len+len>=MSize(s->read_base)) { 
136     buf_len=s->write_ptr-s->read_ptr;
137     copy=s->read_base;
138     s->read_base=CAlloc(len+32+buf_len);
139     MemCpy(s->read_base,s->read_ptr,buf_len);
140     Free(copy);
141     s->read_ptr=s->read_base;
142     s->write_ptr=s->read_base+buf_len;
143   }
144   MemCpy(s->write_ptr,buf,len);
145   s->write_ptr+=len;
146 }
147 static U0 DyadAcceptCallback(CDyadStream *new,CExodusSock *s) {
148   I64SetAdd(s->children,_Socket(new));
149   s->read_cnt++;
150 }
151 static U0 DyadCloseCallback(CDyadStream *who,U8 *user_data) {
152   I64 idx=DyadSockIdx(who);
153   if(idx==-1) return;
154   CExodusSock *s=exodus_socks[idx];
155   s->hangup_cnt++;  
156 }
157 CExodusSock *_Socket(CDyadStream *stream) {
158   CExodusSock *ret=CAlloc(sizeof CExodusSock);
159   I64 sock=FindFreeSock;
160   ret->sock_num=sock;
161   ret->accept=&ExodusAccept;
162   ret->bind=&ExodusBind;
163   ret->close=&ExodusClose;
164   ret->connect=&ExodusConnect;
165   ret->listen=&ExodusListen;
166   ret->recvfrom=&ExodusRecvFrom;
167   ret->sendto=&ExodusSendTo;
168   ret->setsockopt=&ExodusSockOpt;
169   ret->children=I64SetNew;
170   DyadSetListenCallback(stream,DYAD_EVENT_ACCEPT,&DyadAcceptCallback,ret);
171   DyadSetReadCallback(stream,DYAD_EVENT_DATA,&DyadReadCallback,ret);
172   DyadSetCloseCallback(stream,DYAD_EVENT_CLOSE,&DyadCloseCallback,ret);
173   dyad_socks[sock]=stream;
174   exodus_socks[sock]=ret;
175   return ret;
176 }
177 
178 U8 *ExodusSocket(U16,U16) {
179   if(!net_task) {
180     Spawn(&DyadSocketTask,0,"DyadShim",-1,Fs);
181     while(!net_task) 
182       Yield;
183   }  
184   return _Socket(DyadNewStream);
185 }
186 
187 RegisterSocketClass(AF_INET,SOCK_STREAM,&ExodusSocket);
188 
189 /*I64 sock=create_connection("aiwnios.com",6667);
190 sendString(sock,
191 "NICK asshole\n"
192 "USER asshole 0 * :asshole\n"
193 ,0);
194 U8 buf[STR_LEN];
195 recvLine(sock,buf,STR_LEN,0);
196 "%s\n",buf;
197 sendString(sock,
198 "JOIN #main\n"
199 ,0);
200 while(recvLine(sock,buf,STR_LEN,0))
201   "%s\n",buf;
202 close(sock);*/