|
3 | 3 |
|
4 | 4 | #include <linux/vm_sockets.h> |
5 | 5 |
|
| 6 | +/* include/linux/net.h */ |
| 7 | +#define SOCK_TYPE_MASK 0xf |
| 8 | + |
6 | 9 | #define IO_TIMEOUT_SEC 30 |
7 | 10 | #define MAX_STRERR_LEN 256 |
8 | 11 | #define MAX_TEST_NAME 80 |
|
14 | 17 |
|
15 | 18 | #define __always_unused __attribute__((__unused__)) |
16 | 19 |
|
| 20 | +/* include/linux/cleanup.h */ |
| 21 | +#define __get_and_null(p, nullvalue) \ |
| 22 | + ({ \ |
| 23 | + __auto_type __ptr = &(p); \ |
| 24 | + __auto_type __val = *__ptr; \ |
| 25 | + *__ptr = nullvalue; \ |
| 26 | + __val; \ |
| 27 | + }) |
| 28 | + |
| 29 | +#define take_fd(fd) __get_and_null(fd, -EBADF) |
| 30 | + |
17 | 31 | #define _FAIL(errnum, fmt...) \ |
18 | 32 | ({ \ |
19 | 33 | error_at_line(0, (errnum), __func__, __LINE__, fmt); \ |
|
179 | 193 | __ret; \ |
180 | 194 | }) |
181 | 195 |
|
| 196 | +static inline void close_fd(int *fd) |
| 197 | +{ |
| 198 | + if (*fd >= 0) |
| 199 | + xclose(*fd); |
| 200 | +} |
| 201 | + |
| 202 | +#define __close_fd __attribute__((cleanup(close_fd))) |
| 203 | + |
182 | 204 | static inline int poll_connect(int fd, unsigned int timeout_sec) |
183 | 205 | { |
184 | 206 | struct timeval timeout = { .tv_sec = timeout_sec }; |
@@ -312,54 +334,6 @@ static inline int add_to_sockmap(int sock_mapfd, int fd1, int fd2) |
312 | 334 | return xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); |
313 | 335 | } |
314 | 336 |
|
315 | | -static inline int create_pair(int s, int family, int sotype, int *c, int *p) |
316 | | -{ |
317 | | - struct sockaddr_storage addr; |
318 | | - socklen_t len; |
319 | | - int err = 0; |
320 | | - |
321 | | - len = sizeof(addr); |
322 | | - err = xgetsockname(s, sockaddr(&addr), &len); |
323 | | - if (err) |
324 | | - return err; |
325 | | - |
326 | | - *c = xsocket(family, sotype, 0); |
327 | | - if (*c < 0) |
328 | | - return errno; |
329 | | - err = xconnect(*c, sockaddr(&addr), len); |
330 | | - if (err) { |
331 | | - err = errno; |
332 | | - goto close_cli0; |
333 | | - } |
334 | | - |
335 | | - *p = xaccept_nonblock(s, NULL, NULL); |
336 | | - if (*p < 0) { |
337 | | - err = errno; |
338 | | - goto close_cli0; |
339 | | - } |
340 | | - return err; |
341 | | -close_cli0: |
342 | | - close(*c); |
343 | | - return err; |
344 | | -} |
345 | | - |
346 | | -static inline int create_socket_pairs(int s, int family, int sotype, |
347 | | - int *c0, int *c1, int *p0, int *p1) |
348 | | -{ |
349 | | - int err; |
350 | | - |
351 | | - err = create_pair(s, family, sotype, c0, p0); |
352 | | - if (err) |
353 | | - return err; |
354 | | - |
355 | | - err = create_pair(s, family, sotype, c1, p1); |
356 | | - if (err) { |
357 | | - close(*c0); |
358 | | - close(*p0); |
359 | | - } |
360 | | - return err; |
361 | | -} |
362 | | - |
363 | 337 | static inline int enable_reuseport(int s, int progfd) |
364 | 338 | { |
365 | 339 | int err, one = 1; |
@@ -412,5 +386,84 @@ static inline int socket_loopback(int family, int sotype) |
412 | 386 | return socket_loopback_reuseport(family, sotype, -1); |
413 | 387 | } |
414 | 388 |
|
| 389 | +static inline int create_pair(int family, int sotype, int *p0, int *p1) |
| 390 | +{ |
| 391 | + __close_fd int s, c = -1, p = -1; |
| 392 | + struct sockaddr_storage addr; |
| 393 | + socklen_t len = sizeof(addr); |
| 394 | + int err; |
| 395 | + |
| 396 | + s = socket_loopback(family, sotype); |
| 397 | + if (s < 0) |
| 398 | + return s; |
| 399 | + |
| 400 | + err = xgetsockname(s, sockaddr(&addr), &len); |
| 401 | + if (err) |
| 402 | + return err; |
| 403 | + |
| 404 | + c = xsocket(family, sotype, 0); |
| 405 | + if (c < 0) |
| 406 | + return c; |
| 407 | + |
| 408 | + err = connect(c, sockaddr(&addr), len); |
| 409 | + if (err) { |
| 410 | + if (errno != EINPROGRESS) { |
| 411 | + FAIL_ERRNO("connect"); |
| 412 | + return err; |
| 413 | + } |
| 414 | + |
| 415 | + err = poll_connect(c, IO_TIMEOUT_SEC); |
| 416 | + if (err) { |
| 417 | + FAIL_ERRNO("poll_connect"); |
| 418 | + return err; |
| 419 | + } |
| 420 | + } |
| 421 | + |
| 422 | + switch (sotype & SOCK_TYPE_MASK) { |
| 423 | + case SOCK_DGRAM: |
| 424 | + err = xgetsockname(c, sockaddr(&addr), &len); |
| 425 | + if (err) |
| 426 | + return err; |
| 427 | + |
| 428 | + err = xconnect(s, sockaddr(&addr), len); |
| 429 | + if (err) |
| 430 | + return err; |
| 431 | + |
| 432 | + *p0 = take_fd(s); |
| 433 | + break; |
| 434 | + case SOCK_STREAM: |
| 435 | + case SOCK_SEQPACKET: |
| 436 | + p = xaccept_nonblock(s, NULL, NULL); |
| 437 | + if (p < 0) |
| 438 | + return p; |
| 439 | + |
| 440 | + *p0 = take_fd(p); |
| 441 | + break; |
| 442 | + default: |
| 443 | + FAIL("Unsupported socket type %#x", sotype); |
| 444 | + return -EOPNOTSUPP; |
| 445 | + } |
| 446 | + |
| 447 | + *p1 = take_fd(c); |
| 448 | + return 0; |
| 449 | +} |
| 450 | + |
| 451 | +static inline int create_socket_pairs(int family, int sotype, int *c0, int *c1, |
| 452 | + int *p0, int *p1) |
| 453 | +{ |
| 454 | + int err; |
| 455 | + |
| 456 | + err = create_pair(family, sotype, c0, p0); |
| 457 | + if (err) |
| 458 | + return err; |
| 459 | + |
| 460 | + err = create_pair(family, sotype, c1, p1); |
| 461 | + if (err) { |
| 462 | + close(*c0); |
| 463 | + close(*p0); |
| 464 | + } |
| 465 | + |
| 466 | + return err; |
| 467 | +} |
415 | 468 |
|
416 | 469 | #endif // __SOCKMAP_HELPERS__ |
0 commit comments