LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
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
73int curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
74{
75 return poll(ufds, nfds, timeout_ms);
76}
77
78#else
79
80static 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 */
88long 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
95static 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
106int 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 */
Wrapper for poll(2) using select(2) when poll() is unavailable.
Logging functionality.
#define log_notice(fmt,...)
Log a notice message.
Definition lirc_log.h:119
logchannel_t
Log channels used to filter messages.
Definition lirc_log.h:53