select.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. ***************************************************************************/
  23. #include "setup.h"
  24. #include <errno.h>
  25. #ifdef HAVE_SYS_TYPES_H
  26. #include <sys/types.h>
  27. #endif
  28. #ifdef HAVE_SYS_SELECT_H
  29. #include <sys/select.h>
  30. #endif
  31. #ifdef HAVE_SYS_TIME_H
  32. #include <sys/time.h>
  33. #endif
  34. #ifndef HAVE_SELECT
  35. #error "We can't compile without select() support!"
  36. #endif
  37. #ifdef __BEOS__
  38. /* BeOS has FD_SET defined in socket.h */
  39. #include <socket.h>
  40. #endif
  41. #ifdef __MSDOS__
  42. #include <dos.h> /* delay() */
  43. #endif
  44. #include <curl/curl.h>
  45. #include "urldata.h"
  46. #include "connect.h"
  47. #include "select.h"
  48. #if defined(USE_WINSOCK) || defined(TPF)
  49. #define VERIFY_SOCK(x) /* sockets are not in range [0..FD_SETSIZE] */
  50. #else
  51. #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
  52. #define VERIFY_SOCK(x) do { \
  53. if(!VALID_SOCK(x)) { \
  54. errno = EINVAL; \
  55. return -1; \
  56. } \
  57. } while(0)
  58. #endif
  59. /*
  60. * This is an internal function used for waiting for read or write
  61. * events on single file descriptors. It attempts to replace select()
  62. * in order to avoid limits with FD_SETSIZE.
  63. *
  64. * Return values:
  65. * -1 = system call error
  66. * 0 = timeout
  67. * CSELECT_IN | CSELECT_OUT | CSELECT_ERR
  68. */
  69. int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
  70. {
  71. #if defined(HAVE_POLL_FINE) || defined(CURL_HAVE_WSAPOLL)
  72. struct pollfd pfd[2];
  73. int num;
  74. int r;
  75. int ret;
  76. num = 0;
  77. if (readfd != CURL_SOCKET_BAD) {
  78. pfd[num].fd = readfd;
  79. pfd[num].events = POLLIN;
  80. num++;
  81. }
  82. if (writefd != CURL_SOCKET_BAD) {
  83. pfd[num].fd = writefd;
  84. pfd[num].events = POLLOUT;
  85. num++;
  86. }
  87. #ifdef HAVE_POLL_FINE
  88. do {
  89. r = poll(pfd, num, timeout_ms);
  90. } while((r == -1) && (errno == EINTR));
  91. #else
  92. r = WSAPoll(pfd, num, timeout_ms);
  93. #endif
  94. if (r < 0)
  95. return -1;
  96. if (r == 0)
  97. return 0;
  98. ret = 0;
  99. num = 0;
  100. if (readfd != CURL_SOCKET_BAD) {
  101. if (pfd[num].revents & (POLLIN|POLLHUP))
  102. ret |= CSELECT_IN;
  103. if (pfd[num].revents & POLLERR) {
  104. #ifdef __CYGWIN__
  105. /* Cygwin 1.5.21 needs this hack to pass test 160 */
  106. if (errno == EINPROGRESS)
  107. ret |= CSELECT_IN;
  108. else
  109. #endif
  110. ret |= CSELECT_ERR;
  111. }
  112. num++;
  113. }
  114. if (writefd != CURL_SOCKET_BAD) {
  115. if (pfd[num].revents & POLLOUT)
  116. ret |= CSELECT_OUT;
  117. if (pfd[num].revents & (POLLERR|POLLHUP))
  118. ret |= CSELECT_ERR;
  119. }
  120. return ret;
  121. #else
  122. struct timeval timeout;
  123. fd_set fds_read;
  124. fd_set fds_write;
  125. fd_set fds_err;
  126. curl_socket_t maxfd;
  127. int r;
  128. int ret;
  129. timeout.tv_sec = timeout_ms / 1000;
  130. timeout.tv_usec = (timeout_ms % 1000) * 1000;
  131. if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) {
  132. /* According to POSIX we should pass in NULL pointers if we don't want to
  133. wait for anything in particular but just use the timeout function.
  134. Windows however returns immediately if done so. I copied the MSDOS
  135. delay() use from src/main.c that already had this work-around. */
  136. #ifdef WIN32
  137. Sleep(timeout_ms);
  138. #elif defined(__MSDOS__)
  139. delay(timeout_ms);
  140. #else
  141. select(0, NULL, NULL, NULL, &timeout);
  142. #endif
  143. return 0;
  144. }
  145. FD_ZERO(&fds_err);
  146. maxfd = (curl_socket_t)-1;
  147. FD_ZERO(&fds_read);
  148. if (readfd != CURL_SOCKET_BAD) {
  149. VERIFY_SOCK(readfd);
  150. FD_SET(readfd, &fds_read);
  151. FD_SET(readfd, &fds_err);
  152. maxfd = readfd;
  153. }
  154. FD_ZERO(&fds_write);
  155. if (writefd != CURL_SOCKET_BAD) {
  156. VERIFY_SOCK(writefd);
  157. FD_SET(writefd, &fds_write);
  158. FD_SET(writefd, &fds_err);
  159. if (writefd > maxfd)
  160. maxfd = writefd;
  161. }
  162. do {
  163. r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
  164. } while((r == -1) && (Curl_sockerrno() == EINTR));
  165. if (r < 0)
  166. return -1;
  167. if (r == 0)
  168. return 0;
  169. ret = 0;
  170. if (readfd != CURL_SOCKET_BAD) {
  171. if (FD_ISSET(readfd, &fds_read))
  172. ret |= CSELECT_IN;
  173. if (FD_ISSET(readfd, &fds_err))
  174. ret |= CSELECT_ERR;
  175. }
  176. if (writefd != CURL_SOCKET_BAD) {
  177. if (FD_ISSET(writefd, &fds_write))
  178. ret |= CSELECT_OUT;
  179. if (FD_ISSET(writefd, &fds_err))
  180. ret |= CSELECT_ERR;
  181. }
  182. return ret;
  183. #endif
  184. }
  185. /*
  186. * This is a wrapper around poll(). If poll() does not exist, then
  187. * select() is used instead. An error is returned if select() is
  188. * being used and a file descriptor too large for FD_SETSIZE.
  189. *
  190. * Return values:
  191. * -1 = system call error or fd >= FD_SETSIZE
  192. * 0 = timeout
  193. * 1 = number of structures with non zero revent fields
  194. */
  195. int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
  196. {
  197. int r;
  198. #ifdef HAVE_POLL_FINE
  199. do {
  200. r = poll(ufds, nfds, timeout_ms);
  201. } while((r == -1) && (errno == EINTR));
  202. #elif defined(CURL_HAVE_WSAPOLL)
  203. r = WSAPoll(ufds, nfds, timeout_ms);
  204. #else
  205. struct timeval timeout;
  206. struct timeval *ptimeout;
  207. fd_set fds_read;
  208. fd_set fds_write;
  209. fd_set fds_err;
  210. curl_socket_t maxfd;
  211. unsigned int i;
  212. FD_ZERO(&fds_read);
  213. FD_ZERO(&fds_write);
  214. FD_ZERO(&fds_err);
  215. maxfd = (curl_socket_t)-1;
  216. for (i = 0; i < nfds; i++) {
  217. if (ufds[i].fd == CURL_SOCKET_BAD)
  218. continue;
  219. #ifndef USE_WINSOCK /* winsock sockets are not in range [0..FD_SETSIZE] */
  220. if (ufds[i].fd >= FD_SETSIZE) {
  221. errno = EINVAL;
  222. return -1;
  223. }
  224. #endif
  225. if (ufds[i].fd > maxfd)
  226. maxfd = ufds[i].fd;
  227. if (ufds[i].events & POLLIN)
  228. FD_SET(ufds[i].fd, &fds_read);
  229. if (ufds[i].events & POLLOUT)
  230. FD_SET(ufds[i].fd, &fds_write);
  231. if (ufds[i].events & POLLERR)
  232. FD_SET(ufds[i].fd, &fds_err);
  233. }
  234. if (timeout_ms < 0) {
  235. ptimeout = NULL; /* wait forever */
  236. } else {
  237. timeout.tv_sec = timeout_ms / 1000;
  238. timeout.tv_usec = (timeout_ms % 1000) * 1000;
  239. ptimeout = &timeout;
  240. }
  241. do {
  242. r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
  243. } while((r == -1) && (Curl_sockerrno() == EINTR));
  244. if (r < 0)
  245. return -1;
  246. if (r == 0)
  247. return 0;
  248. r = 0;
  249. for (i = 0; i < nfds; i++) {
  250. ufds[i].revents = 0;
  251. if (ufds[i].fd == CURL_SOCKET_BAD)
  252. continue;
  253. if (FD_ISSET(ufds[i].fd, &fds_read))
  254. ufds[i].revents |= POLLIN;
  255. if (FD_ISSET(ufds[i].fd, &fds_write))
  256. ufds[i].revents |= POLLOUT;
  257. if (FD_ISSET(ufds[i].fd, &fds_err))
  258. ufds[i].revents |= POLLERR;
  259. if (ufds[i].revents != 0)
  260. r++;
  261. }
  262. #endif
  263. return r;
  264. }
  265. #ifdef TPF
  266. /*
  267. * This is a replacement for select() on the TPF platform.
  268. * It is used whenever libcurl calls select().
  269. * The call below to tpf_process_signals() is required because
  270. * TPF's select calls are not signal interruptible.
  271. *
  272. * Return values are the same as select's.
  273. */
  274. int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
  275. fd_set* excepts, struct timeval* tv)
  276. {
  277. int rc;
  278. rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
  279. tpf_process_signals();
  280. return(rc);
  281. }
  282. #endif /* TPF */