Coverage Report

Created: 2026-10-15 06:19

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