1#include "toys.h"
2
3int xsocket(int domain, int type, int protocol)
4{
5 int fd = socket(domain, type, protocol);
6
7 if (fd < 0) perror_exit("socket %x %x", type, protocol);
8 fcntl(fd, F_SETFD, FD_CLOEXEC);
9
10 return fd;
11}
12
13void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len)
14{
15 if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt");
16}
17
18struct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype,
19 int protocol, int flags)
20{
21 struct addrinfo info, *ai;
22 int rc;
23
24 memset(&info, 0, sizeof(struct addrinfo));
25 info.ai_family = family;
26 info.ai_socktype = socktype;
27 info.ai_protocol = protocol;
28 info.ai_flags = flags;
29
30 rc = getaddrinfo(host, port, &info, &ai);
31 if (rc || !ai)
32 error_exit("%s%s%s: %s", host, port ? ":" : "", port ? port : "",
33 rc ? gai_strerror(rc) : "not found");
34
35 return ai;
36}
37
38int xconnbind(struct addrinfo *ai_arg, int dobind)
39{
40 struct addrinfo *ai;
41 int fd = -1;
42
43
44 for (ai = ai_arg; ai; ai = ai->ai_next) {
45 fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
46 ai->ai_protocol);
47 if (!(dobind ? bind : connect)(fd, ai->ai_addr, ai->ai_addrlen)) break;
48 else if (!ai->ai_next) perror_exit_raw(dobind ? "bind" : "connect");
49 close(fd);
50 }
51 freeaddrinfo(ai_arg);
52
53 return fd;
54}
55
56int xconnect(struct addrinfo *ai)
57{
58 return xconnbind(ai, 0);
59}
60
61
62int xbind(struct addrinfo *ai)
63{
64 return xconnbind(ai, 1);
65}
66
67int xpoll(struct pollfd *fds, int nfds, int timeout)
68{
69 int i;
70 long long now, then = timeout>0 ? millitime() : 0;
71
72 for (;;) {
73 if (0<=(i = poll(fds, nfds, timeout)) || toys.signal) return i;
74 if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll");
75 else {
76 now = millitime();
77 timeout -= now-then;
78 then = now;
79 }
80 }
81}
82
83
84
85
86int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout)
87{
88 struct pollfd pollfds[2];
89 int i, pollcount = 2;
90
91 memset(pollfds, 0, 2*sizeof(struct pollfd));
92 pollfds[0].events = pollfds[1].events = POLLIN;
93 pollfds[0].fd = in1;
94 pollfds[1].fd = in2;
95
96
97 for (;;) {
98 if (!xpoll(pollfds, pollcount, timeout)) return pollcount;
99
100 for (i=0; i<pollcount; i++) {
101 if (pollfds[i].revents & POLLIN) {
102 int len = read(pollfds[i].fd, libbuf, sizeof(libbuf));
103 if (len<1) pollfds[i].revents = POLLHUP;
104 else xwrite(i ? out2 : out1, libbuf, len);
105 }
106 if (pollfds[i].revents & POLLHUP) {
107
108
109
110 if (i) {
111 shutdown(pollfds[0].fd, SHUT_WR);
112 pollcount--;
113 timeout = shutdown_timeout;
114 } else return 0;
115 }
116 }
117 }
118}
119
120
121char *ntop(struct sockaddr *sa)
122{
123 void *addr;
124
125 if (sa->sa_family == AF_INET) addr = &((struct sockaddr_in *)sa)->sin_addr;
126 else addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
127
128 inet_ntop(sa->sa_family, addr, libbuf, sizeof(libbuf));
129
130 return libbuf;
131}
132
133void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest)
134{
135 int rc = sendto(sockfd, buf, len, 0, dest,
136 dest->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
137 sizeof(struct sockaddr_in6));
138
139 if (rc != len) perror_exit("sendto");
140}
141