You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

249 lines
4.8 KiB

  1. #include "netutil.h"
  2. #include "compat.h"
  3. #include <errno.h>
  4. #include <sys/types.h>
  5. #include <stdio.h>
  6. /* Initialize networking */
  7. void net_init(void)
  8. {
  9. #ifdef __WIN32__
  10. WSADATA blah;
  11. WSAStartup(0x0101, &blah);
  12. #endif
  13. }
  14. /* Set socket blocking/nonblocking */
  15. int soblock(int socket, int blocking)
  16. {
  17. #ifdef __WIN32__
  18. unsigned long arg = blocking ? 0 : 1;
  19. if (ioctlsocket(socket, FIONBIO, &arg) != 0)
  20. return -1;
  21. return 0;
  22. #else
  23. int sockopt;
  24. /* Get flags */
  25. sockopt = fcntl(socket, F_GETFL);
  26. if (sockopt == -1) {
  27. return -1;
  28. }
  29. /* Modify */
  30. if (blocking)
  31. sockopt &= ~O_NONBLOCK;
  32. else
  33. sockopt |= O_NONBLOCK;
  34. /* Set flags */
  35. if (fcntl(socket, F_SETFL, sockopt) != 0)
  36. return -1;
  37. return 0;
  38. #endif
  39. }
  40. /* Like connect(2), but with a timeout. Socket must be non-blocking. */
  41. int
  42. connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen,
  43. struct timeval *timeout)
  44. {
  45. int ret;
  46. fd_set writefds;
  47. fd_set exceptfds;
  48. int optval;
  49. socklen_t optlen;
  50. /* Start connect */
  51. ret = connect(s, serv_addr, addrlen);
  52. if (ret == 0) {
  53. /* Success */
  54. return 0;
  55. }
  56. /* Check for immediate failure */
  57. #ifdef __WIN32__
  58. errno = WSAGetLastError();
  59. if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL)
  60. return -1;
  61. #else
  62. if (ret < 0 && errno != EINPROGRESS && errno != EALREADY)
  63. return -1;
  64. #endif
  65. /* In progress, wait for result. */
  66. FD_ZERO(&writefds);
  67. FD_SET(s, &writefds);
  68. FD_ZERO(&exceptfds);
  69. FD_SET(s, &exceptfds);
  70. ret = select(s + 1, NULL, &writefds, &exceptfds, timeout);
  71. if (ret < 0) {
  72. /* Error */
  73. return -1;
  74. }
  75. if (ret == 0) {
  76. /* Timed out */
  77. errno = ETIMEDOUT;
  78. return -1;
  79. }
  80. /* Check the socket state */
  81. optlen = sizeof(optval);
  82. if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen) != 0)
  83. return -1;
  84. if (optval != 0) {
  85. /* Connection failed. */
  86. errno = optval;
  87. return -1;
  88. }
  89. /* On Windows, SO_ERROR sometimes shows no error but the connection
  90. still failed. Sigh. */
  91. if (FD_ISSET(s, &exceptfds) || !FD_ISSET(s, &writefds)) {
  92. errno = EIO;
  93. return -1;
  94. }
  95. /* Success */
  96. return 0;
  97. }
  98. /* Like send(2), but with a timeout. Socket must be non-blocking.
  99. The timeout only applies if no data at all is sent -- this function
  100. may still send less than requested. */
  101. ssize_t
  102. send_timeout(int s, const void *buf, size_t len, int flags,
  103. struct timeval * timeout)
  104. {
  105. fd_set writefds;
  106. int ret;
  107. FD_ZERO(&writefds);
  108. FD_SET(s, &writefds);
  109. ret = select(s + 1, NULL, &writefds, NULL, timeout);
  110. if (ret == 0) {
  111. /* Timed out */
  112. errno = ETIMEDOUT;
  113. return -1;
  114. }
  115. if (ret != 1) {
  116. /* Error */
  117. return -1;
  118. }
  119. return send(s, buf, len, flags);
  120. }
  121. /* Like recv(2), but with a timeout. Socket must be non-blocking.
  122. The timeout only applies if no data at all is received -- this
  123. function may still return less than requested. */
  124. ssize_t
  125. recv_timeout(int s, void *buf, size_t len, int flags, struct timeval * timeout)
  126. {
  127. fd_set readfds;
  128. int ret;
  129. FD_ZERO(&readfds);
  130. FD_SET(s, &readfds);
  131. ret = select(s + 1, &readfds, NULL, NULL, timeout);
  132. if (ret == 0) {
  133. /* Timed out */
  134. errno = ETIMEDOUT;
  135. return -1;
  136. }
  137. if (ret != 1) {
  138. /* Error */
  139. return -1;
  140. }
  141. return recv(s, buf, len, flags);
  142. }
  143. /* Like recvfrom(2), but with a timeout. Socket must be non-blocking.
  144. The timeout only applies if no data at all is received -- this
  145. function may still return less than requested. */
  146. ssize_t
  147. recvfrom_timeout(int s, void *buf, size_t len, int flags,
  148. struct sockaddr * address, socklen_t * address_len,
  149. struct timeval * timeout)
  150. {
  151. fd_set readfds;
  152. int ret;
  153. FD_ZERO(&readfds);
  154. FD_SET(s, &readfds);
  155. ret = select(s + 1, &readfds, NULL, NULL, timeout);
  156. if (ret == 0) {
  157. /* Timed out */
  158. errno = ETIMEDOUT;
  159. return -1;
  160. }
  161. if (ret != 1) {
  162. /* Error */
  163. return -1;
  164. }
  165. return recvfrom(s, buf, len, flags, address, address_len);
  166. }
  167. /* Like send_timeout, but retries (with the same timeout) in case of
  168. partial transfers. This is a stronger attempt to send all
  169. requested data. */
  170. ssize_t
  171. send_all_timeout(int s, const void *buf, size_t len, int flags,
  172. struct timeval * timeout)
  173. {
  174. struct timeval tv;
  175. size_t left = len;
  176. ssize_t ret;
  177. while (left > 0) {
  178. tv.tv_sec = timeout->tv_sec;
  179. tv.tv_usec = timeout->tv_usec;
  180. ret = send_timeout(s, buf, left, flags, &tv);
  181. if (ret < 0)
  182. return ret;
  183. if (ret == 0)
  184. break;
  185. left -= ret;
  186. buf += ret;
  187. }
  188. return len - left;
  189. }
  190. /* Like recv_timeout, but retries (with the same timeout) in case of
  191. partial transfers. This is a stronger attempt to recv all
  192. requested data. */
  193. ssize_t
  194. recv_all_timeout(int s, void *buf, size_t len, int flags,
  195. struct timeval * timeout)
  196. {
  197. struct timeval tv;
  198. size_t left = len;
  199. ssize_t ret;
  200. while (left > 0) {
  201. tv.tv_sec = timeout->tv_sec;
  202. tv.tv_usec = timeout->tv_usec;
  203. ret = recv_timeout(s, buf, left, flags, &tv);
  204. if (ret < 0)
  205. return ret;
  206. if (ret == 0)
  207. break;
  208. left -= ret;
  209. buf += ret;
  210. }
  211. return len - left;
  212. }