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