net.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "toys.h"
  2. int xsocket(int domain, int type, int protocol)
  3. {
  4. int fd = socket(domain, type, protocol);
  5. if (fd < 0) perror_exit("socket %x %x", type, protocol);
  6. fcntl(fd, F_SETFD, FD_CLOEXEC);
  7. return fd;
  8. }
  9. void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len)
  10. {
  11. if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt");
  12. }
  13. // if !host bind to all local interfaces
  14. struct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype,
  15. int protocol, int flags)
  16. {
  17. struct addrinfo info, *ai;
  18. int rc;
  19. memset(&info, 0, sizeof(struct addrinfo));
  20. info.ai_family = family;
  21. info.ai_socktype = socktype;
  22. info.ai_protocol = protocol;
  23. info.ai_flags = flags;
  24. if (!host) info.ai_flags |= AI_PASSIVE;
  25. rc = getaddrinfo(host, port, &info, &ai);
  26. if (rc || !ai)
  27. error_exit("%s%s%s: %s", host ? host : "*", port ? ":" : "",
  28. port ? port : "", rc ? gai_strerror(rc) : "not found");
  29. return ai;
  30. }
  31. static int xconnbind(struct addrinfo *ai_arg, int dobind)
  32. {
  33. struct addrinfo *ai;
  34. int fd = -1, one = 1;
  35. // Try all the returned addresses. Report errors if last entry can't connect.
  36. for (ai = ai_arg; ai; ai = ai->ai_next) {
  37. fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
  38. ai->ai_protocol);
  39. xsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  40. if (!(dobind ? bind : connect)(fd, ai->ai_addr, ai->ai_addrlen)) break;
  41. else if (!ai->ai_next) perror_exit_raw(dobind ? "bind" : "connect");
  42. close(fd);
  43. }
  44. freeaddrinfo(ai_arg);
  45. return fd;
  46. }
  47. int xconnectany(struct addrinfo *ai)
  48. {
  49. return xconnbind(ai, 0);
  50. }
  51. int xbindany(struct addrinfo *ai)
  52. {
  53. return xconnbind(ai, 1);
  54. }
  55. void xbind(int fd, const struct sockaddr *sa, socklen_t len)
  56. {
  57. if (bind(fd, sa, len)) perror_exit("bind");
  58. }
  59. void xconnect(int fd, const struct sockaddr *sa, socklen_t len)
  60. {
  61. if (connect(fd, sa, len)) perror_exit("connect");
  62. }
  63. int xpoll(struct pollfd *fds, int nfds, int timeout)
  64. {
  65. int i;
  66. long long now, then = timeout>0 ? millitime() : 0;
  67. for (;;) {
  68. if (0<=(i = poll(fds, nfds, timeout)) || toys.signal) return i;
  69. if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll");
  70. else {
  71. now = millitime();
  72. timeout -= now-then;
  73. then = now;
  74. }
  75. }
  76. }
  77. // Loop forwarding data from in1 to out1 and in2 to out2, handling
  78. // half-connection shutdown. timeouts return if no data for X ms.
  79. // Returns 0: both closed, 1 shutdown_timeout, 2 timeout
  80. int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout)
  81. {
  82. struct pollfd pollfds[2];
  83. int i, pollcount = 2;
  84. memset(pollfds, 0, 2*sizeof(struct pollfd));
  85. pollfds[0].events = pollfds[1].events = POLLIN;
  86. pollfds[0].fd = in1;
  87. pollfds[1].fd = in2;
  88. // Poll loop copying data from each fd to the other one.
  89. for (;;) {
  90. if (!xpoll(pollfds, pollcount, timeout)) return pollcount;
  91. for (i=0; i<pollcount; i++) {
  92. if (pollfds[i].revents & POLLIN) {
  93. int len = read(pollfds[i].fd, libbuf, sizeof(libbuf));
  94. if (len<1) pollfds[i].revents = POLLHUP;
  95. else {
  96. xwrite(i ? out2 : out1, libbuf, len);
  97. continue;
  98. }
  99. }
  100. if (pollfds[i].revents & POLLHUP) {
  101. // Close half-connection. This is needed for things like
  102. // "echo GET / | netcat landley.net 80"
  103. // Note that in1 closing triggers timeout, in2 returns now.
  104. if (i) {
  105. shutdown(pollfds[0].fd, SHUT_WR);
  106. pollcount--;
  107. timeout = shutdown_timeout;
  108. } else return 0;
  109. }
  110. }
  111. }
  112. }
  113. // Return converted ipv4/ipv6 numeric address in libbuf
  114. char *ntop(struct sockaddr *sa)
  115. {
  116. void *addr;
  117. if (sa->sa_family == AF_INET) addr = &((struct sockaddr_in *)sa)->sin_addr;
  118. else addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
  119. inet_ntop(sa->sa_family, addr, libbuf, sizeof(libbuf));
  120. return libbuf;
  121. }
  122. void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest)
  123. {
  124. int rc = sendto(sockfd, buf, len, 0, dest,
  125. dest->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
  126. sizeof(struct sockaddr_in6));
  127. if (rc != len) perror_exit("sendto");
  128. }
  129. // xrecvfrom with timeout in milliseconds
  130. int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout)
  131. {
  132. socklen_t sl = sizeof(*sa);
  133. if (timeout >= 0) {
  134. struct pollfd pfd;
  135. pfd.fd = fd;
  136. pfd.events = POLLIN;
  137. if (!xpoll(&pfd, 1, timeout)) return 0;
  138. }
  139. len = recvfrom(fd, buf, len, 0, (void *)sa, &sl);
  140. if (len<0) perror_exit("recvfrom");
  141. return len;
  142. }
  143. // Convert space/low ascii to %XX escapes, plus any chars in "and" string.
  144. // Returns newly allocated copy of string (even if no changes)
  145. char *escape_url(char *str, char *and)
  146. {
  147. int i, j , count;
  148. char *ret QUIET, *ss QUIET;
  149. for (j = count = 0;;) {
  150. for (i = 0;;) {
  151. if (str[i] && (str[i]<=' ' || (and && strchr(and, str[i])))) {
  152. if (j) ss += sprintf(ss, "%%%02x", str[i]);
  153. else count++;
  154. } else if (j) *ss++ = str[i];
  155. if (!str[i++]) break;
  156. }
  157. if (j++) break;
  158. ret = ss = xmalloc(i+count*2);
  159. }
  160. return ret;
  161. }
  162. // Convert %XX escapes to character (in place)
  163. void unescape_url(char *str)
  164. {
  165. char *to;
  166. int i;
  167. for (to = str;;) {
  168. if (*str!='%' || !isxdigit(str[1]) || !isxdigit(str[2])) {
  169. if (!(*to++ = *str++)) break;
  170. } else {
  171. sscanf(++str, "%2x", &i);
  172. *to++ = i;
  173. str += 2;
  174. }
  175. }
  176. }