8d67e71be62b551f4eed403da97de9b992cf3690
[libjh.git] / net.c
1 HEADER #include <netdb.h>
2
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <netinet/tcp.h>
7 #include <unistd.h>
8 #include <errno.h>
9
10 HEADER extern const struct addrinfo libjh_tcp_hints;
11 HEADER #define JH_TCP_HINTS (&libjh_tcp_hints)
12 const struct addrinfo libjh_tcp_hints = {
13   .ai_flags = AI_ADDRCONFIG,
14   .ai_family = AF_UNSPEC,
15   .ai_socktype = SOCK_STREAM,
16   .ai_protocol = 0
17 };
18
19 // negative return value: interpret as a getaddrinfo() error (non-gai errors become EAI_SYSTEM)
20 // >=0 return value: interpret as resulting fd
21 PUBLIC_FN int netopen(const char *node, const char *service, const struct addrinfo *hints) {
22   struct addrinfo *addrs;
23   int gai_res = getaddrinfo(node, service, hints, &addrs);
24   if (gai_res) return gai_res;
25
26   int s = socket(addrs[0].ai_family, addrs[0].ai_socktype, addrs[0].ai_protocol);
27   if (s == -1) goto err_socket;
28
29   if (connect(s, addrs[0].ai_addr, addrs[0].ai_addrlen)) goto err_connect;
30
31   freeaddrinfo(addrs);
32   return s;
33
34 err_connect:;
35   int errno_ = errno;
36   close(s);
37   errno = errno_;
38 err_socket:
39   freeaddrinfo(addrs);
40   return EAI_SYSTEM;
41 }
42
43 // err points to where the error from netopen() should be stored
44 PUBLIC_FN FILE *fnetopen(const char *node, const char *service, const struct addrinfo *hints, int *err) {
45   int rval = netopen(node, service, hints);
46   if (rval < 0) goto err;
47
48   FILE *res = fdopen(rval, "r+");
49   if (res) return res;
50
51   int errno_ = errno;
52   close(rval);
53   errno = errno_;
54   rval = EAI_SYSTEM;
55
56 err:
57   if (err) *err = rval;
58   return NULL;
59 }