fix compilation
[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 PUBLIC_FN int fnetopen(FILE **in, FILE **out, const char *node, const char *service, const struct addrinfo *hints) {
44   int fd = netopen(node, service, hints);
45   if (fd < 0) return EAI_SYSTEM;
46   int ret = fopen_bistream(in, out, fd, 0);
47   if (ret) close(fd);
48   return ret;
49 }
50
51 HEADER // negative return value for error, else a socket
52 PUBLIC_FN int netopen_server(const char *node /*NULL for ANY*/, const char *service, const struct addrinfo *hints) {
53   struct addrinfo hints_;
54   if (hints == &libjh_tcp_hints) {
55     hints_ = *hints;
56     hints_.ai_flags |= AI_PASSIVE;
57     hints_.ai_flags &= ~AI_ADDRCONFIG;
58     hints = &hints_;
59   }
60
61   struct addrinfo *addrs;
62   int gai_res = getaddrinfo(node, service, hints, &addrs);
63   if (gai_res) return gai_res;
64
65   int s = socket(addrs[0].ai_family, addrs[0].ai_socktype, addrs[0].ai_protocol);
66   if (s == -1) goto err_socket;
67
68   if (bind(s, addrs[0].ai_addr, addrs[0].ai_addrlen)) goto err_bind_n_listen;
69   if (listen(s, 16)) goto err_bind_n_listen;
70
71   freeaddrinfo(addrs);
72   return s;
73
74 err_bind_n_listen:;
75   int errno_ = errno;
76   close(s);
77   errno = errno_;
78 err_socket:
79   freeaddrinfo(addrs);
80   return EAI_SYSTEM;
81 }
82
83 /**********************   SERVER SOCKET STUFF   **********************/
84 HEADER typedef void (*jh_ev_io_ssock_cb)(EV_P_ ev_io *w, int socket);
85 static void ev_io_ssock_cb(EV_P_ ev_io *w, int revents) {
86   jh_ev_io_ssock_cb cb = (jh_ev_io_ssock_cb)w->data;
87   if (revents == EV_ERROR) {
88     cb(EV_A_ w, -1);
89     return;
90   }
91   int fd = accept(w->fd, NULL, NULL);
92   if (fd == -1) {
93     fprintf(stderr, "\nLIBJH ERROR: ACCEPT() FAILED - SLEEPING 1s\n");
94     sleep(1);
95     return;
96   }
97   cb(EV_A_ w, fd);
98 }
99 PUBLIC_FN void jh_ev_io_ssock_init(ev_io *w, jh_ev_io_ssock_cb cb, int fd) {
100   ev_io_init(w, ev_io_ssock_cb, fd, EV_READ);
101   w->data = cb;
102 }