001 // vim: set ft=c: 002 003 #define SOCK_STREAM 1 004 #define SOCK_DGRAM 2 005 #define SOCK_RAW 3 006 007 #define AF_UNSPEC 0 008 #define AF_INET 2 009 #define AF_INET6 10 010 011 #define INADDR_ANY 0 012 013 #define SOL_SOCKET 1 014 015 // optval = I64* 016 #define SO_RCVTIMEO_MS 1 017 018 #define AI_CACHED 0x8000 019 020 class in_addr { 021 U32 s_addr; 022 }; 023 024 class sockaddr { 025 U16 sa_family; 026 U8 sa_data[14]; 027 }; 028 029 class sockaddr_in { 030 I16 sin_family; 031 U16 sin_port; 032 in_addr sin_addr; 033 U8 sin_zero[8]; 034 }; 035 036 class addrinfo { 037 I32 ai_flags; 038 I32 ai_family; 039 I32 ai_socktype; 040 I32 ai_protocol; 041 I64 ai_addrlen; 042 sockaddr* ai_addr; 043 U8* ai_canonname; 044 addrinfo* ai_next; 045 }; 046 047 I64 inet_aton(U8* cp, in_addr* inp) { 048 // FIXME: error handling 049 I64 a, b, c, d; 050 StrScan(cp, "%d.%d.%d.%d", &a, &b, &c, &d); 051 inp->s_addr = (a | (b << 8) | (c << 16) | (d << 24)); 052 return 0; 053 } 054 055 U8* inet_ntoa(in_addr in) { 056 static U8 buffer[16]; 057 StrPrint(buffer, "%d.%d.%d.%d", in.s_addr & 0xff, (in.s_addr >> 8) & 0xff, 058 (in.s_addr >> 16) & 0xff, (in.s_addr >> 24) & 0xff); 059 return buffer; 060 } 061 062 class CSocket { 063 I64 (*accept)(CSocket* s, sockaddr* src_addr, I64 addrlen); 064 I64 (*bind)(CSocket* s, sockaddr* addr, I64 addrlen); 065 I64 (*close)(CSocket* s); 066 I64 (*connect)(CSocket* s, sockaddr* addr, I64 addrlen); 067 I64 (*listen)(CSocket* s, I64 backlog); 068 I64 (*recvfrom)(CSocket* s, U8* buf, I64 len, I64 flags, sockaddr* src_addr, I64 addrlen); 069 I64 (*sendto)(CSocket* s, U8* buf, I64 len, I64 flags, sockaddr* dest_addr, I64 addrlen); 070 I64 (*setsockopt)(CSocket* s, I64 level, I64 optname, U8* optval, I64 optlen); 071 }; 072 073 class CSocketClass { 074 CSocketClass* next; 075 076 U16 domain; 077 U16 type; 078 U8 padding[4]; 079 080 CSocket* (*socket)(U16 domain, U16 type); 081 }; 082 083 class CAddrResolver { 084 // TODO: allow different resolvers for different socket domains 085 086 I64 (*getaddrinfo)(U8* node, U8* service, addrinfo* hints, addrinfo** res); 087 }; 088 089 static CSocketClass* socket_classes = NULL; 090 static CAddrResolver* socket_addr_resolver = NULL; 091 092 static CSocketClass* FindSocketClass(U16 domain, U16 type) { 093 CSocketClass* cls = socket_classes; 094 095 while (cls) { 096 if (cls->domain == domain && cls->type == type) 097 return cls; 098 099 cls = cls->next; 100 } 101 102 return NULL; 103 } 104 105 I64 SocketInit() { 106 return 0; 107 } 108 109 I64 socket(I64 domain, I64 type) { 110 CSocketClass* cls = FindSocketClass(domain, type); 111 112 if (cls) return cls->socket(domain, type)(I64); 113 else return -1; 114 } 115 116 I64 accept(I64 sockfd, sockaddr* addr, I64 addrlen) { 117 CSocket* sock = sockfd(CSocket*); 118 if (sockfd > 0) return sock->accept(sock, addr, addrlen); 119 else return -1; 120 } 121 122 I64 close(I64 sockfd) { 123 CSocket* sock = sockfd(CSocket*); 124 if (sockfd > 0) return sock->close(sock); 125 else return -1; 126 } 127 128 I64 bind(I64 sockfd, sockaddr* addr, I64 addrlen) { 129 CSocket* sock = sockfd(CSocket*); 130 if (sockfd > 0) return sock->bind(sock, addr, addrlen); 131 else return -1; 132 } 133 134 I64 connect(I64 sockfd, sockaddr* addr, I64 addrlen) { 135 CSocket* sock = sockfd(CSocket*); 136 if (sockfd > 0) return sock->connect(sock, addr, addrlen); 137 else return -1; 138 } 139 140 I64 listen(I64 sockfd, I64 backlog) { 141 CSocket* sock = sockfd(CSocket*); 142 if (sockfd > 0) return sock->listen(sock, backlog); 143 else return -1; 144 } 145 146 I64 recv(I64 sockfd, U8* buf, I64 len, I64 flags) { 147 CSocket* sock = sockfd(CSocket*); 148 if (sockfd > 0) return sock->recvfrom(sock, buf, len, flags, NULL, 0); 149 else return -1; 150 } 151 152 I64 recvfrom(I64 sockfd, U8* buf, I64 len, I64 flags, sockaddr* src_addr, I64 addrlen) { 153 CSocket* sock = sockfd(CSocket*); 154 if (sockfd > 0) return sock->recvfrom(sock, buf, len, flags, src_addr, addrlen); 155 else return -1; 156 } 157 158 I64 send(I64 sockfd, U8* buf, I64 len, I64 flags) { 159 CSocket* sock = sockfd(CSocket*); 160 if (sockfd > 0) return sock->sendto(sock, buf, len, flags, NULL, 0); 161 else return -1; 162 } 163 164 I64 sendto(I64 sockfd, U8* buf, I64 len, I64 flags, sockaddr* dest_addr, I64 addrlen) { 165 CSocket* sock = sockfd(CSocket*); 166 if (sockfd > 0) return sock->sendto(sock, buf, len, flags, dest_addr, addrlen); 167 else return -1; 168 } 169 170 I64 setsockopt(I64 sockfd, I64 level, I64 optname, U8* optval, I64 optlen) { 171 CSocket* sock = sockfd(CSocket*); 172 if (sockfd > 0) return sock->setsockopt(sock, level, optname, optval, optlen); 173 else return -1; 174 } 175 176 I64 getaddrinfo(U8* node, U8* service, addrinfo* hints, addrinfo** res) { 177 if (socket_addr_resolver) return socket_addr_resolver->getaddrinfo(node, service, hints, res); 178 else return -1; 179 } 180 181 U0 freeaddrinfo(addrinfo* res) { 182 while (res) { 183 addrinfo* next = res->ai_next; 184 Free(res->ai_addr); 185 Free(res->ai_canonname); 186 Free(res); 187 res = next; 188 } 189 } 190 191 U0 AddrInfoCopy(addrinfo* ai_out, addrinfo* ai_in) { 192 MemCpy(ai_out, ai_in, sizeof(addrinfo)); 193 194 if (ai_in->ai_addr) { 195 ai_out->ai_addr = MAlloc(ai_in->ai_addrlen); 196 MemCpy(ai_out->ai_addr, ai_in->ai_addr, ai_in->ai_addrlen); 197 } 198 199 if (ai_in->ai_canonname) { 200 ai_out->ai_canonname = StrNew(ai_in->ai_canonname); 201 } 202 } 203 204 U8* gai_strerror(I64 errcode) { 205 no_warn errcode; 206 return "Unspecified error"; 207 } 208 209 // Inspired by https://docs.python.org/3.7/library/socket.html#socket.create_connection 210 I64 create_connection(U8* hostname, U16 port) { 211 sockaddr_in addr; 212 addr.sin_family = AF_INET; 213 addr.sin_port = htons(port); 214 addr.sin_addr.s_addr = 0; 215 216 addrinfo* res; 217 I64 error = getaddrinfo(hostname, NULL, NULL, &res); 218 219 if (error < 0) { 220 "getaddrinfo: error %d\n", error; 221 } 222 else { 223 addrinfo* curr = res; 224 225 while (curr) { 226 if (curr->ai_family == AF_INET && (curr->ai_socktype == 0 || curr->ai_socktype == SOCK_STREAM)) { 227 addr.sin_addr.s_addr = (curr->ai_addr(sockaddr_in*))->sin_addr.s_addr; 228 freeaddrinfo(res); 229 230 I64 sockfd = socket(AF_INET, SOCK_STREAM); 231 232 if (sockfd < 0) 233 return sockfd; 234 235 error = connect(sockfd, &addr, sizeof(addr)); 236 237 if (error < 0) { 238 close(sockfd); 239 return error; 240 } 241 242 return sockfd; 243 } 244 245 curr = curr->ai_next; 246 } 247 248 "create_connection: no suitable address\n"; 249 } 250 251 freeaddrinfo(res); 252 return -1; 253 } 254 255 U0 RegisterSocketClass(U16 domain, U16 type, CSocket* (*socket)(U16 domain, U16 type)) { 256 CSocketClass* cls = MAlloc(sizeof(CSocketClass)); 257 258 cls->next = socket_classes; 259 cls->domain = domain; 260 cls->type = type; 261 cls->socket = socket; 262 263 socket_classes = cls; 264 }