10f66f451Sopenharmony_ci#include "toys.h" 20f66f451Sopenharmony_ci 30f66f451Sopenharmony_ciint xsocket(int domain, int type, int protocol) 40f66f451Sopenharmony_ci{ 50f66f451Sopenharmony_ci int fd = socket(domain, type, protocol); 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ci if (fd < 0) perror_exit("socket %x %x", type, protocol); 80f66f451Sopenharmony_ci fcntl(fd, F_SETFD, FD_CLOEXEC); 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ci return fd; 110f66f451Sopenharmony_ci} 120f66f451Sopenharmony_ci 130f66f451Sopenharmony_civoid xsetsockopt(int fd, int level, int opt, void *val, socklen_t len) 140f66f451Sopenharmony_ci{ 150f66f451Sopenharmony_ci if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt"); 160f66f451Sopenharmony_ci} 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ci// if !host bind to all local interfaces 190f66f451Sopenharmony_cistruct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype, 200f66f451Sopenharmony_ci int protocol, int flags) 210f66f451Sopenharmony_ci{ 220f66f451Sopenharmony_ci struct addrinfo info, *ai; 230f66f451Sopenharmony_ci int rc; 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci memset(&info, 0, sizeof(struct addrinfo)); 260f66f451Sopenharmony_ci info.ai_family = family; 270f66f451Sopenharmony_ci info.ai_socktype = socktype; 280f66f451Sopenharmony_ci info.ai_protocol = protocol; 290f66f451Sopenharmony_ci info.ai_flags = flags; 300f66f451Sopenharmony_ci if (!host) info.ai_flags |= AI_PASSIVE; 310f66f451Sopenharmony_ci 320f66f451Sopenharmony_ci rc = getaddrinfo(host, port, &info, &ai); 330f66f451Sopenharmony_ci if (rc || !ai) 340f66f451Sopenharmony_ci error_exit("%s%s%s: %s", host ? host : "*", port ? ":" : "", 350f66f451Sopenharmony_ci port ? port : "", rc ? gai_strerror(rc) : "not found"); 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci return ai; 380f66f451Sopenharmony_ci} 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_cistatic int xconnbind(struct addrinfo *ai_arg, int dobind) 410f66f451Sopenharmony_ci{ 420f66f451Sopenharmony_ci struct addrinfo *ai; 430f66f451Sopenharmony_ci int fd = -1, one = 1; 440f66f451Sopenharmony_ci 450f66f451Sopenharmony_ci // Try all the returned addresses. Report errors if last entry can't connect. 460f66f451Sopenharmony_ci for (ai = ai_arg; ai; ai = ai->ai_next) { 470f66f451Sopenharmony_ci fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype, 480f66f451Sopenharmony_ci ai->ai_protocol); 490f66f451Sopenharmony_ci xsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 500f66f451Sopenharmony_ci if (!(dobind ? bind : connect)(fd, ai->ai_addr, ai->ai_addrlen)) break; 510f66f451Sopenharmony_ci else if (!ai->ai_next) perror_exit_raw(dobind ? "bind" : "connect"); 520f66f451Sopenharmony_ci close(fd); 530f66f451Sopenharmony_ci } 540f66f451Sopenharmony_ci freeaddrinfo(ai_arg); 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci return fd; 570f66f451Sopenharmony_ci} 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_ciint xconnectany(struct addrinfo *ai) 600f66f451Sopenharmony_ci{ 610f66f451Sopenharmony_ci return xconnbind(ai, 0); 620f66f451Sopenharmony_ci} 630f66f451Sopenharmony_ci 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ciint xbindany(struct addrinfo *ai) 660f66f451Sopenharmony_ci{ 670f66f451Sopenharmony_ci return xconnbind(ai, 1); 680f66f451Sopenharmony_ci} 690f66f451Sopenharmony_ci 700f66f451Sopenharmony_civoid xbind(int fd, const struct sockaddr *sa, socklen_t len) 710f66f451Sopenharmony_ci{ 720f66f451Sopenharmony_ci if (bind(fd, sa, len)) perror_exit("bind"); 730f66f451Sopenharmony_ci} 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_civoid xconnect(int fd, const struct sockaddr *sa, socklen_t len) 760f66f451Sopenharmony_ci{ 770f66f451Sopenharmony_ci if (connect(fd, sa, len)) perror_exit("connect"); 780f66f451Sopenharmony_ci} 790f66f451Sopenharmony_ci 800f66f451Sopenharmony_ciint xpoll(struct pollfd *fds, int nfds, int timeout) 810f66f451Sopenharmony_ci{ 820f66f451Sopenharmony_ci int i; 830f66f451Sopenharmony_ci long long now, then = timeout>0 ? millitime() : 0; 840f66f451Sopenharmony_ci 850f66f451Sopenharmony_ci for (;;) { 860f66f451Sopenharmony_ci if (0<=(i = poll(fds, nfds, timeout)) || toys.signal) return i; 870f66f451Sopenharmony_ci if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll"); 880f66f451Sopenharmony_ci else { 890f66f451Sopenharmony_ci now = millitime(); 900f66f451Sopenharmony_ci timeout -= now-then; 910f66f451Sopenharmony_ci then = now; 920f66f451Sopenharmony_ci } 930f66f451Sopenharmony_ci } 940f66f451Sopenharmony_ci} 950f66f451Sopenharmony_ci 960f66f451Sopenharmony_ci// Loop forwarding data from in1 to out1 and in2 to out2, handling 970f66f451Sopenharmony_ci// half-connection shutdown. timeouts return if no data for X ms. 980f66f451Sopenharmony_ci// Returns 0: both closed, 1 shutdown_timeout, 2 timeout 990f66f451Sopenharmony_ciint pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout) 1000f66f451Sopenharmony_ci{ 1010f66f451Sopenharmony_ci struct pollfd pollfds[2]; 1020f66f451Sopenharmony_ci int i, pollcount = 2; 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci memset(pollfds, 0, 2*sizeof(struct pollfd)); 1050f66f451Sopenharmony_ci pollfds[0].events = pollfds[1].events = POLLIN; 1060f66f451Sopenharmony_ci pollfds[0].fd = in1; 1070f66f451Sopenharmony_ci pollfds[1].fd = in2; 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_ci // Poll loop copying data from each fd to the other one. 1100f66f451Sopenharmony_ci for (;;) { 1110f66f451Sopenharmony_ci if (!xpoll(pollfds, pollcount, timeout)) return pollcount; 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci for (i=0; i<pollcount; i++) { 1140f66f451Sopenharmony_ci if (pollfds[i].revents & POLLIN) { 1150f66f451Sopenharmony_ci int len = read(pollfds[i].fd, libbuf, sizeof(libbuf)); 1160f66f451Sopenharmony_ci if (len<1) pollfds[i].revents = POLLHUP; 1170f66f451Sopenharmony_ci else xwrite(i ? out2 : out1, libbuf, len); 1180f66f451Sopenharmony_ci } 1190f66f451Sopenharmony_ci if (pollfds[i].revents & POLLHUP) { 1200f66f451Sopenharmony_ci // Close half-connection. This is needed for things like 1210f66f451Sopenharmony_ci // "echo GET / | netcat landley.net 80" 1220f66f451Sopenharmony_ci // Note that in1 closing triggers timeout, in2 returns now. 1230f66f451Sopenharmony_ci if (i) { 1240f66f451Sopenharmony_ci shutdown(pollfds[0].fd, SHUT_WR); 1250f66f451Sopenharmony_ci pollcount--; 1260f66f451Sopenharmony_ci timeout = shutdown_timeout; 1270f66f451Sopenharmony_ci } else return 0; 1280f66f451Sopenharmony_ci } 1290f66f451Sopenharmony_ci } 1300f66f451Sopenharmony_ci } 1310f66f451Sopenharmony_ci} 1320f66f451Sopenharmony_ci 1330f66f451Sopenharmony_ci// Return converted ipv4/ipv6 numeric address in libbuf 1340f66f451Sopenharmony_cichar *ntop(struct sockaddr *sa) 1350f66f451Sopenharmony_ci{ 1360f66f451Sopenharmony_ci void *addr; 1370f66f451Sopenharmony_ci 1380f66f451Sopenharmony_ci if (sa->sa_family == AF_INET) addr = &((struct sockaddr_in *)sa)->sin_addr; 1390f66f451Sopenharmony_ci else addr = &((struct sockaddr_in6 *)sa)->sin6_addr; 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci inet_ntop(sa->sa_family, addr, libbuf, sizeof(libbuf)); 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci return libbuf; 1440f66f451Sopenharmony_ci} 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_civoid xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest) 1470f66f451Sopenharmony_ci{ 1480f66f451Sopenharmony_ci int rc = sendto(sockfd, buf, len, 0, dest, 1490f66f451Sopenharmony_ci dest->sa_family == AF_INET ? sizeof(struct sockaddr_in) : 1500f66f451Sopenharmony_ci sizeof(struct sockaddr_in6)); 1510f66f451Sopenharmony_ci 1520f66f451Sopenharmony_ci if (rc != len) perror_exit("sendto"); 1530f66f451Sopenharmony_ci} 1540f66f451Sopenharmony_ci 1550f66f451Sopenharmony_ci// xrecvfrom with timeout in milliseconds 1560f66f451Sopenharmony_ciint xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout) 1570f66f451Sopenharmony_ci{ 1580f66f451Sopenharmony_ci socklen_t sl = sizeof(*sa); 1590f66f451Sopenharmony_ci 1600f66f451Sopenharmony_ci if (timeout >= 0) { 1610f66f451Sopenharmony_ci struct pollfd pfd; 1620f66f451Sopenharmony_ci 1630f66f451Sopenharmony_ci pfd.fd = fd; 1640f66f451Sopenharmony_ci pfd.events = POLLIN; 1650f66f451Sopenharmony_ci if (!xpoll(&pfd, 1, timeout)) return 0; 1660f66f451Sopenharmony_ci } 1670f66f451Sopenharmony_ci 1680f66f451Sopenharmony_ci len = recvfrom(fd, buf, len, 0, (void *)sa, &sl); 1690f66f451Sopenharmony_ci if (len<0) perror_exit("recvfrom"); 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_ci return len; 1720f66f451Sopenharmony_ci} 173