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 }