summaryrefslogblamecommitdiffstats
path: root/source/l/libuv/libuv.977be04762b9bda29a88d39bb3e2cb7c44b2ad22.patch
blob: f0dae9cb3ded2d5fff3d4b0b6e3fa53f125d9d54 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484



































































































































































































































































































































































































































































































                                                                                                 
From 977be04762b9bda29a88d39bb3e2cb7c44b2ad22 Mon Sep 17 00:00:00 2001
From: Ben Noordhuis <info@bnoordhuis.nl>
Date: Thu, 16 Apr 2020 09:59:03 +0200
Subject: [PATCH] Revert "freebsd,linux: add recvmmsg() + sendmmsg() udp
 implementation"

This reverts commit 3d7136639a39db46bc4a9074922559a564e49514.
This reverts commit d9cd7d437d6bcea56355b6e0ef215aa64687d7a1.

The first reverted commit is the sendmmsg/recvmmsg support, the second
one a fix-up to deliver datagrams in order. The second commit has been
implicated in causing bind9 to crash on freebsd.

A quick review of the code suggests that downstream code written against
pre-v1.35.0 libuv can't safely deal with multi-datagram support because
they are unaware of the `UV_UDP_MMSG_CHUNK` flag and what that implies
for buffer management, hence I'm moving to revert it.

The `UV_UDP_MMSG_CHUNK` flag remains part of `uv_udp_flags` for
API/ABI backwards compatibility reasons but it is no longer used.

Fixes: https://github.com/libuv/libuv/issues/2791
Refs: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245653
---
 docs/src/udp.rst          |  18 +---
 include/uv.h              |   5 +-
 src/unix/freebsd.c        |  25 -----
 src/unix/internal.h       |  24 -----
 src/unix/linux-syscalls.c |   1 -
 src/unix/linux-syscalls.h |  14 +++
 src/unix/udp.c            | 207 +-------------------------------------
 7 files changed, 22 insertions(+), 272 deletions(-)

diff --git a/docs/src/udp.rst b/docs/src/udp.rst
index 786a28b030..53b1fea493 100644
--- a/docs/src/udp.rst
+++ b/docs/src/udp.rst
@@ -42,11 +42,6 @@ Data types
             * any traffic, in effect "stealing" the port from the previous listener.
             */
             UV_UDP_REUSEADDR = 4
-            /*
-             * Indicates that the message was received by recvmmsg, so the buffer provided
-             * must not be freed by the recv_cb callback.
-             */
-            UV_UDP_MMSG_CHUNK = 8
         };
 
 .. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
@@ -67,18 +62,13 @@ Data types
     * `buf`: :c:type:`uv_buf_t` with the received data.
     * `addr`: ``struct sockaddr*`` containing the address of the sender.
       Can be NULL. Valid for the duration of the callback only.
-    * `flags`: One or more or'ed UV_UDP_* constants.
+    * `flags`: One or more or'ed UV_UDP_* constants. Right now only
+      ``UV_UDP_PARTIAL`` is used.
 
     The callee is responsible for freeing the buffer, libuv does not reuse it.
     The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0)
     on error.
 
-    When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set,
-    those must not be freed. There will be a final callback with `nread` set to 0,
-    `addr` set to NULL and the buffer pointing at the initially allocated data with
-    the `UV_UDP_MMSG_CHUNK` flag cleared. This is a good chance for the callee to
-    free the provided buffer.
-
     .. note::
         The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
         nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is
@@ -376,10 +366,6 @@ API
 
     :returns: 0 on success, or an error code < 0 on failure.
 
-    .. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms).
-                        The use of this feature requires a buffer larger than
-                        2 * 64KB to be passed to `alloc_cb`.
-
 .. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
 
     Stop listening for incoming datagrams.
diff --git a/include/uv.h b/include/uv.h
index 2e8072fdae..dd8c8a40b0 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -1,4 +1,4 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+/* COPYRIGHT JOYENT, INC. AND OTHER NODE CONTRIBUTORS. ALL RIGHTS RESERVED.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -607,8 +607,7 @@ enum uv_udp_flags {
    */
   UV_UDP_REUSEADDR = 4,
   /*
-   * Indicates that the message was received by recvmmsg, so the buffer provided
-   * must not be freed by the recv_cb callback.
+   * Unused. Here for API/ABI compatibility.
    */
   UV_UDP_MMSG_CHUNK = 8
 };
diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c
index ef77e127c2..57bd04e240 100644
--- a/src/unix/freebsd.c
+++ b/src/unix/freebsd.c
@@ -288,28 +288,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
   uv__free(cp_times);
   return 0;
 }
-
-
-int uv__sendmmsg(int fd,
-                 struct uv__mmsghdr* mmsg,
-                 unsigned int vlen,
-                 unsigned int flags) {
-#if __FreeBSD__ >= 11
-  return sendmmsg(fd, mmsg, vlen, flags);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__recvmmsg(int fd,
-                 struct uv__mmsghdr* mmsg,
-                 unsigned int vlen,
-                 unsigned int flags,
-                 struct timespec* timeout) {
-#if __FreeBSD__ >= 11
-  return recvmmsg(fd, mmsg, vlen, flags, timeout);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
diff --git a/src/unix/internal.h b/src/unix/internal.h
index 598554b607..469fd7d2b8 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -31,7 +31,6 @@
 #include <fcntl.h>  /* O_CLOEXEC and O_NONBLOCK, if supported. */
 #include <stdio.h>
 #include <errno.h>
-#include <sys/socket.h>
 
 #if defined(__STRICT_ANSI__)
 # define inline __inline
@@ -328,27 +327,4 @@ int uv__getsockpeername(const uv_handle_t* handle,
                         struct sockaddr* name,
                         int* namelen);
 
-#if defined(__linux__)            ||                                      \
-    defined(__FreeBSD__)          ||                                      \
-    defined(__FreeBSD_kernel__)
-#define HAVE_MMSG 1
-struct uv__mmsghdr {
-  struct msghdr msg_hdr;
-  unsigned int msg_len;
-};
-
-int uv__recvmmsg(int fd,
-                 struct uv__mmsghdr* mmsg,
-                 unsigned int vlen,
-                 unsigned int flags,
-                 struct timespec* timeout);
-int uv__sendmmsg(int fd,
-                 struct uv__mmsghdr* mmsg,
-                 unsigned int vlen,
-                 unsigned int flags);
-#else
-#define HAVE_MMSG 0
-#endif
-
-
 #endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c
index 742f26ada8..eb5a8fd274 100644
--- a/src/unix/linux-syscalls.c
+++ b/src/unix/linux-syscalls.c
@@ -126,7 +126,6 @@
 # endif
 #endif /* __NR_getrandom */
 
-struct uv__mmsghdr;
 
 int uv__sendmmsg(int fd,
                  struct uv__mmsghdr* mmsg,
diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h
index 2e8fa2a519..7ee1511a45 100644
--- a/src/unix/linux-syscalls.h
+++ b/src/unix/linux-syscalls.h
@@ -61,6 +61,20 @@ struct uv__statx {
   uint64_t unused1[14];
 };
 
+struct uv__mmsghdr {
+  struct msghdr msg_hdr;
+  unsigned int msg_len;
+};
+
+int uv__recvmmsg(int fd,
+                 struct uv__mmsghdr* mmsg,
+                 unsigned int vlen,
+                 unsigned int flags,
+                 struct timespec* timeout);
+int uv__sendmmsg(int fd,
+                 struct uv__mmsghdr* mmsg,
+                 unsigned int vlen,
+                 unsigned int flags);
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
 ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
 int uv__dup3(int oldfd, int newfd, int flags);
diff --git a/src/unix/udp.c b/src/unix/udp.c
index f2fcae1760..982059ff48 100644
--- a/src/unix/udp.c
+++ b/src/unix/udp.c
@@ -32,8 +32,6 @@
 #endif
 #include <sys/un.h>
 
-#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
-
 #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
 # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
 #endif
@@ -51,36 +49,6 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
                                        int domain,
                                        unsigned int flags);
 
-#if HAVE_MMSG
-
-#define UV__MMSG_MAXWIDTH 20
-
-static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
-static void uv__udp_sendmmsg(uv_udp_t* handle);
-
-static int uv__recvmmsg_avail;
-static int uv__sendmmsg_avail;
-static uv_once_t once = UV_ONCE_INIT;
-
-static void uv__udp_mmsg_init(void) {
-  int ret;
-  int s;
-  s = uv__socket(AF_INET, SOCK_DGRAM, 0);
-  if (s < 0)
-    return;
-  ret = uv__sendmmsg(s, NULL, 0, 0);
-  if (ret == 0 || errno != ENOSYS) {
-    uv__sendmmsg_avail = 1;
-    uv__recvmmsg_avail = 1;
-  } else {
-    ret = uv__recvmmsg(s, NULL, 0, 0, NULL);
-    if (ret == 0 || errno != ENOSYS)
-      uv__recvmmsg_avail = 1;
-  }
-  uv__close(s);
-}
-
-#endif
 
 void uv__udp_close(uv_udp_t* handle) {
   uv__io_close(handle->loop, &handle->io_watcher);
@@ -180,61 +148,6 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
   }
 }
 
-#if HAVE_MMSG
-static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
-  struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
-  struct iovec iov[UV__MMSG_MAXWIDTH];
-  struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
-  ssize_t nread;
-  uv_buf_t chunk_buf;
-  size_t chunks;
-  int flags;
-  size_t k;
-
-  /* prepare structures for recvmmsg */
-  chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
-  if (chunks > ARRAY_SIZE(iov))
-    chunks = ARRAY_SIZE(iov);
-  for (k = 0; k < chunks; ++k) {
-    iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
-    iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
-    msgs[k].msg_hdr.msg_iov = iov + k;
-    msgs[k].msg_hdr.msg_iovlen = 1;
-    msgs[k].msg_hdr.msg_name = peers + k;
-    msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
-  }
-
-  do
-    nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
-  while (nread == -1 && errno == EINTR);
-
-  if (nread < 1) {
-    if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
-      handle->recv_cb(handle, 0, buf, NULL, 0);
-    else
-      handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
-  } else {
-    /* pass each chunk to the application */
-    for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
-      flags = UV_UDP_MMSG_CHUNK;
-      if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
-        flags |= UV_UDP_PARTIAL;
-
-      chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
-      handle->recv_cb(handle,
-                      msgs[k].msg_len,
-                      &chunk_buf,
-                      msgs[k].msg_hdr.msg_name,
-                      flags);
-    }
-
-    /* one last callback so the original buffer is freed */
-    if (handle->recv_cb != NULL)
-      handle->recv_cb(handle, 0, buf, NULL, 0);
-  }
-  return nread;
-}
-#endif
 
 static void uv__udp_recvmsg(uv_udp_t* handle) {
   struct sockaddr_storage peer;
@@ -254,27 +167,13 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
 
   do {
     buf = uv_buf_init(NULL, 0);
-    handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
+    handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
     if (buf.base == NULL || buf.len == 0) {
       handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
       return;
     }
     assert(buf.base != NULL);
 
-#if HAVE_MMSG
-    uv_once(&once, uv__udp_mmsg_init);
-    if (uv__recvmmsg_avail) {
-      /* Returned space for more than 1 datagram, use it to receive
-       * multiple datagrams. */
-      if (buf.len >= 2 * UV__UDP_DGRAM_MAXSIZE) {
-        nread = uv__udp_recvmmsg(handle, &buf);
-        if (nread > 0)
-          count -= nread;
-        continue;
-      }
-    }
-#endif
-
     memset(&h, 0, sizeof(h));
     memset(&peer, 0, sizeof(peer));
     h.msg_name = &peer;
@@ -300,120 +199,21 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
 
       handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
     }
-    count--;
   }
   /* recv_cb callback may decide to pause or close the handle */
   while (nread != -1
-      && count > 0
+      && count-- > 0
       && handle->io_watcher.fd != -1
       && handle->recv_cb != NULL);
 }
 
-#if HAVE_MMSG
-static void uv__udp_sendmmsg(uv_udp_t* handle) {
-  uv_udp_send_t* req;
-  struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
-  struct uv__mmsghdr *p;
-  QUEUE* q;
-  ssize_t npkts;
-  size_t pkts;
-  size_t i;
-
-  if (QUEUE_EMPTY(&handle->write_queue))
-    return;
-
-write_queue_drain:
-  for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
-       pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
-       ++pkts, q = QUEUE_HEAD(q)) {
-    assert(q != NULL);
-    req = QUEUE_DATA(q, uv_udp_send_t, queue);
-    assert(req != NULL);
-
-    p = &h[pkts];
-    memset(p, 0, sizeof(*p));
-    if (req->addr.ss_family == AF_UNSPEC) {
-      p->msg_hdr.msg_name = NULL;
-      p->msg_hdr.msg_namelen = 0;
-    } else {
-      p->msg_hdr.msg_name = &req->addr;
-      if (req->addr.ss_family == AF_INET6)
-        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
-      else if (req->addr.ss_family == AF_INET)
-        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
-      else if (req->addr.ss_family == AF_UNIX)
-        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
-      else {
-        assert(0 && "unsupported address family");
-        abort();
-      }
-    }
-    h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
-    h[pkts].msg_hdr.msg_iovlen = req->nbufs;
-  }
-
-  do
-    npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0);
-  while (npkts == -1 && errno == EINTR);
-
-  if (npkts < 1) {
-    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
-      return;
-    for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
-         i < pkts && q != &handle->write_queue;
-         ++i, q = QUEUE_HEAD(q)) {
-      assert(q != NULL);
-      req = QUEUE_DATA(q, uv_udp_send_t, queue);
-      assert(req != NULL);
-
-      req->status = UV__ERR(errno);
-      QUEUE_REMOVE(&req->queue);
-      QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
-    }
-    uv__io_feed(handle->loop, &handle->io_watcher);
-    return;
-  }
-
-  for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
-       i < pkts && q != &handle->write_queue;
-       ++i, q = QUEUE_HEAD(&handle->write_queue)) {
-    assert(q != NULL);
-    req = QUEUE_DATA(q, uv_udp_send_t, queue);
-    assert(req != NULL);
-
-    req->status = req->bufs[0].len;
-
-    /* Sending a datagram is an atomic operation: either all data
-     * is written or nothing is (and EMSGSIZE is raised). That is
-     * why we don't handle partial writes. Just pop the request
-     * off the write queue and onto the completed queue, done.
-     */
-    QUEUE_REMOVE(&req->queue);
-    QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
-  }
-
-  /* couldn't batch everything, continue sending (jump to avoid stack growth) */
-  if (!QUEUE_EMPTY(&handle->write_queue))
-    goto write_queue_drain;
-  uv__io_feed(handle->loop, &handle->io_watcher);
-  return;
-}
-#endif
 
 static void uv__udp_sendmsg(uv_udp_t* handle) {
   uv_udp_send_t* req;
-  struct msghdr h;
   QUEUE* q;
+  struct msghdr h;
   ssize_t size;
 
-#if HAVE_MMSG
-  uv_once(&once, uv__udp_mmsg_init);
-  if (uv__sendmmsg_avail) {
-    uv__udp_sendmmsg(handle);
-    return;
-  }
-#endif
-
   while (!QUEUE_EMPTY(&handle->write_queue)) {
     q = QUEUE_HEAD(&handle->write_queue);
     assert(q != NULL);
@@ -463,6 +263,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
   }
 }
 
+
 /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
  * refinements for programs that use multicast.
  *