|
1 | 1 | // vim: set ft=c: |
2 | 2 |
|
3 | | -#define SOCK_STREAM 1 |
4 | | -#define SOCK_DGRAM 2 |
5 | | -#define SOCK_RAW 3 |
| 3 | +#define SOCK_STREAM 1 |
| 4 | +#define SOCK_DGRAM 2 |
| 5 | +#define SOCK_RAW 3 |
6 | 6 |
|
7 | | -#define AF_UNSPEC 0 |
8 | | -#define AF_INET 2 |
9 | | -#define AF_INET6 10 |
| 7 | +#define AF_UNSPEC 0 |
| 8 | +#define AF_INET 2 |
| 9 | +#define AF_INET6 10 |
10 | 10 |
|
11 | | -#define INADDR_ANY 0 |
| 11 | +#define INADDR_ANY 0 |
12 | 12 |
|
13 | | -#define SOL_SOCKET 1 |
| 13 | +#define SOL_SOCKET 1 |
14 | 14 |
|
15 | 15 | // optval = I64* |
16 | | -#define SO_RCVTIMEO_MS 1 |
| 16 | +#define SO_RCVTIMEO_MS 1 |
17 | 17 |
|
18 | | -#define AI_CACHED 0x8000 |
| 18 | +#define AI_CACHED 0x8000 |
19 | 19 |
|
20 | 20 | class in_addr { |
21 | 21 | U32 s_addr; |
@@ -159,8 +159,6 @@ I64 setsockopt(I64 sockfd, I64 level, I64 optname, U8* optval, I64 optlen) { |
159 | 159 | else return -1; |
160 | 160 | } |
161 | 161 |
|
162 | | -I64 connectTcp(I64, U8*, U16) { return -1; } |
163 | | -I64 recvall(I64, U8*, I64, I64) { return -1; } |
164 | 162 | I64 getaddrinfo(U8* node, U8* service, addrinfo* hints, addrinfo** res) { |
165 | 163 | if (socket_addr_resolver) return socket_addr_resolver->getaddrinfo(node, service, hints, res); |
166 | 164 | else return -1; |
@@ -194,6 +192,67 @@ U8* gai_strerror(I64 errcode) { |
194 | 192 | return "Unspecified error"; |
195 | 193 | } |
196 | 194 |
|
| 195 | +// Inspired by https://docs.python.org/3.7/library/socket.html#socket.create_connection |
| 196 | +I64 create_connection(U8* hostname, U16 port) { |
| 197 | + sockaddr_in addr; |
| 198 | + addr.sin_family = AF_INET; |
| 199 | + addr.sin_port = htons(port); |
| 200 | + addr.sin_addr.s_addr = 0; |
| 201 | + |
| 202 | + addrinfo* res; |
| 203 | + I64 error = getaddrinfo(hostname, NULL, NULL, &res); |
| 204 | + |
| 205 | + if (error < 0) { |
| 206 | + "$FG,4$getaddrinfo: error %d\n$FG$", error; |
| 207 | + } |
| 208 | + else { |
| 209 | + addrinfo* curr = res; |
| 210 | + |
| 211 | + while (curr) { |
| 212 | + if (curr->ai_family == AF_INET && (curr->ai_socktype == 0 || curr->ai_socktype == SOCK_STREAM)) { |
| 213 | + addr.sin_addr.s_addr = (curr->ai_addr(sockaddr_in*))->sin_addr.s_addr; |
| 214 | + freeaddrinfo(res); |
| 215 | + |
| 216 | + I64 sockfd = socket(AF_INET, SOCK_STREAM); |
| 217 | + |
| 218 | + if (sockfd < 0) |
| 219 | + return sockfd; |
| 220 | + |
| 221 | + error = connect(sockfd, &addr, sizeof(addr)); |
| 222 | + |
| 223 | + if (error < 0) { |
| 224 | + close(sockfd); |
| 225 | + return error; |
| 226 | + } |
| 227 | + |
| 228 | + return sockfd; |
| 229 | + } |
| 230 | + |
| 231 | + curr = curr->ai_next; |
| 232 | + } |
| 233 | + |
| 234 | + "$FG,4$create_connection: no suitable address\n$FG$"; |
| 235 | + } |
| 236 | + |
| 237 | + freeaddrinfo(res); |
| 238 | + return -1; |
| 239 | +} |
| 240 | + |
| 241 | +I64 recvall(I64 sockfd, U8* buf, I64 len, I64 flags) { |
| 242 | + I64 total = 0; |
| 243 | + |
| 244 | + while (len) { |
| 245 | + I64 got = recv(sockfd, buf + total, len, flags); |
| 246 | + |
| 247 | + if (got < 0) |
| 248 | + break; |
| 249 | + |
| 250 | + len -= got; |
| 251 | + total += got; |
| 252 | + } |
| 253 | + |
| 254 | + return total; |
| 255 | +} |
197 | 256 |
|
198 | 257 | U0 RegisterSocketClass(U16 domain, U16 type, CSocket* (*socket)(U16 domain, U16 type)) { |
199 | 258 | CSocketClass* cls = MAlloc(sizeof(CSocketClass)); |
|
0 commit comments