1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 ***************************************************************************/
22
23#include "setup.h"
24
25#ifdef HAVE_SYS_SELECT_H
26#include <sys/select.h>
27#endif
28#ifdef HAVE_SYS_TIME_H
29#include <sys/time.h>
30#endif
31
32#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
33#error "We can't compile without select() or poll() support."
34#endif
35
36#if defined(__BEOS__) && !defined(__HAIKU__)
37/* BeOS has FD_SET defined in socket.h */
38#include <socket.h>
39#endif
40
41#ifdef MSDOS
42#include <dos.h>  /* delay() */
43#endif
44
45#include <curl/curl.h>
46
47#include "urldata.h"
48#include "connect.h"
49#include "select.h"
50#include "warnless.h"
51
52/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */
53
54#if defined(USE_WINSOCK) || defined(TPF)
55#define VERIFY_SOCK(x) do { } while(0)
56#else
57#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
58#define VERIFY_SOCK(x) do { \
59  if(!VALID_SOCK(x)) { \
60    SET_SOCKERRNO(EINVAL); \
61    return -1; \
62  } \
63} while(0)
64#endif
65
66/* Convenience local macros */
67
68#define elapsed_ms  (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
69
70#ifdef CURL_ACKNOWLEDGE_EINTR
71#define error_not_EINTR (1)
72#else
73#define error_not_EINTR (error != EINTR)
74#endif
75
76/*
77 * Internal function used for waiting a specific amount of ms
78 * in Curl_socket_ready() and Curl_poll() when no file descriptor
79 * is provided to wait on, just being used to delay execution.
80 * WinSock select() and poll() timeout mechanisms need a valid
81 * socket descriptor in a not null file descriptor set to work.
82 * Waiting indefinitely with this function is not allowed, a
83 * zero or negative timeout value will return immediately.
84 * Timeout resolution, accuracy, as well as maximum supported
85 * value is system dependent, neither factor is a citical issue
86 * for the intended use of this function in the library.
87 * On non-DOS and non-Winsock platforms, when compiled with
88 * CURL_ACKNOWLEDGE_EINTR defined, EINTR condition is honored
89 * and function might exit early without awaiting full timeout,
90 * otherwise EINTR will be ignored and full timeout will elapse.
91 *
92 * Return values:
93 *   -1 = system call error, invalid timeout value, or interrupted
94 *    0 = specified timeout has elapsed
95 */
96static int wait_ms(int timeout_ms)
97{
98#if !defined(MSDOS) && !defined(USE_WINSOCK)
99#ifndef HAVE_POLL_FINE
100  struct timeval pending_tv;
101#endif
102  struct timeval initial_tv;
103  int pending_ms;
104  int error;
105#endif
106  int r = 0;
107
108  if(!timeout_ms)
109    return 0;
110  if(timeout_ms < 0) {
111    SET_SOCKERRNO(EINVAL);
112    return -1;
113  }
114#if defined(MSDOS)
115  delay(timeout_ms);
116#elif defined(USE_WINSOCK)
117  Sleep(timeout_ms);
118#else
119  pending_ms = timeout_ms;
120  initial_tv = curlx_tvnow();
121  do {
122#if defined(HAVE_POLL_FINE)
123    r = poll(NULL, 0, pending_ms);
124#else
125    pending_tv.tv_sec = pending_ms / 1000;
126    pending_tv.tv_usec = (pending_ms % 1000) * 1000;
127    r = select(0, NULL, NULL, NULL, &pending_tv);
128#endif /* HAVE_POLL_FINE */
129    if(r != -1)
130      break;
131    error = SOCKERRNO;
132    if(error && error_not_EINTR)
133      break;
134    pending_ms = timeout_ms - elapsed_ms;
135    if(pending_ms <= 0)
136      break;
137  } while(r == -1);
138#endif /* USE_WINSOCK */
139  if(r)
140    r = -1;
141  return r;
142}
143
144/*
145 * This is an internal function used for waiting for read or write
146 * events on a pair of file descriptors.  It uses poll() when a fine
147 * poll() is available, in order to avoid limits with FD_SETSIZE,
148 * otherwise select() is used.  An error is returned if select() is
149 * being used and a file descriptor is too large for FD_SETSIZE.
150 * A negative timeout value makes this function wait indefinitely,
151 * unles no valid file descriptor is given, when this happens the
152 * negative timeout is ignored and the function times out immediately.
153 * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
154 * is honored and function might exit early without awaiting timeout,
155 * otherwise EINTR will be ignored.
156 *
157 * Return values:
158 *   -1 = system call error or fd >= FD_SETSIZE
159 *    0 = timeout
160 *    CURL_CSELECT_IN | CURL_CSELECT_OUT | CURL_CSELECT_ERR
161 */
162int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd,
163                      long timeout_ms)
164{
165#ifdef HAVE_POLL_FINE
166  struct pollfd pfd[2];
167  int num;
168#else
169  struct timeval pending_tv;
170  struct timeval *ptimeout;
171  fd_set fds_read;
172  fd_set fds_write;
173  fd_set fds_err;
174  curl_socket_t maxfd;
175#endif
176  struct timeval initial_tv = {0,0};
177  int pending_ms = 0;
178  int error;
179  int r;
180  int ret;
181
182  if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) {
183    r = wait_ms((int)timeout_ms);
184    return r;
185  }
186
187  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
188     time in this function does not need to be measured. This happens
189     when function is called with a zero timeout or a negative timeout
190     value indicating a blocking call should be performed. */
191
192  if(timeout_ms > 0) {
193    pending_ms = (int)timeout_ms;
194    initial_tv = curlx_tvnow();
195  }
196
197#ifdef HAVE_POLL_FINE
198
199  num = 0;
200  if(readfd != CURL_SOCKET_BAD) {
201    pfd[num].fd = readfd;
202    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
203    pfd[num].revents = 0;
204    num++;
205  }
206  if(writefd != CURL_SOCKET_BAD) {
207    pfd[num].fd = writefd;
208    pfd[num].events = POLLWRNORM|POLLOUT;
209    pfd[num].revents = 0;
210    num++;
211  }
212
213  do {
214    if(timeout_ms < 0)
215      pending_ms = -1;
216    else if(!timeout_ms)
217      pending_ms = 0;
218    r = poll(pfd, num, pending_ms);
219    if(r != -1)
220      break;
221    error = SOCKERRNO;
222    if(error && error_not_EINTR)
223      break;
224    if(timeout_ms > 0) {
225      pending_ms = (int)(timeout_ms - elapsed_ms);
226      if(pending_ms <= 0)
227        break;
228    }
229  } while(r == -1);
230
231  if(r < 0)
232    return -1;
233  if(r == 0)
234    return 0;
235
236  ret = 0;
237  num = 0;
238  if(readfd != CURL_SOCKET_BAD) {
239    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
240      ret |= CURL_CSELECT_IN;
241    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
242      ret |= CURL_CSELECT_ERR;
243    num++;
244  }
245  if(writefd != CURL_SOCKET_BAD) {
246    if(pfd[num].revents & (POLLWRNORM|POLLOUT))
247      ret |= CURL_CSELECT_OUT;
248    if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
249      ret |= CURL_CSELECT_ERR;
250  }
251
252  return ret;
253
254#else  /* HAVE_POLL_FINE */
255
256  FD_ZERO(&fds_err);
257  maxfd = (curl_socket_t)-1;
258
259  FD_ZERO(&fds_read);
260  if(readfd != CURL_SOCKET_BAD) {
261    VERIFY_SOCK(readfd);
262    FD_SET(readfd, &fds_read);
263    FD_SET(readfd, &fds_err);
264    maxfd = readfd;
265  }
266
267  FD_ZERO(&fds_write);
268  if(writefd != CURL_SOCKET_BAD) {
269    VERIFY_SOCK(writefd);
270    FD_SET(writefd, &fds_write);
271    FD_SET(writefd, &fds_err);
272    if(writefd > maxfd)
273      maxfd = writefd;
274  }
275
276  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
277
278  do {
279    if(timeout_ms > 0) {
280      pending_tv.tv_sec = pending_ms / 1000;
281      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
282    }
283    else if(!timeout_ms) {
284      pending_tv.tv_sec = 0;
285      pending_tv.tv_usec = 0;
286    }
287    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
288    if(r != -1)
289      break;
290    error = SOCKERRNO;
291    if(error && error_not_EINTR)
292      break;
293    if(timeout_ms > 0) {
294      pending_ms = timeout_ms - elapsed_ms;
295      if(pending_ms <= 0)
296        break;
297    }
298  } while(r == -1);
299
300  if(r < 0)
301    return -1;
302  if(r == 0)
303    return 0;
304
305  ret = 0;
306  if(readfd != CURL_SOCKET_BAD) {
307    if(FD_ISSET(readfd, &fds_read))
308      ret |= CURL_CSELECT_IN;
309    if(FD_ISSET(readfd, &fds_err))
310      ret |= CURL_CSELECT_ERR;
311  }
312  if(writefd != CURL_SOCKET_BAD) {
313    if(FD_ISSET(writefd, &fds_write))
314      ret |= CURL_CSELECT_OUT;
315    if(FD_ISSET(writefd, &fds_err))
316      ret |= CURL_CSELECT_ERR;
317  }
318
319  return ret;
320
321#endif  /* HAVE_POLL_FINE */
322
323}
324
325/*
326 * This is a wrapper around poll().  If poll() does not exist, then
327 * select() is used instead.  An error is returned if select() is
328 * being used and a file descriptor is too large for FD_SETSIZE.
329 * A negative timeout value makes this function wait indefinitely,
330 * unles no valid file descriptor is given, when this happens the
331 * negative timeout is ignored and the function times out immediately.
332 * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
333 * is honored and function might exit early without awaiting timeout,
334 * otherwise EINTR will be ignored.
335 *
336 * Return values:
337 *   -1 = system call error or fd >= FD_SETSIZE
338 *    0 = timeout
339 *    N = number of structures with non zero revent fields
340 */
341int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
342{
343#ifndef HAVE_POLL_FINE
344  struct timeval pending_tv;
345  struct timeval *ptimeout;
346  fd_set fds_read;
347  fd_set fds_write;
348  fd_set fds_err;
349  curl_socket_t maxfd;
350#endif
351  struct timeval initial_tv = {0,0};
352  bool fds_none = TRUE;
353  unsigned int i;
354  int pending_ms = 0;
355  int error;
356  int r;
357
358  if(ufds) {
359    for(i = 0; i < nfds; i++) {
360      if(ufds[i].fd != CURL_SOCKET_BAD) {
361        fds_none = FALSE;
362        break;
363      }
364    }
365  }
366  if(fds_none) {
367    r = wait_ms((int)timeout_ms);
368    return r;
369  }
370
371  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
372     time in this function does not need to be measured. This happens
373     when function is called with a zero timeout or a negative timeout
374     value indicating a blocking call should be performed. */
375
376  if(timeout_ms > 0) {
377    pending_ms = timeout_ms;
378    initial_tv = curlx_tvnow();
379  }
380
381#ifdef HAVE_POLL_FINE
382
383  do {
384    if(timeout_ms < 0)
385      pending_ms = -1;
386    else if(!timeout_ms)
387      pending_ms = 0;
388    r = poll(ufds, nfds, pending_ms);
389    if(r != -1)
390      break;
391    error = SOCKERRNO;
392    if(error && error_not_EINTR)
393      break;
394    if(timeout_ms > 0) {
395      pending_ms = timeout_ms - elapsed_ms;
396      if(pending_ms <= 0)
397        break;
398    }
399  } while(r == -1);
400
401  if(r < 0)
402    return -1;
403  if(r == 0)
404    return 0;
405
406  for(i = 0; i < nfds; i++) {
407    if(ufds[i].fd == CURL_SOCKET_BAD)
408      continue;
409    if(ufds[i].revents & POLLHUP)
410      ufds[i].revents |= POLLIN;
411    if(ufds[i].revents & POLLERR)
412      ufds[i].revents |= (POLLIN|POLLOUT);
413  }
414
415#else  /* HAVE_POLL_FINE */
416
417  FD_ZERO(&fds_read);
418  FD_ZERO(&fds_write);
419  FD_ZERO(&fds_err);
420  maxfd = (curl_socket_t)-1;
421
422  for(i = 0; i < nfds; i++) {
423    ufds[i].revents = 0;
424    if(ufds[i].fd == CURL_SOCKET_BAD)
425      continue;
426    VERIFY_SOCK(ufds[i].fd);
427    if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
428                          POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
429      if(ufds[i].fd > maxfd)
430        maxfd = ufds[i].fd;
431      if(ufds[i].events & (POLLRDNORM|POLLIN))
432        FD_SET(ufds[i].fd, &fds_read);
433      if(ufds[i].events & (POLLWRNORM|POLLOUT))
434        FD_SET(ufds[i].fd, &fds_write);
435      if(ufds[i].events & (POLLRDBAND|POLLPRI))
436        FD_SET(ufds[i].fd, &fds_err);
437    }
438  }
439
440  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
441
442  do {
443    if(timeout_ms > 0) {
444      pending_tv.tv_sec = pending_ms / 1000;
445      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
446    }
447    else if(!timeout_ms) {
448      pending_tv.tv_sec = 0;
449      pending_tv.tv_usec = 0;
450    }
451    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
452    if(r != -1)
453      break;
454    error = SOCKERRNO;
455    if(error && error_not_EINTR)
456      break;
457    if(timeout_ms > 0) {
458      pending_ms = timeout_ms - elapsed_ms;
459      if(pending_ms <= 0)
460        break;
461    }
462  } while(r == -1);
463
464  if(r < 0)
465    return -1;
466  if(r == 0)
467    return 0;
468
469  r = 0;
470  for(i = 0; i < nfds; i++) {
471    ufds[i].revents = 0;
472    if(ufds[i].fd == CURL_SOCKET_BAD)
473      continue;
474    if(FD_ISSET(ufds[i].fd, &fds_read))
475      ufds[i].revents |= POLLIN;
476    if(FD_ISSET(ufds[i].fd, &fds_write))
477      ufds[i].revents |= POLLOUT;
478    if(FD_ISSET(ufds[i].fd, &fds_err))
479      ufds[i].revents |= POLLPRI;
480    if(ufds[i].revents != 0)
481      r++;
482  }
483
484#endif  /* HAVE_POLL_FINE */
485
486  return r;
487}
488
489#ifdef TPF
490/*
491 * This is a replacement for select() on the TPF platform.
492 * It is used whenever libcurl calls select().
493 * The call below to tpf_process_signals() is required because
494 * TPF's select calls are not signal interruptible.
495 *
496 * Return values are the same as select's.
497 */
498int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
499                       fd_set* excepts, struct timeval* tv)
500{
501   int rc;
502
503   rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
504   tpf_process_signals();
505   return(rc);
506}
507#endif /* TPF */
508