001 // vim: set ft=c:
002 
003 //From netfifo
004 U16 htons(U16 h) {
005     return ((h >> 8) | (h << 8)) & 0xffff;
006 }
007 
008 U16 ntohs(U16 h) {
009     return ((h >> 8) | (h << 8)) & 0xffff;
010 }
011 
012 U32 htonl(U32 h) {
013     return ((h >> 24) | ((h & 0x00ff0000) >> 8) | ((h & 0x0000ff00) << 8) | (h << 24)) & 0xffffffff;
014 }
015 
016 U32 ntohl(U32 h) {
017     return ((h >> 24) | ((h & 0x00ff0000) >> 8) | ((h & 0x0000ff00) << 8) | (h << 24)) & 0xffffffff;
018 }
019 
020 
021 
022 #define SOCK_STREAM     1
023 #define SOCK_DGRAM      2
024 #define SOCK_RAW        3
025 
026 #define AF_UNSPEC       0
027 #define AF_INET         2
028 #define AF_INET6        10
029 
030 #define INADDR_ANY      0
031 
032 #define SOL_SOCKET      1
033 
034 // optval = I64*
035 #define SO_RCVTIMEO_MS  1
036 
037 #define AI_CACHED       0x8000
038 
039 class in_addr {
040   U32 s_addr;
041 };
042 
043 class sockaddr {
044   U16   sa_family;
045   U8    sa_data[16];
046 };
047 
048 class sockaddr_in {
049   I16     sin_family;
050   U16     sin_port;
051   in_addr sin_addr;
052   U8      sin_zero[8];
053 };
054 
055 class addrinfo {
056   I32       ai_flags;
057   I32       ai_family;
058   I32       ai_socktype;
059   I32       ai_protocol;
060   I64       ai_addrlen;
061   sockaddr* ai_addr;
062   U8*       ai_canonname;
063   addrinfo* ai_next;
064 };
065 
066 I64 inet_aton(U8* cp, in_addr* inp) {
067   // FIXME: error handling
068   I64 a, b, c, d;
069   StrScan(cp, "%d.%d.%d.%d", &a, &b, &c, &d);
070   inp->s_addr = (a | (b << 8) | (c << 16) | (d << 24));
071   return 0;
072 }
073 
074 U8* inet_ntoa(in_addr in) {
075   static U8 buffer[16];
076   StrPrint(buffer, "%d.%d.%d.%d", in.s_addr & 0xff, (in.s_addr >> 8) & 0xff,
077       (in.s_addr >> 16) & 0xff, (in.s_addr >> 24) & 0xff);
078   return buffer;
079 }
080 
081 class CSocket {
082   I64 (*accept)(CSocket* s, sockaddr* src_addr, I64 addrlen);
083   I64 (*bind)(CSocket* s, sockaddr* addr, I64 addrlen);
084   I64 (*close)(CSocket* s);
085   I64 (*connect)(CSocket* s, sockaddr* addr, I64 addrlen);
086   I64 (*listen)(CSocket* s, I64 backlog);
087   I64 (*recvfrom)(CSocket* s, U8* buf, I64 len, I64 flags, sockaddr* src_addr, I64 addrlen);
088   I64 (*sendto)(CSocket* s, U8* buf, I64 len, I64 flags, sockaddr* dest_addr, I64 addrlen);
089   I64 (*setsockopt)(CSocket* s, I64 level, I64 optname, U8* optval, I64 optlen);
090 };
091 
092 class CSocketClass {
093   CSocketClass* next;
094 
095   U16 domain;
096   U16 type;
097   U8 padding[4];
098 
099   CSocket* (*socket)(U16 domain, U16 type);
100 };
101 
102 class CAddrResolver {
103   // TODO: allow different resolvers for different socket domains
104   I64 (*getaddrinfo)(U8* node, U8* service, addrinfo* hints, addrinfo** res);
105 };
106 
107 static CSocketClass* socket_classes = NULL;
108 static CAddrResolver* socket_addr_resolver = NULL;
109 
110 static CSocketClass* FindSocketClass(U16 domain, U16 type) {
111   CSocketClass* cls = socket_classes;
112 
113   while (cls) {
114     if (cls->domain == domain && cls->type == type)
115       return cls;
116 
117     cls = cls->next;
118   }
119 
120   return NULL;
121 }
122 
123 I64 SocketInit() {
124   return 0;
125 }
126 
127 I64 socket(I64 domain, I64 type) {
128   CSocketClass* cls = FindSocketClass(domain, type);
129 
130   if (cls) return cls->socket(domain, type)(I64);
131   else return -1;
132 }
133 
134 I64 accept(I64 sockfd, sockaddr* addr, I64 addrlen) {
135   CSocket* sock = sockfd(CSocket*);
136   if (sockfd > 0) return sock->accept(sock, addr, addrlen);
137   else return -1;
138 }
139 
140 I64 close(I64 sockfd) {
141   CSocket* sock = sockfd(CSocket*);
142   if (sockfd > 0) return sock->close(sock);
143   else return -1;
144 }
145 
146 I64 bind(I64 sockfd, sockaddr* addr, I64 addrlen) {
147   CSocket* sock = sockfd(CSocket*);
148   if (sockfd > 0) return sock->bind(sock, addr, addrlen);
149   else return -1;
150 }
151 
152 I64 connect(I64 sockfd, sockaddr* addr, I64 addrlen) {
153   CSocket* sock = sockfd(CSocket*);
154   if (sockfd > 0) return sock->connect(sock, addr, addrlen);
155   else return -1;
156 }
157 
158 I64 listen(I64 sockfd, I64 backlog) {
159   CSocket* sock = sockfd(CSocket*);
160   if (sockfd > 0) return sock->listen(sock, backlog);
161   else return -1;
162 }
163 
164 I64 recv(I64 sockfd, U8* buf, I64 len, I64 flags) {
165   CSocket* sock = sockfd(CSocket*);
166   if (sockfd > 0) return sock->recvfrom(sock, buf, len, flags, NULL, 0);
167   else return -1;
168 }
169 
170 I64 recvfrom(I64 sockfd, U8* buf, I64 len, I64 flags, sockaddr* src_addr, I64 addrlen) {
171   CSocket* sock = sockfd(CSocket*);
172   if (sockfd > 0) return sock->recvfrom(sock, buf, len, flags, src_addr, addrlen);
173   else return -1;
174 }
175 
176 I64 send(I64 sockfd, U8* buf, I64 len, I64 flags) {
177   CSocket* sock = sockfd(CSocket*);
178   if (sockfd > 0) return sock->sendto(sock, buf, len, flags, NULL, 0);
179   else return -1;
180 }
181 
182 I64 sendto(I64 sockfd, U8* buf, I64 len, I64 flags, sockaddr* dest_addr, I64 addrlen) {
183   CSocket* sock = sockfd(CSocket*);
184   if (sockfd > 0) return sock->sendto(sock, buf, len, flags, dest_addr, addrlen);
185   else return -1;
186 }
187 
188 I64 setsockopt(I64 sockfd, I64 level, I64 optname, U8* optval, I64 optlen) {
189   CSocket* sock = sockfd(CSocket*);
190   if (sockfd > 0) return sock->setsockopt(sock, level, optname, optval, optlen);
191   else return -1;
192 }
193 
194 I64 getaddrinfo(U8* node, U8* service, addrinfo* hints, addrinfo** res) {
195   if (socket_addr_resolver) return socket_addr_resolver->getaddrinfo(node, service, hints, res);
196   else return -1;
197 }
198 
199 U0 freeaddrinfo(addrinfo* res) {
200   while (res) {
201     addrinfo* next = res->ai_next;
202 #ifdef __AIWNIOS_
203     CNetAddr *na=res->ai_addr(sockaddr_in)*->sin_zero[0](U64);
204     if(na) NetAddrDel(na);
205 #endif
206     Free(res->ai_addr);
207     Free(res->ai_canonname);
208     Free(res);
209     res = next;
210   }
211 }
212 
213 U0 AddrInfoCopy(addrinfo* ai_out, addrinfo* ai_in) {
214   MemCpy(ai_out, ai_in, sizeof(addrinfo));
215 
216   if (ai_in->ai_addr) {
217     ai_out->ai_addr = MAlloc(ai_in->ai_addrlen);
218     MemCpy(ai_out->ai_addr, ai_in->ai_addr, ai_in->ai_addrlen);
219   }
220 
221   if (ai_in->ai_canonname) {
222     ai_out->ai_canonname = StrNew(ai_in->ai_canonname);
223   }
224 }
225 
226 U8* gai_strerror(I64 errcode) {
227   no_warn errcode;
228   return "Unspecified error";
229 }
230 
231 I64 create_server(U8 *hostname,U16 port,I64 backlog=10) {
232   I64 sock = socket(AF_INET,SOCK_STREAM);
233   if (sock < 0)
234     return -1;
235   sockaddr_in addr;
236   addr.sin_family = AF_INET;
237   addr.sin_port = htons(port);
238   addr.sin_addr.s_addr = 0;
239   addrinfo* res, *curr;
240   getaddrinfo("0.0.0.0", NULL, NULL, &res);
241   for(curr=res;curr;curr=curr->ai_next) { 
242     if (curr->ai_family == AF_INET && (curr->ai_socktype == 0 || curr->ai_socktype == SOCK_STREAM)) {
243       MemCpy(&addr.sin_zero,&curr->ai_addr(sockaddr_in*)->sin_zero,8);
244       addr.sin_addr.s_addr = (curr->ai_addr(sockaddr_in*))->sin_addr.s_addr;
245       break;
246     }
247   }
248   bind(sock,&addr,sizeof (sockaddr_in));
249   freeaddrinfo(res);
250   listen(sock,backlog);
251   return sock;
252 }
253 
254 // Inspired by https://docs.python.org/3.7/library/socket.html#socket.create_connection
255 I64 create_connection(U8* hostname, U16 port) {
256   sockaddr_in addr;
257   addr.sin_family = AF_INET;
258   addr.sin_port = htons(port);
259   addr.sin_addr.s_addr = 0;
260 
261   addrinfo* res;
262   I64 error = getaddrinfo(hostname, NULL, NULL, &res);
263 
264   if (error < 0) {
265     "getaddrinfo: error %d\n", error;
266   }
267   else {
268     addrinfo* curr = res;
269 
270     while (curr) {
271       if (curr->ai_family == AF_INET && (curr->ai_socktype == 0 || curr->ai_socktype == SOCK_STREAM)) {
272         addr.sin_addr.s_addr = (curr->ai_addr(sockaddr_in*))->sin_addr.s_addr;
273 //For aiwnios I store the aiwnios CNetAddr ptr in sin_zero
274         MemCpy(&addr.sin_zero,&curr->ai_addr(sockaddr_in*)->sin_zero,8);
275         freeaddrinfo(res);
276 
277         I64 sockfd = socket(AF_INET, SOCK_STREAM);
278 
279         if (sockfd < 0)
280           return sockfd;
281 
282         error = connect(sockfd, &addr, sizeof(addr));
283 
284         if (error < 0) {
285           close(sockfd);
286           return error;
287         }
288 
289         return sockfd;
290       }
291 
292       curr = curr->ai_next;
293     }
294 
295     "create_connection: no suitable address\n";
296   }
297 
298   freeaddrinfo(res);
299   return -1;
300 }
301 
302 U0 RegisterSocketClass(U16 domain, U16 type, CSocket* (*socket)(U16 domain, U16 type)) {
303   CSocketClass* cls = MAlloc(sizeof(CSocketClass));
304 
305   cls->next = socket_classes;
306   cls->domain = domain;
307   cls->type = type;
308   cls->socket = socket;
309 
310   socket_classes = cls;
311 }
312 
313 //From Socket.HC
314 I64 recvLine(I64 sock, U8* buffer, I64 size, I64 flags) {
315   I64 got = 0;
316   while (got + 1 < size) {
317     if (!recv(sock, buffer + got, 1, flags))
318       return -1;
319 
320     if (buffer[got] == '\n')
321       break;
322     else if (buffer[got] != '\r')
323       got++;
324   }
325   // FIXME: safe but incorrect behavior on overflow
326   buffer[got] = 0;
327   return got;
328 }
329 
330 I64 sendString(I64 sockfd, U8* str, I64 flags) {
331   return send(sockfd, str, StrLen(str), flags);
332 }