|
17 | 17 |
|
18 | 18 | #define __always_unused __attribute__((__unused__))
|
19 | 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 | + |
20 | 31 | #define _FAIL(errnum, fmt...) \
|
21 | 32 | ({ \
|
22 | 33 | error_at_line(0, (errnum), __func__, __LINE__, fmt); \
|
|
182 | 193 | __ret; \
|
183 | 194 | })
|
184 | 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 | + |
185 | 204 | static inline int poll_connect(int fd, unsigned int timeout_sec)
|
186 | 205 | {
|
187 | 206 | struct timeval timeout = { .tv_sec = timeout_sec };
|
@@ -369,72 +388,64 @@ static inline int socket_loopback(int family, int sotype)
|
369 | 388 |
|
370 | 389 | static inline int create_pair(int family, int sotype, int *p0, int *p1)
|
371 | 390 | {
|
| 391 | + __close_fd int s, c = -1, p = -1; |
372 | 392 | struct sockaddr_storage addr;
|
373 | 393 | socklen_t len = sizeof(addr);
|
374 |
| - int s, c, p, err; |
| 394 | + int err; |
375 | 395 |
|
376 | 396 | s = socket_loopback(family, sotype);
|
377 | 397 | if (s < 0)
|
378 | 398 | return s;
|
379 | 399 |
|
380 | 400 | err = xgetsockname(s, sockaddr(&addr), &len);
|
381 | 401 | if (err)
|
382 |
| - goto close_s; |
| 402 | + return err; |
383 | 403 |
|
384 | 404 | c = xsocket(family, sotype, 0);
|
385 |
| - if (c < 0) { |
386 |
| - err = c; |
387 |
| - goto close_s; |
388 |
| - } |
| 405 | + if (c < 0) |
| 406 | + return c; |
389 | 407 |
|
390 | 408 | err = connect(c, sockaddr(&addr), len);
|
391 | 409 | if (err) {
|
392 | 410 | if (errno != EINPROGRESS) {
|
393 | 411 | FAIL_ERRNO("connect");
|
394 |
| - goto close_c; |
| 412 | + return err; |
395 | 413 | }
|
396 | 414 |
|
397 | 415 | err = poll_connect(c, IO_TIMEOUT_SEC);
|
398 | 416 | if (err) {
|
399 | 417 | FAIL_ERRNO("poll_connect");
|
400 |
| - goto close_c; |
| 418 | + return err; |
401 | 419 | }
|
402 | 420 | }
|
403 | 421 |
|
404 | 422 | switch (sotype & SOCK_TYPE_MASK) {
|
405 | 423 | case SOCK_DGRAM:
|
406 | 424 | err = xgetsockname(c, sockaddr(&addr), &len);
|
407 | 425 | if (err)
|
408 |
| - goto close_c; |
| 426 | + return err; |
409 | 427 |
|
410 | 428 | err = xconnect(s, sockaddr(&addr), len);
|
411 |
| - if (!err) { |
412 |
| - *p0 = s; |
413 |
| - *p1 = c; |
| 429 | + if (err) |
414 | 430 | return err;
|
415 |
| - } |
| 431 | + |
| 432 | + *p0 = take_fd(s); |
416 | 433 | break;
|
417 | 434 | case SOCK_STREAM:
|
418 | 435 | case SOCK_SEQPACKET:
|
419 | 436 | p = xaccept_nonblock(s, NULL, NULL);
|
420 |
| - if (p >= 0) { |
421 |
| - *p0 = p; |
422 |
| - *p1 = c; |
423 |
| - goto close_s; |
424 |
| - } |
| 437 | + if (p < 0) |
| 438 | + return p; |
425 | 439 |
|
426 |
| - err = p; |
| 440 | + *p0 = take_fd(p); |
427 | 441 | break;
|
428 | 442 | default:
|
429 | 443 | FAIL("Unsupported socket type %#x", sotype);
|
430 |
| - err = -EOPNOTSUPP; |
| 444 | + return -EOPNOTSUPP; |
431 | 445 | }
|
432 | 446 |
|
433 |
| -close_c: |
434 |
| - close(c); |
435 |
| -close_s: |
436 |
| - close(s); |
437 |
| - return err; |
| 447 | + *p1 = take_fd(c); |
| 448 | + return 0; |
438 | 449 | }
|
439 | 450 |
|
440 | 451 | static inline int create_socket_pairs(int family, int sotype, int *c0, int *c1,
|
|
0 commit comments