| 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 */
lirc_log.h
Logging functionality.
logchannel_t
logchannel_t
Definition: lirc_log.h:53
log_notice
#define log_notice(fmt,...)
Definition: lirc_log.h:119