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