Coverage Report

Created: 2026-08-31 06:47

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
0
{
121
0
  struct pollfd pfd[3];
122
0
  int num;
123
0
  int r;
124
125
0
  if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
126
0
     (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
0
  num = 0;
137
0
  if(readfd0 != CURL_SOCKET_BAD) {
138
0
    pfd[num].fd = readfd0;
139
0
    pfd[num].events = POLLRDNORM | POLLIN | POLLRDBAND | POLLPRI;
140
0
    pfd[num].revents = 0;
141
0
    num++;
142
0
  }
143
0
  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
0
  if(writefd != CURL_SOCKET_BAD) {
150
0
    pfd[num].fd = writefd;
151
0
    pfd[num].events = POLLWRNORM | POLLOUT | POLLPRI;
152
0
    pfd[num].revents = 0;
153
0
    num++;
154
0
  }
155
156
0
  r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
157
0
  if(r <= 0)
158
0
    return r;
159
160
0
  r = 0;
161
0
  num = 0;
162
0
  if(readfd0 != CURL_SOCKET_BAD) {
163
0
    if(pfd[num].revents & (POLLRDNORM | POLLIN | POLLERR | POLLHUP))
164
0
      r |= CURL_CSELECT_IN;
165
0
    if(pfd[num].revents & (POLLPRI | POLLNVAL))
166
0
      r |= CURL_CSELECT_ERR;
167
0
    num++;
168
0
  }
169
0
  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
0
  if(writefd != CURL_SOCKET_BAD) {
177
0
    if(pfd[num].revents & (POLLWRNORM | POLLOUT))
178
0
      r |= CURL_CSELECT_OUT;
179
0
    if(pfd[num].revents & (POLLERR | POLLHUP | POLLPRI | POLLNVAL))
180
0
      r |= CURL_CSELECT_ERR;
181
0
  }
182
183
0
  return r;
184
0
}
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
0
{
201
0
#ifdef HAVE_POLL
202
0
  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
0
  bool fds_none = TRUE;
210
0
  unsigned int i;
211
0
  int r;
212
213
0
  if(ufds) {
214
0
    for(i = 0; i < nfds; i++) {
215
0
      if(ufds[i].fd != CURL_SOCKET_BAD) {
216
0
        fds_none = FALSE;
217
0
        break;
218
0
      }
219
0
    }
220
0
  }
221
0
  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
0
#ifdef HAVE_POLL
232
233
  /* prevent overflow, timeout_ms is typecast to int. */
234
0
#if TIMEDIFF_T_MAX > INT_MAX
235
0
  if(timeout_ms > INT_MAX)
236
0
    timeout_ms = INT_MAX;
237
0
#endif
238
0
  if(timeout_ms > 0)
239
0
    pending_ms = (int)timeout_ms;
240
0
  else if(timeout_ms < 0)
241
0
    pending_ms = -1;
242
0
  else
243
0
    pending_ms = 0;
244
0
  r = poll(ufds, nfds, pending_ms);
245
0
  if(r <= 0) {
246
0
    if((r == -1) && (SOCKERRNO == SOCKEINTR))
247
      /* make EINTR from select or poll not a "lethal" error */
248
0
      r = 0;
249
0
    return r;
250
0
  }
251
252
0
  for(i = 0; i < nfds; i++) {
253
0
    if(ufds[i].fd == CURL_SOCKET_BAD)
254
0
      continue;
255
0
    if(ufds[i].revents & POLLHUP)
256
0
      ufds[i].revents |= POLLIN;
257
0
    if(ufds[i].revents & POLLERR)
258
0
      ufds[i].revents |= POLLIN | POLLOUT;
259
0
  }
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
0
  return r;
328
0
}
329
330
void Curl_pollfds_init(struct curl_pollfds *cpfds,
331
                       struct pollfd *static_pfds,
332
                       unsigned int static_count)
333
0
{
334
0
  DEBUGASSERT(cpfds);
335
0
  memset(cpfds, 0, sizeof(*cpfds));
336
0
  if(static_pfds && static_count) {
337
0
    cpfds->pfds = static_pfds;
338
0
    cpfds->count = static_count;
339
0
  }
340
0
}
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
0
{
349
0
  DEBUGASSERT(cpfds);
350
0
  if(cpfds->allocated_pfds) {
351
0
    curlx_free(cpfds->pfds);
352
0
  }
353
0
  memset(cpfds, 0, sizeof(*cpfds));
354
0
}
355
356
static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
357
0
{
358
0
  struct pollfd *new_fds;
359
0
  unsigned int new_count = cpfds->count + inc;
360
361
0
  new_fds = curlx_calloc(new_count, sizeof(struct pollfd));
362
0
  if(!new_fds)
363
0
    return CURLE_OUT_OF_MEMORY;
364
365
0
  memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
366
0
  if(cpfds->allocated_pfds)
367
0
    curlx_free(cpfds->pfds);
368
0
  cpfds->pfds = new_fds;
369
0
  cpfds->count = new_count;
370
0
  cpfds->allocated_pfds = TRUE;
371
0
  return CURLE_OK;
372
0
}
373
374
static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
375
                               curl_socket_t sock, short events, bool fold)
376
0
{
377
0
  int i;
378
379
0
  if(fold && cpfds->n <= INT_MAX) {
380
0
    for(i = (int)cpfds->n - 1; i >= 0; --i) {
381
0
      if(sock == cpfds->pfds[i].fd) {
382
0
        cpfds->pfds[i].events |= events;
383
0
        return CURLE_OK;
384
0
      }
385
0
    }
386
0
  }
387
  /* not folded, add new entry */
388
0
  if(cpfds->n >= cpfds->count) {
389
0
    if(cpfds_increase(cpfds, 100))
390
0
      return CURLE_OUT_OF_MEMORY;
391
0
  }
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) {
418
0
      if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
419
0
        return CURLE_OUT_OF_MEMORY;
420
0
    }
421
0
  }
422
0
  return CURLE_OK;
423
0
}
424
425
void Curl_waitfds_init(struct Curl_waitfds *cwfds,
426
                       struct curl_waitfd *static_wfds,
427
                       unsigned int static_count)
428
0
{
429
0
  DEBUGASSERT(cwfds);
430
0
  DEBUGASSERT(static_wfds || !static_count);
431
0
  memset(cwfds, 0, sizeof(*cwfds));
432
0
  cwfds->wfds = static_wfds;
433
0
  cwfds->count = static_count;
434
0
}
435
436
static unsigned int cwfds_add_sock(struct Curl_waitfds *cwfds,
437
                                   curl_socket_t sock, short events)
438
0
{
439
0
  int i;
440
0
  if(!cwfds->wfds) {
441
0
    DEBUGASSERT(!cwfds->count && !cwfds->n);
442
0
    return 1;
443
0
  }
444
0
  if(cwfds->n <= INT_MAX) {
445
0
    for(i = (int)cwfds->n - 1; i >= 0; --i) {
446
0
      if(sock == cwfds->wfds[i].fd) {
447
0
        cwfds->wfds[i].events |= events;
448
0
        return 0;
449
0
      }
450
0
    }
451
0
  }
452
  /* not folded, add new entry */
453
0
  if(cwfds->n < cwfds->count) {
454
0
    cwfds->wfds[cwfds->n].fd = sock;
455
0
    cwfds->wfds[cwfds->n].events = events;
456
0
    ++cwfds->n;
457
0
  }
458
0
  return 1;
459
0
}
460
461
unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
462
                                 struct easy_pollset *ps)
463
0
{
464
0
  size_t i;
465
0
  unsigned int need = 0;
466
467
0
  DEBUGASSERT(cwfds);
468
0
  DEBUGASSERT(ps);
469
0
  for(i = 0; i < ps->n; i++) {
470
0
    short events = 0;
471
0
    if(ps->actions[i] & CURL_POLL_IN)
472
0
      events |= CURL_WAIT_POLLIN;
473
0
    if(ps->actions[i] & CURL_POLL_OUT)
474
0
      events |= CURL_WAIT_POLLOUT;
475
0
    if(events)
476
0
      need += cwfds_add_sock(cwfds, ps->sockets[i], events);
477
0
  }
478
0
  return need;
479
0
}
480
481
void Curl_pollset_reset(struct easy_pollset *ps)
482
0
{
483
0
  unsigned int i;
484
0
  ps->n = 0;
485
0
#ifdef DEBUGBUILD
486
0
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
487
0
#endif
488
0
  DEBUGASSERT(ps->count);
489
0
  for(i = 0; i < ps->count; i++)
490
0
    ps->sockets[i] = CURL_SOCKET_BAD;
491
0
  memset(ps->actions, 0, ps->count * sizeof(ps->actions[0]));
492
0
}
493
494
void Curl_pollset_init(struct easy_pollset *ps)
495
0
{
496
0
#ifdef DEBUGBUILD
497
0
  ps->init = CURL_EASY_POLLSET_MAGIC;
498
0
#endif
499
0
  ps->sockets = ps->def_sockets;
500
0
  ps->actions = ps->def_actions;
501
0
  ps->count = CURL_ARRAYSIZE(ps->def_sockets);
502
0
  ps->n = 0;
503
0
  Curl_pollset_reset(ps);
504
0
}
505
506
struct easy_pollset *Curl_pollset_create(void)
507
0
{
508
0
  struct easy_pollset *ps = curlx_calloc(1, sizeof(*ps));
509
0
  if(ps)
510
0
    Curl_pollset_init(ps);
511
0
  return ps;
512
0
}
513
514
void Curl_pollset_cleanup(struct easy_pollset *ps)
515
0
{
516
0
#ifdef DEBUGBUILD
517
0
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
518
0
#endif
519
0
  if(ps->sockets != ps->def_sockets) {
520
0
    curlx_free(ps->sockets);
521
0
    ps->sockets = ps->def_sockets;
522
0
  }
523
0
  if(ps->actions != ps->def_actions) {
524
0
    curlx_free(ps->actions);
525
0
    ps->actions = ps->def_actions;
526
0
  }
527
0
  ps->count = CURL_ARRAYSIZE(ps->def_sockets);
528
0
  Curl_pollset_reset(ps);
529
0
}
530
531
void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from)
532
0
{
533
0
  Curl_pollset_cleanup(to); /* deallocate anything in to */
534
0
  if(from->sockets != from->def_sockets) {
535
0
    DEBUGASSERT(from->actions != from->def_actions);
536
0
    to->sockets = from->sockets;
537
0
    to->actions = from->actions;
538
0
    to->count = from->count;
539
0
    to->n = from->n;
540
0
    Curl_pollset_init(from);
541
0
  }
542
0
  else {
543
0
    DEBUGASSERT(to->sockets == to->def_sockets);
544
0
    DEBUGASSERT(to->actions == to->def_actions);
545
0
    memcpy(to->sockets, from->sockets, to->count * sizeof(to->sockets[0]));
546
0
    memcpy(to->actions, from->actions, to->count * sizeof(to->actions[0]));
547
0
    to->n = from->n;
548
0
    Curl_pollset_init(from);
549
0
  }
550
0
}
551
552
/**
553
 *
554
 */
555
CURLcode Curl_pollset_change(struct Curl_easy *data,
556
                             struct easy_pollset *ps, curl_socket_t sock,
557
                             int add_flags, int remove_flags)
558
0
{
559
0
  unsigned int i;
560
561
0
#ifdef DEBUGBUILD
562
0
  DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
563
0
#endif
564
565
0
  DEBUGASSERT(VALID_SOCK(sock));
566
0
  if(!VALID_SOCK(sock))
567
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
568
569
0
  DEBUGASSERT(add_flags <= (CURL_POLL_IN | CURL_POLL_OUT));
570
0
  DEBUGASSERT(remove_flags <= (CURL_POLL_IN | CURL_POLL_OUT));
571
0
  DEBUGASSERT((add_flags & remove_flags) == 0); /* no overlap */
572
0
  for(i = 0; i < ps->n; ++i) {
573
0
    if(ps->sockets[i] == sock) {
574
0
      ps->actions[i] &= (unsigned char)(~remove_flags);
575
0
      ps->actions[i] |= (unsigned char)add_flags;
576
      /* all gone? remove socket */
577
0
      if(!ps->actions[i]) {
578
0
        if((i + 1) < ps->n) {
579
0
          memmove(&ps->sockets[i], &ps->sockets[i + 1],
580
0
                  (ps->n - (i + 1)) * sizeof(ps->sockets[0]));
581
0
          memmove(&ps->actions[i], &ps->actions[i + 1],
582
0
                  (ps->n - (i + 1)) * sizeof(ps->actions[0]));
583
0
        }
584
0
        --ps->n;
585
0
      }
586
0
      return CURLE_OK;
587
0
    }
588
0
  }
589
  /* not present */
590
0
  if(add_flags) {
591
0
    if(i >= ps->count) { /* need to grow */
592
0
      unsigned int new_count = CURLMAX(ps->count * 2, 8);
593
0
      curl_socket_t *nsockets;
594
0
      unsigned char *nactions;
595
596
0
      CURL_TRC_M(data, "growing pollset capacity from %u to %u",
597
0
                 ps->count, new_count);
598
0
      if(new_count <= ps->count)
599
0
        return CURLE_OUT_OF_MEMORY;
600
0
      nsockets = curlx_calloc(new_count, sizeof(nsockets[0]));
601
0
      if(!nsockets)
602
0
        return CURLE_OUT_OF_MEMORY;
603
0
      nactions = curlx_calloc(new_count, sizeof(nactions[0]));
604
0
      if(!nactions) {
605
0
        curlx_free(nsockets);
606
0
        return CURLE_OUT_OF_MEMORY;
607
0
      }
608
0
      memcpy(nsockets, ps->sockets, ps->count * sizeof(ps->sockets[0]));
609
0
      memcpy(nactions, ps->actions, ps->count * sizeof(ps->actions[0]));
610
0
      if(ps->sockets != ps->def_sockets)
611
0
        curlx_free(ps->sockets);
612
0
      ps->sockets = nsockets;
613
0
      if(ps->actions != ps->def_actions)
614
0
        curlx_free(ps->actions);
615
0
      ps->actions = nactions;
616
0
      ps->count = new_count;
617
0
    }
618
0
    DEBUGASSERT(i < ps->count);
619
0
    if(i < ps->count) {
620
0
      ps->sockets[i] = sock;
621
0
      ps->actions[i] = (unsigned char)add_flags;
622
0
      ps->n = i + 1;
623
0
    }
624
0
  }
625
0
  return CURLE_OK;
626
0
}
627
628
CURLcode Curl_pollset_set(struct Curl_easy *data,
629
                          struct easy_pollset *ps, curl_socket_t sock,
630
                          bool do_in, bool do_out)
631
0
{
632
0
  return Curl_pollset_change(data, ps, sock,
633
0
                             (do_in ? CURL_POLL_IN : 0) |
634
0
                             (do_out ? CURL_POLL_OUT : 0),
635
0
                             (!do_in ? CURL_POLL_IN : 0) |
636
0
                             (!do_out ? CURL_POLL_OUT : 0));
637
0
}
638
639
/*
640
 * Return values:
641
 *   -1 = error
642
 *    0 = timeout
643
 *    N = number of structures with non zero revent fields
644
 */
645
int Curl_pollset_poll(struct Curl_easy *data,
646
                      struct easy_pollset *ps,
647
                      timediff_t timeout_ms)
648
0
{
649
0
  struct pollfd *pfds;
650
0
  unsigned int i, npfds;
651
0
  int rc;
652
653
0
  (void)data;
654
0
  DEBUGASSERT(data);
655
0
  DEBUGASSERT(data->conn);
656
657
0
  if(!ps->n)
658
0
    return curlx_wait_ms(timeout_ms);
659
660
0
  pfds = curlx_calloc(ps->n, sizeof(*pfds));
661
0
  if(!pfds)
662
0
    return -1;
663
664
0
  npfds = 0;
665
0
  for(i = 0; i < ps->n; ++i) {
666
0
    short events = 0;
667
0
    if(ps->actions[i] & CURL_POLL_IN) {
668
0
      events |= POLLIN;
669
0
    }
670
0
    if(ps->actions[i] & CURL_POLL_OUT) {
671
0
      events |= POLLOUT;
672
0
    }
673
0
    if(events) {
674
0
      pfds[npfds].fd = ps->sockets[i];
675
0
      pfds[npfds].events = events;
676
0
      ++npfds;
677
0
    }
678
0
  }
679
680
0
  rc = Curl_poll(pfds, npfds, timeout_ms);
681
0
  curlx_free(pfds);
682
0
  return rc;
683
0
}
684
685
void Curl_pollset_check(struct Curl_easy *data,
686
                        struct easy_pollset *ps, curl_socket_t sock,
687
                        bool *pwant_read, bool *pwant_write)
688
0
{
689
0
  unsigned int i;
690
691
0
  (void)data;
692
0
  DEBUGASSERT(VALID_SOCK(sock));
693
0
  for(i = 0; i < ps->n; ++i) {
694
0
    if(ps->sockets[i] == sock) {
695
0
      *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
696
0
      *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
697
0
      return;
698
0
    }
699
0
  }
700
0
  *pwant_read = *pwant_write = FALSE;
701
0
}
702
703
bool Curl_pollset_want_recv(struct Curl_easy *data,
704
                            struct easy_pollset *ps,
705
                            curl_socket_t sock)
706
0
{
707
0
  unsigned int i;
708
0
  (void)data;
709
0
  for(i = 0; i < ps->n; ++i) {
710
0
    if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
711
0
      return TRUE;
712
0
  }
713
0
  return FALSE;
714
0
}
715
716
bool Curl_pollset_want_send(struct Curl_easy *data,
717
                            struct easy_pollset *ps,
718
                            curl_socket_t sock)
719
0
{
720
0
  unsigned int i;
721
0
  (void)data;
722
0
  for(i = 0; i < ps->n; ++i) {
723
0
    if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_OUT))
724
0
      return TRUE;
725
0
  }
726
0
  return FALSE;
727
0
}