LIRC libraries
LinuxInfraredRemoteControl
 All Classes Files Functions Variables Typedefs Enumerations Macros Modules Pages
curl_poll.c
Go to the documentation of this file.
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, 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 https://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 
28 #define _XOPEN_SOURCE 700
29 
30 #include "config.h"
31 
32 #ifdef HAVE_SYS_SELECT_H
33 #include <sys/select.h>
34 #endif
35 
36 #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
37 #error "We can't compile without select() or poll() support."
38 #endif
39 
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 
46 #include "lirc_log.h"
47 #include "curl_poll.h"
48 
49 
50 /* Convenience local macros */
51 
52 #ifndef TRUE
53 #define TRUE 1
54 #define FALSE 0
55 #endif
56 
57 /*
58  * This is a wrapper around poll(). If poll() does not exist, then
59  * select() is used instead. An error is returned if select() is
60  * being used and a file descriptor is too large for FD_SETSIZE.
61  * A negative timeout value makes this function wait indefinitely,
62  * unles no valid file descriptor is given, when this happens the
63  * negative timeout is ignored and the function times out immediately.
64  *
65  * Return values:
66  * -1 = system call error or fd >= FD_SETSIZE
67  * 0 = timeout
68  * N = number of structures with non zero revent fields
69  */
70 
71 #ifdef HAVE_POLL_FINE
72 
73 int curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
74 {
75  return poll(ufds, nfds, timeout_ms);
76 }
77 
78 #else
79 
80 static const logchannel_t logchannel = LOG_LIB;
81 
82 /*
83  * Make sure that the first argument is the more recent time, as otherwise
84  * we'll get a weird negative time-diff back...
85  *
86  * Returns: the time difference in number of milliseconds.
87  */
88 long curlx_tvdiff(struct timeval newer, struct timeval older)
89 {
90  return (newer.tv_sec - older.tv_sec) * 1000 +
91  (long)(newer.tv_usec - older.tv_usec) / 1000;
92 }
93 
94 
95 static int verify_sock(int s)
96 {
97  if (s < 0 || s >= FD_SETSIZE) {
98  errno = EINVAL;
99  log_notice("curl_poll: Invalid socket %d", s);
100  return -1;
101  }
102  return s;
103 }
104 
105 
106 int curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
107 {
108  struct timeval pending_tv;
109  struct timeval* ptimeout;
110  fd_set fds_read;
111  fd_set fds_write;
112  fd_set fds_err;
113  int maxfd;
114 
115  struct timeval initial_tv = { 0, 0 };
116  unsigned int i;
117  int pending_ms = 0;
118  int r;
119 
120  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
121  * time in this function does not need to be measured. This happens
122  * when function is called with a zero timeout or a negative timeout
123  * value indicating a blocking call should be performed. */
124 
125  if (timeout_ms > 0) {
126  pending_ms = timeout_ms;
127  gettimeofday(&initial_tv, NULL);
128  }
129 
130  FD_ZERO(&fds_read);
131  FD_ZERO(&fds_write);
132  FD_ZERO(&fds_err);
133  maxfd = (int)-1;
134 
135  for (i = 0; i < nfds; i++) {
136  ufds[i].revents = 0;
137  if (ufds[i].fd == -1)
138  continue;
139  ufds[i].fd = verify_sock(ufds[i].fd);
140  if (ufds[i].events & (POLLIN | POLLOUT | POLLPRI |
141  POLLRDNORM | POLLWRNORM | POLLRDBAND)) {
142  if (ufds[i].fd > maxfd)
143  maxfd = ufds[i].fd;
144  if (ufds[i].events & (POLLRDNORM | POLLIN))
145  FD_SET(ufds[i].fd, &fds_read);
146  if (ufds[i].events & (POLLWRNORM | POLLOUT))
147  FD_SET(ufds[i].fd, &fds_write);
148  if (ufds[i].events & (POLLRDBAND | POLLPRI))
149  FD_SET(ufds[i].fd, &fds_err);
150  }
151  }
152 
153  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
154 
155  if (timeout_ms > 0) {
156  pending_tv.tv_sec = pending_ms / 1000;
157  pending_tv.tv_usec = (pending_ms % 1000) * 1000;
158  } else if (!timeout_ms) {
159  pending_tv.tv_sec = 0;
160  pending_tv.tv_usec = 0;
161  }
162  r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err,
163  ptimeout);
164  if (r < 0)
165  return -1;
166  if (r == 0)
167  return 0;
168  r = 0;
169  for (i = 0; i < nfds; i++) {
170  ufds[i].revents = 0;
171  if (ufds[i].fd == -1)
172  continue;
173  if (FD_ISSET(ufds[i].fd, &fds_read))
174  ufds[i].revents |= POLLIN;
175  if (FD_ISSET(ufds[i].fd, &fds_write))
176  ufds[i].revents |= POLLOUT;
177  if (FD_ISSET(ufds[i].fd, &fds_err))
178  ufds[i].revents |= POLLPRI;
179  if (ufds[i].revents != 0)
180  r++;
181  }
182  return r;
183 }
184 
185 #endif /* HAVE_POLL_FINE */
Logging functionality.
Wrapper for poll(2) using select(2) when poll() is unavailable.
logchannel_t
Log channels used to filter messages.
Definition: lirc_log.h:53
#define log_notice(fmt,...)
Log a notice message.
Definition: lirc_log.h:119