Coverage Report

Created: 2025-08-26 07:08

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