Coverage Report

Created: 2026-01-09 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/select.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 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.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
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#if !defined(HAVE_SELECT) && !defined(HAVE_POLL)
27
#error "We cannot compile without select() or poll() support."
28
#endif
29
30
#ifdef HAVE_SYS_SELECT_H
31
#include <sys/select.h>
32
#elif defined(HAVE_UNISTD_H)
33
#include <unistd.h>
34
#endif
35
36
#include "urldata.h"
37
#include "connect.h"
38
#include "select.h"
39
#include "curl_trc.h"
40
#include "curlx/timediff.h"
41
#include "curlx/wait.h"
42
43
#ifndef HAVE_POLL
44
/*
45
 * This is a wrapper around select() to aid in Windows compatibility. A
46
 * negative timeout value makes this function wait indefinitely, unless no
47
 * valid file descriptor is given, when this happens the negative timeout is
48
 * ignored and the function times out immediately.
49
 *
50
 * Return values:
51
 *   -1 = system call error or fd >= FD_SETSIZE
52
 *    0 = timeout
53
 *    N = number of signalled file descriptors
54
 */
55
static int our_select(curl_socket_t maxfd,   /* highest socket number */
56
                      fd_set *fds_read,      /* sockets ready for reading */
57
                      fd_set *fds_write,     /* sockets ready for writing */
58
                      fd_set *fds_err,       /* sockets with errors */
59
                      timediff_t timeout_ms) /* milliseconds to wait */
60
{
61
  struct timeval pending_tv;
62
  struct timeval *ptimeout;
63
64
#ifdef USE_WINSOCK
65
  /* Winsock select() cannot handle zero events. See the comment below. */
66
  if((!fds_read || fds_read->fd_count == 0) &&
67
     (!fds_write || fds_write->fd_count == 0) &&
68
     (!fds_err || fds_err->fd_count == 0)) {
69
    /* no sockets, just wait */
70
    return curlx_wait_ms(timeout_ms);
71
  }
72
#endif
73
74
  ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
75
76
#ifdef USE_WINSOCK
77
  /* Winsock select() must not be called with an fd_set that contains zero
78
    fd flags, or it will return WSAEINVAL. But, it also cannot be called
79
    with no fd_sets at all!  From the documentation:
80
81
    Any two of the parameters, readfds, writefds, or exceptfds, can be
82
    given as null. At least one must be non-null, and any non-null
83
    descriptor set must contain at least one handle to a socket.
84
85
    It is unclear why Winsock does not just handle this for us instead of
86
    calling this an error. Luckily, with Winsock, we can _also_ ask how
87
    many bits are set on an fd_set. So, let's just check it beforehand.
88
  */
89
  return select((int)maxfd + 1,
90
                fds_read && fds_read->fd_count ? fds_read : NULL,
91
                fds_write && fds_write->fd_count ? fds_write : NULL,
92
                fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
93
#else
94
  return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
95
#endif
96
}
97
98
#endif
99
100
/*
101
 * Wait for read or write events on a set of file descriptors. It uses poll()
102
 * when poll() is available, in order to avoid limits with FD_SETSIZE,
103
 * otherwise select() is used. An error is returned if select() is being used
104
 * and a file descriptor is too large for FD_SETSIZE.
105
 *
106
 * A negative timeout value makes this function wait indefinitely, unless no
107
 * valid file descriptor is given, when this happens the negative timeout is
108
 * ignored and the function times out immediately.
109
 *
110
 * Return values:
111
 *   -1 = system call error or fd >= FD_SETSIZE
112
 *    0 = timeout
113
 *    [bitmask] = action as described below
114
 *
115
 * CURL_CSELECT_IN - first socket is readable
116
 * CURL_CSELECT_IN2 - second socket is readable
117
 * CURL_CSELECT_OUT - write socket is writable
118
 * CURL_CSELECT_ERR - an error condition occurred
119
 */
120
int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
121
                      curl_socket_t readfd1,
122
                      curl_socket_t writefd, /* socket to write to */
123
                      timediff_t timeout_ms) /* milliseconds to wait */
124
792k
{
125
792k
  struct pollfd pfd[3];
126
792k
  int num;
127
792k
  int r;
128
129
792k
  if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
130
764k
     (writefd == CURL_SOCKET_BAD)) {
131
    /* no sockets, just wait */
132
0
    return curlx_wait_ms(timeout_ms);
133
0
  }
134
135
  /* Avoid initial timestamp, avoid curlx_now() call, when elapsed
136
     time in this function does not need to be measured. This happens
137
     when function is called with a zero timeout or a negative timeout
138
     value indicating a blocking call should be performed. */
139
140
792k
  num = 0;
141
792k
  if(readfd0 != CURL_SOCKET_BAD) {
142
28.6k
    pfd[num].fd = readfd0;
143
28.6k
    pfd[num].events = POLLRDNORM | POLLIN | POLLRDBAND | POLLPRI;
144
28.6k
    pfd[num].revents = 0;
145
28.6k
    num++;
146
28.6k
  }
147
792k
  if(readfd1 != CURL_SOCKET_BAD) {
148
0
    pfd[num].fd = readfd1;
149
0
    pfd[num].events = POLLRDNORM | POLLIN | POLLRDBAND | POLLPRI;
150
0
    pfd[num].revents = 0;
151
0
    num++;
152
0
  }
153
792k
  if(writefd != CURL_SOCKET_BAD) {
154
764k
    pfd[num].fd = writefd;
155
764k
    pfd[num].events = POLLWRNORM | POLLOUT | POLLPRI;
156
764k
    pfd[num].revents = 0;
157
764k
    num++;
158
764k
  }
159
160
792k
  r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
161
792k
  if(r <= 0)
162
765k
    return r;
163
164
27.2k
  r = 0;
165
27.2k
  num = 0;
166
27.2k
  if(readfd0 != CURL_SOCKET_BAD) {
167
26.9k
    if(pfd[num].revents & (POLLRDNORM | POLLIN | POLLERR | POLLHUP))
168
26.9k
      r |= CURL_CSELECT_IN;
169
26.9k
    if(pfd[num].revents & (POLLPRI | POLLNVAL))
170
0
      r |= CURL_CSELECT_ERR;
171
26.9k
    num++;
172
26.9k
  }
173
27.2k
  if(readfd1 != CURL_SOCKET_BAD) {
174
0
    if(pfd[num].revents & (POLLRDNORM | POLLIN | POLLERR | POLLHUP))
175
0
      r |= CURL_CSELECT_IN2;
176
0
    if(pfd[num].revents & (POLLPRI | POLLNVAL))
177
0
      r |= CURL_CSELECT_ERR;
178
0
    num++;
179
0
  }
180
27.2k
  if(writefd != CURL_SOCKET_BAD) {
181
315
    if(pfd[num].revents & (POLLWRNORM | POLLOUT))
182
315
      r |= CURL_CSELECT_OUT;
183
315
    if(pfd[num].revents & (POLLERR | POLLHUP | POLLPRI | POLLNVAL))
184
299
      r |= CURL_CSELECT_ERR;
185
315
  }
186
187
27.2k
  return r;
188
792k
}
189
190
/*
191
 * This is a wrapper around poll(). If poll() does not exist, then
192
 * select() is used instead. An error is returned if select() is
193
 * being used and a file descriptor is too large for FD_SETSIZE.
194
 * A negative timeout value makes this function wait indefinitely,
195
 * unless no valid file descriptor is given, when this happens the
196
 * negative timeout is ignored and the function times out immediately.
197
 *
198
 * Return values:
199
 *   -1 = system call error or fd >= FD_SETSIZE
200
 *    0 = timeout
201
 *    N = number of structures with non zero revent fields
202
 */
203
int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
204
804k
{
205
804k
#ifdef HAVE_POLL
206
804k
  int pending_ms;
207
#else
208
  fd_set fds_read;
209
  fd_set fds_write;
210
  fd_set fds_err;
211
  curl_socket_t maxfd;
212
#endif
213
804k
  bool fds_none = TRUE;
214
804k
  unsigned int i;
215
804k
  int r;
216
217
804k
  if(ufds) {
218
804k
    for(i = 0; i < nfds; i++) {
219
804k
      if(ufds[i].fd != CURL_SOCKET_BAD) {
220
804k
        fds_none = FALSE;
221
804k
        break;
222
804k
      }
223
804k
    }
224
804k
  }
225
804k
  if(fds_none) {
226
    /* no sockets, just wait */
227
0
    return curlx_wait_ms(timeout_ms);
228
0
  }
229
230
  /* Avoid initial timestamp, avoid curlx_now() call, when elapsed
231
     time in this function does not need to be measured. This happens
232
     when function is called with a zero timeout or a negative timeout
233
     value indicating a blocking call should be performed. */
234
235
804k
#ifdef HAVE_POLL
236
237
  /* prevent overflow, timeout_ms is typecast to int. */
238
804k
#if TIMEDIFF_T_MAX > INT_MAX
239
804k
  if(timeout_ms > INT_MAX)
240
0
    timeout_ms = INT_MAX;
241
804k
#endif
242
804k
  if(timeout_ms > 0)
243
6.95k
    pending_ms = (int)timeout_ms;
244
797k
  else if(timeout_ms < 0)
245
0
    pending_ms = -1;
246
797k
  else
247
797k
    pending_ms = 0;
248
804k
  r = poll(ufds, nfds, pending_ms);
249
804k
  if(r <= 0) {
250
765k
    if((r == -1) && (SOCKERRNO == SOCKEINTR))
251
      /* make EINTR from select or poll not a "lethal" error */
252
4
      r = 0;
253
765k
    return r;
254
765k
  }
255
256
78.3k
  for(i = 0; i < nfds; i++) {
257
39.1k
    if(ufds[i].fd == CURL_SOCKET_BAD)
258
0
      continue;
259
39.1k
    if(ufds[i].revents & POLLHUP)
260
299
      ufds[i].revents |= POLLIN;
261
39.1k
    if(ufds[i].revents & POLLERR)
262
299
      ufds[i].revents |= POLLIN | POLLOUT;
263
39.1k
  }
264
265
#else /* !HAVE_POLL */
266
267
  FD_ZERO(&fds_read);
268
  FD_ZERO(&fds_write);
269
  FD_ZERO(&fds_err);
270
  maxfd = (curl_socket_t)-1;
271
272
  for(i = 0; i < nfds; i++) {
273
    ufds[i].revents = 0;
274
    if(ufds[i].fd == CURL_SOCKET_BAD)
275
      continue;
276
    VERIFY_SOCK(ufds[i].fd);
277
    if(ufds[i].events & (POLLIN |POLLOUT |POLLPRI |
278
                         POLLRDNORM | POLLWRNORM | POLLRDBAND)) {
279
      if(ufds[i].fd > maxfd)
280
        maxfd = ufds[i].fd;
281
      if(ufds[i].events & (POLLRDNORM | POLLIN))
282
        FD_SET(ufds[i].fd, &fds_read);
283
      if(ufds[i].events & (POLLWRNORM | POLLOUT))
284
        FD_SET(ufds[i].fd, &fds_write);
285
      if(ufds[i].events & (POLLRDBAND | POLLPRI))
286
        FD_SET(ufds[i].fd, &fds_err);
287
    }
288
  }
289
290
  /*
291
     Note also that Winsock ignores the first argument, so we do not worry
292
     about the fact that maxfd is computed incorrectly with Winsock (since
293
     curl_socket_t is unsigned in such cases and thus -1 is the largest
294
     value).
295
  */
296
  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
297
  if(r <= 0) {
298
    if((r == -1) && (SOCKERRNO == SOCKEINTR))
299
      /* make EINTR from select or poll not a "lethal" error */
300
      r = 0;
301
    return r;
302
  }
303
304
  r = 0;
305
  for(i = 0; i < nfds; i++) {
306
    ufds[i].revents = 0;
307
    if(ufds[i].fd == CURL_SOCKET_BAD)
308
      continue;
309
    if(FD_ISSET(ufds[i].fd, &fds_read)) {
310
      if(ufds[i].events & POLLRDNORM)
311
        ufds[i].revents |= POLLRDNORM;
312
      if(ufds[i].events & POLLIN)
313
        ufds[i].revents |= POLLIN;
314
    }
315
    if(FD_ISSET(ufds[i].fd, &fds_write)) {
316
      if(ufds[i].events & POLLWRNORM)
317
        ufds[i].revents |= POLLWRNORM;
318
      if(ufds[i].events & POLLOUT)
319
        ufds[i].revents |= POLLOUT;
320
    }
321
    if(FD_ISSET(ufds[i].fd, &fds_err)) {
322
      if(ufds[i].events & POLLRDBAND)
323
        ufds[i].revents |= POLLRDBAND;
324
      if(ufds[i].events & POLLPRI)
325
        ufds[i].revents |= POLLPRI;
326
    }
327
    if(ufds[i].revents)
328
      r++;
329
  }
330
331
#endif /* HAVE_POLL */
332
333
39.1k
  return r;
334
804k
}
335
336
void Curl_pollfds_init(struct curl_pollfds *cpfds,
337
                       struct pollfd *static_pfds,
338
                       unsigned int static_count)
339
2.04M
{
340
2.04M
  DEBUGASSERT(cpfds);
341
2.04M
  memset(cpfds, 0, sizeof(*cpfds));
342
2.04M
  if(static_pfds && static_count) {
343
2.04M
    cpfds->pfds = static_pfds;
344
2.04M
    cpfds->count = static_count;
345
2.04M
  }
346
2.04M
}
347
348
void Curl_pollfds_reset(struct curl_pollfds *cpfds)
349
0
{
350
0
  cpfds->n = 0;
351
0
}
352
353
void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
354
2.04M
{
355
2.04M
  DEBUGASSERT(cpfds);
356
2.04M
  if(cpfds->allocated_pfds) {
357
0
    curlx_free(cpfds->pfds);
358
0
  }
359
2.04M
  memset(cpfds, 0, sizeof(*cpfds));
360
2.04M
}
361
362
static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
363
0
{
364
0
  struct pollfd *new_fds;
365
0
  unsigned int new_count = cpfds->count + inc;
366
367
0
  new_fds = curlx_calloc(new_count, sizeof(struct pollfd));
368
0
  if(!new_fds)
369
0
    return CURLE_OUT_OF_MEMORY;
370
371
0
  memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
372
0
  if(cpfds->allocated_pfds)
373
0
    curlx_free(cpfds->pfds);
374
0
  cpfds->pfds = new_fds;
375
0
  cpfds->count = new_count;
376
0
  cpfds->allocated_pfds = TRUE;
377
0
  return CURLE_OK;
378
0
}
379
380
static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
381
                               curl_socket_t sock, short events, bool fold)
382
0
{
383
0
  int i;
384
385
0
  if(fold && cpfds->n <= INT_MAX) {
386
0
    for(i = (int)cpfds->n - 1; i >= 0; --i) {
387
0
      if(sock == cpfds->pfds[i].fd) {
388
0
        cpfds->pfds[i].events |= events;
389
0
        return CURLE_OK;
390
0
      }
391
0
    }
392
0
  }
393
  /* not folded, add new entry */
394
0
  if(cpfds->n >= cpfds->count) {
395
0
    if(cpfds_increase(cpfds, 100))
396
0
      return CURLE_OUT_OF_MEMORY;
397
0
  }
398
0
  cpfds->pfds[cpfds->n].fd = sock;
399
0
  cpfds->pfds[cpfds->n].events = events;
400
0
  ++cpfds->n;
401
0
  return CURLE_OK;
402
0
}
403
404
CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
405
                               curl_socket_t sock, short events)
406
0
{
407
0
  return cpfds_add_sock(cpfds, sock, events, FALSE);
408
0
}
409
410
CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
411
                             struct easy_pollset *ps)
412
0
{
413
0
  size_t i;
414
415
0
  DEBUGASSERT(cpfds);
416
0
  DEBUGASSERT(ps);
417
0
  for(i = 0; i < ps->n; i++) {
418
0
    short events = 0;
419
0
    if(ps->actions[i] & CURL_POLL_IN)
420
0
      events |= POLLIN;
421
0
    if(ps->actions[i] & CURL_POLL_OUT)
422
0
      events |= POLLOUT;
423
0
    if(events) {
424
0
      if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
425
0
        return CURLE_OUT_OF_MEMORY;
426
0
    }
427
0
  }
428
0
  return CURLE_OK;
429
0
}
430
431
void Curl_waitfds_init(struct Curl_waitfds *cwfds,
432
                       struct curl_waitfd *static_wfds,
433
                       unsigned int static_count)
434
0
{
435
0
  DEBUGASSERT(cwfds);
436
0
  DEBUGASSERT(static_wfds || !static_count);
437
0
  memset(cwfds, 0, sizeof(*cwfds));
438
0
  cwfds->wfds = static_wfds;
439
0
  cwfds->count = static_count;
440
0
}
441
442
static unsigned int cwfds_add_sock(struct Curl_waitfds *cwfds,
443
                                   curl_socket_t sock, short events)
444
0
{
445
0
  int i;
446
0
  if(!cwfds->wfds) {
447
0
    DEBUGASSERT(!cwfds->count && !cwfds->n);
448
0
    return 1;
449
0
  }
450
0
  if(cwfds->n <= INT_MAX) {
451
0
    for(i = (int)cwfds->n - 1; i >= 0; --i) {
452
0
      if(sock == cwfds->wfds[i].fd) {
453
0
        cwfds->wfds[i].events |= events;
454
0
        return 0;
455
0
      }
456
0
    }
457
0
  }
458
  /* not folded, add new entry */
459
0
  if(cwfds->n < cwfds->count) {
460
0
    cwfds->wfds[cwfds->n].fd = sock;
461
0
    cwfds->wfds[cwfds->n].events = events;
462
0
    ++cwfds->n;
463
0
  }
464
0
  return 1;
465
0
}
466
467
unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
468
                                 struct easy_pollset *ps)
469
0
{
470
0
  size_t i;
471
0
  unsigned int need = 0;
472
473
0
  DEBUGASSERT(cwfds);
474
0
  DEBUGASSERT(ps);
475
0
  for(i = 0; i < ps->n; i++) {
476
0
    short events = 0;
477
0
    if(ps->actions[i] & CURL_POLL_IN)
478
0
      events |= CURL_WAIT_POLLIN;
479
0
    if(ps->actions[i] & CURL_POLL_OUT)
480
0
      events |= CURL_WAIT_POLLOUT;
481
0
    if(events)
482
0
      need += cwfds_add_sock(cwfds, ps->sockets[i], events);
483
0
  }
484
0
  return need;
485
0
}
486
487
void Curl_pollset_reset(struct easy_pollset *ps)
488
96.9M
{
489
96.9M
  unsigned int i;
490
96.9M
  ps->n = 0;
491
96.9M
#ifdef DEBUGBUILD
492
96.9M
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
493
96.9M
#endif
494
96.9M
  DEBUGASSERT(ps->count);
495
290M
  for(i = 0; i < ps->count; i++)
496
193M
    ps->sockets[i] = CURL_SOCKET_BAD;
497
96.9M
  memset(ps->actions, 0, ps->count * sizeof(ps->actions[0]));
498
96.9M
}
499
500
void Curl_pollset_init(struct easy_pollset *ps)
501
25.0M
{
502
25.0M
#ifdef DEBUGBUILD
503
25.0M
  ps->init = CURL_EASY_POLLSET_MAGIC;
504
25.0M
#endif
505
25.0M
  ps->sockets = ps->def_sockets;
506
25.0M
  ps->actions = ps->def_actions;
507
25.0M
  ps->count = CURL_ARRAYSIZE(ps->def_sockets);
508
25.0M
  ps->n = 0;
509
25.0M
  Curl_pollset_reset(ps);
510
25.0M
}
511
512
struct easy_pollset *Curl_pollset_create(void)
513
0
{
514
0
  struct easy_pollset *ps = curlx_calloc(1, sizeof(*ps));
515
0
  if(ps)
516
0
    Curl_pollset_init(ps);
517
0
  return ps;
518
0
}
519
520
void Curl_pollset_cleanup(struct easy_pollset *ps)
521
25.0M
{
522
25.0M
#ifdef DEBUGBUILD
523
25.0M
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
524
25.0M
#endif
525
25.0M
  if(ps->sockets != ps->def_sockets) {
526
0
    curlx_free(ps->sockets);
527
0
    ps->sockets = ps->def_sockets;
528
0
  }
529
25.0M
  if(ps->actions != ps->def_actions) {
530
0
    curlx_free(ps->actions);
531
0
    ps->actions = ps->def_actions;
532
0
  }
533
25.0M
  ps->count = CURL_ARRAYSIZE(ps->def_sockets);
534
25.0M
  Curl_pollset_reset(ps);
535
25.0M
}
536
537
void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from)
538
0
{
539
0
  Curl_pollset_cleanup(to); /* deallocate anything in to */
540
0
  if(from->sockets != from->def_sockets) {
541
0
    DEBUGASSERT(from->actions != from->def_actions);
542
0
    to->sockets = from->sockets;
543
0
    to->actions = from->actions;
544
0
    to->count = from->count;
545
0
    to->n = from->n;
546
0
    Curl_pollset_init(from);
547
0
  }
548
0
  else {
549
0
    DEBUGASSERT(to->sockets == to->def_sockets);
550
0
    DEBUGASSERT(to->actions == to->def_actions);
551
0
    memcpy(to->sockets, from->sockets, to->count * sizeof(to->sockets[0]));
552
0
    memcpy(to->actions, from->actions, to->count * sizeof(to->actions[0]));
553
0
    to->n = from->n;
554
0
    Curl_pollset_init(from);
555
0
  }
556
0
}
557
558
/**
559
 *
560
 */
561
CURLcode Curl_pollset_change(struct Curl_easy *data,
562
                             struct easy_pollset *ps, curl_socket_t sock,
563
                             int add_flags, int remove_flags)
564
34.3M
{
565
34.3M
  unsigned int i;
566
567
34.3M
#ifdef DEBUGBUILD
568
34.3M
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
569
34.3M
#endif
570
571
34.3M
  (void)data;
572
34.3M
  DEBUGASSERT(VALID_SOCK(sock));
573
34.3M
  if(!VALID_SOCK(sock))
574
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
575
576
34.3M
  DEBUGASSERT(add_flags <= (CURL_POLL_IN | CURL_POLL_OUT));
577
34.3M
  DEBUGASSERT(remove_flags <= (CURL_POLL_IN | CURL_POLL_OUT));
578
34.3M
  DEBUGASSERT((add_flags & remove_flags) == 0); /* no overlap */
579
34.3M
  for(i = 0; i < ps->n; ++i) {
580
10.3M
    if(ps->sockets[i] == sock) {
581
10.3M
      ps->actions[i] &= (unsigned char)(~remove_flags);
582
10.3M
      ps->actions[i] |= (unsigned char)add_flags;
583
      /* all gone? remove socket */
584
10.3M
      if(!ps->actions[i]) {
585
78
        if((i + 1) < ps->n) {
586
0
          memmove(&ps->sockets[i], &ps->sockets[i + 1],
587
0
                  (ps->n - (i + 1)) * sizeof(ps->sockets[0]));
588
0
          memmove(&ps->actions[i], &ps->actions[i + 1],
589
0
                  (ps->n - (i + 1)) * sizeof(ps->actions[0]));
590
0
        }
591
78
        --ps->n;
592
78
      }
593
10.3M
      return CURLE_OK;
594
10.3M
    }
595
10.3M
  }
596
  /* not present */
597
23.9M
  if(add_flags) {
598
23.9M
    if(i >= ps->count) { /* need to grow */
599
0
      unsigned int new_count = CURLMAX(ps->count * 2, 8);
600
0
      curl_socket_t *nsockets;
601
0
      unsigned char *nactions;
602
603
0
      CURL_TRC_M(data, "growing pollset capacity from %u to %u",
604
0
                 ps->count, new_count);
605
0
      if(new_count <= ps->count)
606
0
        return CURLE_OUT_OF_MEMORY;
607
0
      nsockets = curlx_calloc(new_count, sizeof(nsockets[0]));
608
0
      if(!nsockets)
609
0
        return CURLE_OUT_OF_MEMORY;
610
0
      nactions = curlx_calloc(new_count, sizeof(nactions[0]));
611
0
      if(!nactions) {
612
0
        curlx_free(nsockets);
613
0
        return CURLE_OUT_OF_MEMORY;
614
0
      }
615
0
      memcpy(nsockets, ps->sockets, ps->count * sizeof(ps->sockets[0]));
616
0
      memcpy(nactions, ps->actions, ps->count * sizeof(ps->actions[0]));
617
0
      if(ps->sockets != ps->def_sockets)
618
0
        curlx_free(ps->sockets);
619
0
      ps->sockets = nsockets;
620
0
      if(ps->actions != ps->def_actions)
621
0
        curlx_free(ps->actions);
622
0
      ps->actions = nactions;
623
0
      ps->count = new_count;
624
0
    }
625
23.9M
    DEBUGASSERT(i < ps->count);
626
23.9M
    if(i < ps->count) {
627
23.9M
      ps->sockets[i] = sock;
628
23.9M
      ps->actions[i] = (unsigned char)add_flags;
629
23.9M
      ps->n = i + 1;
630
23.9M
    }
631
23.9M
  }
632
23.9M
  return CURLE_OK;
633
23.9M
}
634
635
CURLcode Curl_pollset_set(struct Curl_easy *data,
636
                          struct easy_pollset *ps, curl_socket_t sock,
637
                          bool do_in, bool do_out)
638
3.97M
{
639
3.97M
  return Curl_pollset_change(data, ps, sock,
640
3.97M
                             (do_in ? CURL_POLL_IN : 0)|
641
3.97M
                             (do_out ? CURL_POLL_OUT : 0),
642
3.97M
                             (!do_in ? CURL_POLL_IN : 0)|
643
3.97M
                             (!do_out ? CURL_POLL_OUT : 0));
644
3.97M
}
645
646
int Curl_pollset_poll(struct Curl_easy *data,
647
                      struct easy_pollset *ps,
648
                      timediff_t timeout_ms)
649
0
{
650
0
  struct pollfd *pfds;
651
0
  unsigned int i, npfds;
652
0
  int result;
653
654
0
  (void)data;
655
0
  DEBUGASSERT(data);
656
0
  DEBUGASSERT(data->conn);
657
658
0
  if(!ps->n)
659
0
    return curlx_wait_ms(timeout_ms);
660
661
0
  pfds = curlx_calloc(ps->n, sizeof(*pfds));
662
0
  if(!pfds)
663
0
    return -1;
664
665
0
  npfds = 0;
666
0
  for(i = 0; i < ps->n; ++i) {
667
0
    short events = 0;
668
0
    if(ps->actions[i] & CURL_POLL_IN) {
669
0
      events |= POLLIN;
670
0
    }
671
0
    if(ps->actions[i] & CURL_POLL_OUT) {
672
0
      events |= POLLOUT;
673
0
    }
674
0
    if(events) {
675
0
      pfds[npfds].fd = ps->sockets[i];
676
0
      pfds[npfds].events = events;
677
0
      ++npfds;
678
0
    }
679
0
  }
680
681
0
  result = Curl_poll(pfds, npfds, timeout_ms);
682
0
  curlx_free(pfds);
683
0
  return result;
684
0
}
685
686
void Curl_pollset_check(struct Curl_easy *data,
687
                        struct easy_pollset *ps, curl_socket_t sock,
688
                        bool *pwant_read, bool *pwant_write)
689
3.97M
{
690
3.97M
  unsigned int i;
691
692
3.97M
  (void)data;
693
3.97M
  DEBUGASSERT(VALID_SOCK(sock));
694
3.97M
  for(i = 0; i < ps->n; ++i) {
695
3.97M
    if(ps->sockets[i] == sock) {
696
3.97M
      *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
697
3.97M
      *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
698
3.97M
      return;
699
3.97M
    }
700
3.97M
  }
701
0
  *pwant_read = *pwant_write = FALSE;
702
0
}
703
704
bool Curl_pollset_want_recv(struct Curl_easy *data,
705
                            struct easy_pollset *ps,
706
                            curl_socket_t sock)
707
44.8M
{
708
44.8M
  unsigned int i;
709
44.8M
  (void)data;
710
67.9M
  for(i = 0; i < ps->n; ++i) {
711
44.8M
    if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
712
21.7M
      return TRUE;
713
44.8M
  }
714
23.0M
  return FALSE;
715
44.8M
}
716
717
bool Curl_pollset_want_send(struct Curl_easy *data,
718
                            struct easy_pollset *ps,
719
                            curl_socket_t sock)
720
596k
{
721
596k
  unsigned int i;
722
596k
  (void)data;
723
596k
  for(i = 0; i < ps->n; ++i) {
724
596k
    if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_OUT))
725
596k
      return TRUE;
726
596k
  }
727
0
  return FALSE;
728
596k
}