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