1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr.h"
18#include "apr_poll.h"
19#include "apr_arch_networkio.h"
20
21
22
23struct apr_pollset_t {
24    apr_pool_t *pool;
25    apr_uint32_t nelts;
26    apr_uint32_t nalloc;
27    int *pollset;
28    int num_read;
29    int num_write;
30    int num_except;
31    int num_total;
32    apr_pollfd_t *query_set;
33    apr_pollfd_t *result_set;
34};
35
36
37
38APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
39                                             apr_uint32_t size,
40                                             apr_pool_t *p,
41                                             apr_uint32_t flags)
42{
43    *pollset = apr_palloc(p, sizeof(**pollset));
44    (*pollset)->pool = p;
45    (*pollset)->nelts = 0;
46    (*pollset)->nalloc = size;
47    (*pollset)->pollset = apr_palloc(p, size * sizeof(int) * 3);
48    (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
49    (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
50    (*pollset)->num_read = -1;
51    return APR_SUCCESS;
52}
53
54APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **pollset,
55                                                apr_uint32_t size,
56                                                apr_pool_t *p,
57                                                apr_uint32_t flags,
58                                                apr_pollset_method_e method)
59{
60    return apr_pollset_create(pollset, size, p, flags);
61}
62
63APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
64{
65    /* A no-op function for now.  If we later implement /dev/poll
66     * support, we'll need to close the /dev/poll fd here
67     */
68    return APR_SUCCESS;
69}
70
71
72
73APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
74                                          const apr_pollfd_t *descriptor)
75{
76    if (pollset->nelts == pollset->nalloc) {
77        return APR_ENOMEM;
78    }
79
80    pollset->query_set[pollset->nelts] = *descriptor;
81
82    if (descriptor->desc_type != APR_POLL_SOCKET) {
83        return APR_EBADF;
84    }
85
86    pollset->nelts++;
87    pollset->num_read = -1;
88    return APR_SUCCESS;
89}
90
91
92
93APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
94                                             const apr_pollfd_t *descriptor)
95{
96    apr_uint32_t i;
97
98    for (i = 0; i < pollset->nelts; i++) {
99        if (descriptor->desc.s == pollset->query_set[i].desc.s) {
100            /* Found an instance of the fd: remove this and any other copies */
101            apr_uint32_t dst = i;
102            apr_uint32_t old_nelts = pollset->nelts;
103            pollset->nelts--;
104
105            for (i++; i < old_nelts; i++) {
106                if (descriptor->desc.s == pollset->query_set[i].desc.s) {
107                    pollset->nelts--;
108                }
109                else {
110                    pollset->pollset[dst] = pollset->pollset[i];
111                    pollset->query_set[dst] = pollset->query_set[i];
112                    dst++;
113                }
114            }
115
116            pollset->num_read = -1;
117            return APR_SUCCESS;
118        }
119    }
120
121    return APR_NOTFOUND;
122}
123
124
125
126static void make_pollset(apr_pollset_t *pollset)
127{
128    int i;
129    int pos = 0;
130
131    pollset->num_read = 0;
132    pollset->num_write = 0;
133    pollset->num_except = 0;
134
135    for (i = 0; i < pollset->nelts; i++) {
136        if (pollset->query_set[i].reqevents & APR_POLLIN) {
137            pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes;
138            pollset->num_read++;
139        }
140    }
141
142    for (i = 0; i < pollset->nelts; i++) {
143        if (pollset->query_set[i].reqevents & APR_POLLOUT) {
144            pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes;
145            pollset->num_write++;
146        }
147    }
148
149    for (i = 0; i < pollset->nelts; i++) {
150        if (pollset->query_set[i].reqevents & APR_POLLPRI) {
151            pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes;
152            pollset->num_except++;
153        }
154    }
155
156    pollset->num_total = pollset->num_read + pollset->num_write + pollset->num_except;
157}
158
159
160
161APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
162                                           apr_interval_time_t timeout,
163                                           apr_int32_t *num,
164                                           const apr_pollfd_t **descriptors)
165{
166    int rv;
167    apr_uint32_t i;
168    int *pollresult;
169    int read_pos, write_pos, except_pos;
170
171    if (pollset->num_read < 0) {
172        make_pollset(pollset);
173    }
174
175    pollresult = alloca(sizeof(int) * pollset->num_total);
176    memcpy(pollresult, pollset->pollset, sizeof(int) * pollset->num_total);
177    (*num) = 0;
178
179    if (timeout > 0) {
180        timeout /= 1000;
181    }
182
183    rv = select(pollresult, pollset->num_read, pollset->num_write, pollset->num_except, timeout);
184
185    if (rv < 0) {
186        return APR_FROM_OS_ERROR(sock_errno());
187    }
188
189    if (rv == 0) {
190        return APR_TIMEUP;
191    }
192
193    read_pos = 0;
194    write_pos = pollset->num_read;
195    except_pos = pollset->num_read + pollset->num_write;
196
197    for (i = 0; i < pollset->nelts; i++) {
198        int rtnevents = 0;
199
200        if (pollset->query_set[i].reqevents & APR_POLLIN) {
201            if (pollresult[read_pos++] != -1) {
202                rtnevents |= APR_POLLIN;
203            }
204        }
205
206        if (pollset->query_set[i].reqevents & APR_POLLOUT) {
207            if (pollresult[write_pos++] != -1) {
208                rtnevents |= APR_POLLOUT;
209            }
210        }
211
212        if (pollset->query_set[i].reqevents & APR_POLLPRI) {
213            if (pollresult[except_pos++] != -1) {
214                rtnevents |= APR_POLLPRI;
215            }
216        }
217
218        if (rtnevents) {
219            pollset->result_set[*num] = pollset->query_set[i];
220            pollset->result_set[*num].rtnevents = rtnevents;
221            (*num)++;
222        }
223    }
224
225    if (descriptors) {
226        *descriptors = pollset->result_set;
227    }
228
229    return APR_SUCCESS;
230}
231