-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
rfc6555.h
95 lines (89 loc) · 2.9 KB
/
rfc6555.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
* Simple C implementation of [rfc6555] (Happy Eyeballs)
* Copyright (C) 2019 Olivier Mehani <[email protected]>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* The aim is to provide a (almost) drop-in replacement to the standard
* [`connect`(3)] system call, so it can be used in the Example loop from
* [`getaddrinfo`(3)], for ease of integration in existing projects.
*
* The latest version of this code is available in Git from:
* * https://scm.narf.ssji.net/git/happy-eyeballs-c (authoritative)
* * https://github.com/shtrom/happy-eyeballs-c (mirror)
*
* What follows is an example diff between a simple GAI implementation based on
* the manpage, and the updated version to use this drop-in.
*
* --- gai.c 2019-07-10 21:39:59.827667939 +1000
* +++ happy.c 2019-07-12 17:15:06.288931156 +1000
* @@ -12,10 +12,13 @@
* #include <netdb.h>
* #include <unistd.h>
*
* +#include "rfc6555.h"
* +
* int connect_host(char *host, char *service) {
* struct addrinfo hints;
* struct addrinfo *result, *rp;
* int sfd, s;
* + rfc6555_ctx *ctx;
*
* memset(&hints, 0, sizeof(struct addrinfo));
* hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
* @@ -34,6 +37,9 @@
* // If socket(2) (or connect(2)) fails, we (close the socket
* // and) try the next address.
*
* + rfc6555_reorder(result);
* + ctx = rfc6555_context_create();
* +
* for (rp = result; rp != NULL; rp = rp->ai_next) {
* fprintf(stderr, "connecting using rp %p (%s, af %d) ...",
* rp,
* @@ -44,13 +50,13 @@
* if (sfd == -1)
* continue;
*
* - if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
* + if ((sfd = rfc6555_connect(ctx, sfd, &rp)) != -1)
* break; // Success
*
* fprintf(stderr, " failed!\n");
* perror("error: connecting: ");
* - close(sfd);
* }
* + rfc6555_context_destroy(ctx);
*
* if (rp == NULL) { // No address succeeded
* fprintf(stderr, "failed! (last attempt)\n");
*
* [rfc6555]: https://tools.ietf.org/rfcmarkup/6555
*/
#ifndef __RFC6555_H
#include <unistd.h>
#include <sys/types.h>
typedef struct {
int* fds;
int* original_flags;
struct addrinfo* *rps;
size_t len;
size_t max_len;
int successful_fd;
} rfc6555_ctx;
/* Create context */
rfc6555_ctx *rfc6555_context_create();
/* Destroy context and cleanup resources, except for successful socket, if any */
void rfc6555_context_destroy(rfc6555_ctx *ctx);
/* Loop through result, and place the first-found af_inet entry just after
* the first af_inet6 entry.
* Return 0 if this happened, -1 otherwise.
*/
int rfc6555_reorder(struct addrinfo *result);
/* Add a new socket, for rp, to the list, and perform a new select().
* Return the first socket to successfully connect, or -1 otherwise.
* Additionally, on successful connection, the rp pointer is updated
* to match the returned socket.
*/
int rfc6555_connect(rfc6555_ctx *ctx, int sockfd, struct addrinfo **rp);
#endif /*__RFC6555_H */