blob: df68402981459d5417270db5a32e32b824eacc48 [file] [log] [blame]
Robbie Shade8d5196d2015-08-13 19:10:28 -04001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Robbie Shade8d5196d2015-08-13 19:10:28 -04004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Robbie Shadea4e21a12015-07-10 14:16:31 -040034/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE
37#endif
38
39#include <grpc/support/port_platform.h>
40
41#ifdef GPR_POSIX_SOCKET
42
Craig Tiller9533d042016-03-25 17:11:06 -070043#include "src/core/lib/iomgr/udp_server.h"
Robbie Shadea4e21a12015-07-10 14:16:31 -040044
45#include <errno.h>
46#include <fcntl.h>
47#include <limits.h>
48#include <netinet/in.h>
49#include <netinet/tcp.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040050#include <string.h>
51#include <sys/socket.h>
52#include <sys/stat.h>
53#include <sys/types.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040054#include <unistd.h>
55
Craig Tillerf40df232016-03-25 13:38:14 -070056#include <grpc/grpc.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040057#include <grpc/support/alloc.h>
58#include <grpc/support/log.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040059#include <grpc/support/string_util.h>
Craig Tillerf40df232016-03-25 13:38:14 -070060#include <grpc/support/sync.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040061#include <grpc/support/time.h>
Nicolas "Pixel" Noblef55adec2016-07-14 02:20:16 +020062#include "src/core/lib/iomgr/error.h"
Craig Tiller8a034482016-03-28 16:09:04 -070063#include "src/core/lib/iomgr/ev_posix.h"
Craig Tiller9533d042016-03-25 17:11:06 -070064#include "src/core/lib/iomgr/resolve_address.h"
65#include "src/core/lib/iomgr/sockaddr_utils.h"
66#include "src/core/lib/iomgr/socket_utils_posix.h"
Craig Tiller9533d042016-03-25 17:11:06 -070067#include "src/core/lib/support/string.h"
Robbie Shadea4e21a12015-07-10 14:16:31 -040068
69#define INIT_PORT_CAP 2
70
71/* one listening port */
Craig Tillera82950e2015-09-22 12:33:20 -070072typedef struct {
Robbie Shadea4e21a12015-07-10 14:16:31 -040073 int fd;
74 grpc_fd *emfd;
75 grpc_udp_server *server;
Craig Tillera82950e2015-09-22 12:33:20 -070076 union {
Craig Tiller7536af02015-12-22 13:49:30 -080077 uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
Robbie Shadea4e21a12015-07-10 14:16:31 -040078 struct sockaddr sockaddr;
Robbie Shadea4e21a12015-07-10 14:16:31 -040079 } addr;
Craig Tillerf96dfc32015-09-10 14:43:18 -070080 size_t addr_len;
Craig Tiller33825112015-09-18 07:44:19 -070081 grpc_closure read_closure;
82 grpc_closure destroyed_closure;
Robbie Shadea4e21a12015-07-10 14:16:31 -040083 grpc_udp_server_read_cb read_cb;
Robbie Shade9aa6f402016-05-12 13:28:04 -040084 grpc_udp_server_orphan_cb orphan_cb;
Robbie Shadea4e21a12015-07-10 14:16:31 -040085} server_port;
86
Robbie Shadea4e21a12015-07-10 14:16:31 -040087/* the overall server */
Craig Tillera82950e2015-09-22 12:33:20 -070088struct grpc_udp_server {
Robbie Shadea4e21a12015-07-10 14:16:31 -040089 gpr_mu mu;
90 gpr_cv cv;
91
92 /* active port count: how many ports are actually still listening */
93 size_t active_ports;
94 /* destroyed port count: how many ports are completely destroyed */
95 size_t destroyed_ports;
96
97 /* is this server shutting down? (boolean) */
98 int shutdown;
99
100 /* all listening ports */
101 server_port *ports;
102 size_t nports;
103 size_t port_capacity;
104
105 /* shutdown callback */
Craig Tillerd1bec032015-09-18 17:29:00 -0700106 grpc_closure *shutdown_complete;
Robbie Shade1cef6dc2015-07-15 14:16:48 -0400107
108 /* all pollsets interested in new connections */
109 grpc_pollset **pollsets;
110 /* number of pollsets in the pollsets array */
111 size_t pollset_count;
Robbie Shade147fe702015-09-25 15:04:40 -0400112 /* The parent grpc server */
Craig Tiller71a0f9d2015-09-28 17:22:01 -0700113 grpc_server *grpc_server;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400114};
115
Craig Tillera82950e2015-09-22 12:33:20 -0700116grpc_udp_server *grpc_udp_server_create(void) {
117 grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
118 gpr_mu_init(&s->mu);
119 gpr_cv_init(&s->cv);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400120 s->active_ports = 0;
121 s->destroyed_ports = 0;
122 s->shutdown = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700123 s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400124 s->nports = 0;
125 s->port_capacity = INIT_PORT_CAP;
126
Robbie Shadea4e21a12015-07-10 14:16:31 -0400127 return s;
128}
129
Craig Tillera82950e2015-09-22 12:33:20 -0700130static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
Nicolas "Pixel" Noblef55adec2016-07-14 02:20:16 +0200131 grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400132
Craig Tillera82950e2015-09-22 12:33:20 -0700133 gpr_mu_destroy(&s->mu);
134 gpr_cv_destroy(&s->cv);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400135
Craig Tillera82950e2015-09-22 12:33:20 -0700136 gpr_free(s->ports);
137 gpr_free(s);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400138}
139
Bogdan Drutuf89fdf32016-02-16 14:38:38 -0800140static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
Nicolas "Pixel" Noblef55adec2016-07-14 02:20:16 +0200141 grpc_error *error) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400142 grpc_udp_server *s = server;
Craig Tillera82950e2015-09-22 12:33:20 -0700143 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400144 s->destroyed_ports++;
Craig Tillera82950e2015-09-22 12:33:20 -0700145 if (s->destroyed_ports == s->nports) {
146 gpr_mu_unlock(&s->mu);
147 finish_shutdown(exec_ctx, s);
148 } else {
149 gpr_mu_unlock(&s->mu);
150 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400151}
152
Robbie Shadea4e21a12015-07-10 14:16:31 -0400153/* called when all listening endpoints have been shutdown, so no further
154 events will be received on them - at this point it's safe to destroy
155 things */
Craig Tillera82950e2015-09-22 12:33:20 -0700156static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400157 size_t i;
158
159 /* delete ALL the things */
Craig Tillera82950e2015-09-22 12:33:20 -0700160 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400161
Craig Tillera82950e2015-09-22 12:33:20 -0700162 if (!s->shutdown) {
163 gpr_mu_unlock(&s->mu);
164 return;
165 }
Craig Tiller45724b32015-09-22 10:42:19 -0700166
Craig Tillera82950e2015-09-22 12:33:20 -0700167 if (s->nports) {
168 for (i = 0; i < s->nports; i++) {
169 server_port *sp = &s->ports[i];
Craig Tillera82950e2015-09-22 12:33:20 -0700170 sp->destroyed_closure.cb = destroyed_port;
171 sp->destroyed_closure.cb_arg = s;
Robbie Shade9aa6f402016-05-12 13:28:04 -0400172
Robbie Shadece8f9772016-08-01 16:06:00 -0400173 /* Call the orphan_cb to signal that the FD is about to be closed and
174 * should no longer be used. */
Robbie Shade9aa6f402016-05-12 13:28:04 -0400175 GPR_ASSERT(sp->orphan_cb);
176 sp->orphan_cb(sp->emfd);
177
yang-g5d850372015-12-01 10:32:28 -0800178 grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
Craig Tillera82950e2015-09-22 12:33:20 -0700179 "udp_listener_shutdown");
Craig Tiller45724b32015-09-22 10:42:19 -0700180 }
Craig Tillera82950e2015-09-22 12:33:20 -0700181 gpr_mu_unlock(&s->mu);
182 } else {
183 gpr_mu_unlock(&s->mu);
184 finish_shutdown(exec_ctx, s);
185 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400186}
187
Craig Tillera82950e2015-09-22 12:33:20 -0700188void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
189 grpc_closure *on_done) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400190 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700191 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400192
Craig Tillera82950e2015-09-22 12:33:20 -0700193 GPR_ASSERT(!s->shutdown);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400194 s->shutdown = 1;
195
Craig Tillerd1bec032015-09-18 17:29:00 -0700196 s->shutdown_complete = on_done;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400197
198 /* shutdown all fd's */
Craig Tillera82950e2015-09-22 12:33:20 -0700199 if (s->active_ports) {
200 for (i = 0; i < s->nports; i++) {
Robbie Shadece8f9772016-08-01 16:06:00 -0400201 /* Call the orphan_cb to signal that the FD is about to be closed and
202 * should no longer be used. */
203 GPR_ASSERT(sp->orphan_cb);
204 sp->orphan_cb(sp->emfd);
205
Craig Tillera82950e2015-09-22 12:33:20 -0700206 grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400207 }
Craig Tillera82950e2015-09-22 12:33:20 -0700208 gpr_mu_unlock(&s->mu);
209 } else {
210 gpr_mu_unlock(&s->mu);
211 deactivated_all_ports(exec_ctx, s);
212 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400213}
214
215/* Prepare a recently-created socket for listening. */
Craig Tillera82950e2015-09-22 12:33:20 -0700216static int prepare_socket(int fd, const struct sockaddr *addr,
217 size_t addr_len) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400218 struct sockaddr_storage sockname_temp;
219 socklen_t sockname_len;
Robbie Shade3f30e632016-06-08 08:40:56 -0400220 /* Set send/receive socket buffers to 1 MB */
221 int buffer_size_bytes = 1024 * 1024;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400222
Craig Tillera82950e2015-09-22 12:33:20 -0700223 if (fd < 0) {
224 goto error;
225 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400226
Robbie Shadeae8c64d2016-06-30 11:15:36 -0400227 if (grpc_set_socket_nonblocking(fd, 1) != GRPC_ERROR_NONE) {
228 gpr_log(GPR_ERROR, "Unable to set nonblocking %d: %s", fd, strerror(errno));
229 goto error;
230 }
231 if (grpc_set_socket_cloexec(fd, 1) != GRPC_ERROR_NONE) {
232 gpr_log(GPR_ERROR, "Unable to set cloexec %d: %s", fd, strerror(errno));
233 goto error;
Craig Tillera82950e2015-09-22 12:33:20 -0700234 }
Robbie Shade6f03dff2015-09-01 10:35:39 -0400235
Robbie Shadeae8c64d2016-06-30 11:15:36 -0400236 if (grpc_set_socket_ip_pktinfo_if_possible(fd) != GRPC_ERROR_NONE) {
237 gpr_log(GPR_ERROR, "Unable to set ip_pktinfo.");
238 goto error;
239 } else if (addr->sa_family == AF_INET6) {
240 if (grpc_set_socket_ipv6_recvpktinfo_if_possible(fd) != GRPC_ERROR_NONE) {
241 gpr_log(GPR_ERROR, "Unable to set ipv6_recvpktinfo.");
242 goto error;
243 }
Craig Tillera82950e2015-09-22 12:33:20 -0700244 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400245
Craig Tillera82950e2015-09-22 12:33:20 -0700246 GPR_ASSERT(addr_len < ~(socklen_t)0);
247 if (bind(fd, addr, (socklen_t)addr_len) < 0) {
248 char *addr_str;
249 grpc_sockaddr_to_string(&addr_str, addr, 0);
250 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
251 gpr_free(addr_str);
252 goto error;
253 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400254
Craig Tillera82950e2015-09-22 12:33:20 -0700255 sockname_len = sizeof(sockname_temp);
256 if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
257 goto error;
258 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400259
Robbie Shadeae8c64d2016-06-30 11:15:36 -0400260 if (grpc_set_socket_sndbuf(fd, buffer_size_bytes) != GRPC_ERROR_NONE) {
Robbie Shade3f30e632016-06-08 08:40:56 -0400261 gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes",
yang-g773a8822016-06-13 11:09:29 -0700262 buffer_size_bytes);
Robbie Shade3f30e632016-06-08 08:40:56 -0400263 goto error;
264 }
265
Robbie Shadeae8c64d2016-06-30 11:15:36 -0400266 if (grpc_set_socket_rcvbuf(fd, buffer_size_bytes) != GRPC_ERROR_NONE) {
Robbie Shade3f30e632016-06-08 08:40:56 -0400267 gpr_log(GPR_ERROR, "Failed to set receive buffer size to %d bytes",
yang-g773a8822016-06-13 11:09:29 -0700268 buffer_size_bytes);
Robbie Shade3f30e632016-06-08 08:40:56 -0400269 goto error;
270 }
271
Craig Tillera82950e2015-09-22 12:33:20 -0700272 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400273
274error:
Craig Tillera82950e2015-09-22 12:33:20 -0700275 if (fd >= 0) {
276 close(fd);
277 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400278 return -1;
279}
280
281/* event manager callback when reads are ready */
Nicolas "Pixel" Noblef55adec2016-07-14 02:20:16 +0200282static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400283 server_port *sp = arg;
284
Robbie Shade7f6864a2016-06-30 15:11:28 -0400285 if (error != GRPC_ERROR_NONE) {
Craig Tillera82950e2015-09-22 12:33:20 -0700286 gpr_mu_lock(&sp->server->mu);
287 if (0 == --sp->server->active_ports) {
288 gpr_mu_unlock(&sp->server->mu);
289 deactivated_all_ports(exec_ctx, sp->server);
290 } else {
291 gpr_mu_unlock(&sp->server->mu);
Robbie Shadef2eb48a2015-08-04 19:19:36 -0400292 }
Craig Tillera82950e2015-09-22 12:33:20 -0700293 return;
294 }
Robbie Shadef2eb48a2015-08-04 19:19:36 -0400295
Robbie Shadea4e21a12015-07-10 14:16:31 -0400296 /* Tell the registered callback that data is available to read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700297 GPR_ASSERT(sp->read_cb);
Robbie Shadec6787b22015-10-07 10:13:53 -0400298 sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400299
300 /* Re-arm the notification event so we get another chance to read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700301 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400302}
303
Craig Tillera82950e2015-09-22 12:33:20 -0700304static int add_socket_to_server(grpc_udp_server *s, int fd,
305 const struct sockaddr *addr, size_t addr_len,
Robbie Shade9aa6f402016-05-12 13:28:04 -0400306 grpc_udp_server_read_cb read_cb,
307 grpc_udp_server_orphan_cb orphan_cb) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400308 server_port *sp;
309 int port;
310 char *addr_str;
311 char *name;
312
Craig Tillera82950e2015-09-22 12:33:20 -0700313 port = prepare_socket(fd, addr, addr_len);
314 if (port >= 0) {
315 grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
316 gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
Craig Tiller7db24e02015-09-24 23:44:07 -0700317 gpr_free(addr_str);
Craig Tillera82950e2015-09-22 12:33:20 -0700318 gpr_mu_lock(&s->mu);
319 /* append it to the list under a lock */
320 if (s->nports == s->port_capacity) {
321 s->port_capacity *= 2;
322 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400323 }
Craig Tillera82950e2015-09-22 12:33:20 -0700324 sp = &s->ports[s->nports++];
325 sp->server = s;
326 sp->fd = fd;
327 sp->emfd = grpc_fd_create(fd, name);
328 memcpy(sp->addr.untyped, addr, addr_len);
329 sp->addr_len = addr_len;
330 sp->read_cb = read_cb;
Robbie Shade9aa6f402016-05-12 13:28:04 -0400331 sp->orphan_cb = orphan_cb;
Craig Tillera82950e2015-09-22 12:33:20 -0700332 GPR_ASSERT(sp->emfd);
333 gpr_mu_unlock(&s->mu);
Craig Tiller7db24e02015-09-24 23:44:07 -0700334 gpr_free(name);
Craig Tillera82950e2015-09-22 12:33:20 -0700335 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400336
337 return port;
338}
339
Craig Tillera82950e2015-09-22 12:33:20 -0700340int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
Robbie Shade9aa6f402016-05-12 13:28:04 -0400341 size_t addr_len, grpc_udp_server_read_cb read_cb,
342 grpc_udp_server_orphan_cb orphan_cb) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400343 int allocated_port1 = -1;
344 int allocated_port2 = -1;
345 unsigned i;
346 int fd;
347 grpc_dualstack_mode dsmode;
348 struct sockaddr_in6 addr6_v4mapped;
349 struct sockaddr_in wild4;
350 struct sockaddr_in6 wild6;
351 struct sockaddr_in addr4_copy;
352 struct sockaddr *allocated_addr = NULL;
353 struct sockaddr_storage sockname_temp;
354 socklen_t sockname_len;
355 int port;
356
Robbie Shadea4e21a12015-07-10 14:16:31 -0400357 /* Check if this is a wildcard port, and if so, try to keep the port the same
358 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700359 if (grpc_sockaddr_get_port(addr) == 0) {
360 for (i = 0; i < s->nports; i++) {
361 sockname_len = sizeof(sockname_temp);
362 if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
363 &sockname_len)) {
364 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
365 if (port > 0) {
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100366 allocated_addr = gpr_malloc(addr_len);
Craig Tillera82950e2015-09-22 12:33:20 -0700367 memcpy(allocated_addr, addr, addr_len);
368 grpc_sockaddr_set_port(allocated_addr, port);
369 addr = allocated_addr;
370 break;
371 }
372 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400373 }
Craig Tillera82950e2015-09-22 12:33:20 -0700374 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400375
Craig Tillera82950e2015-09-22 12:33:20 -0700376 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
377 addr = (const struct sockaddr *)&addr6_v4mapped;
378 addr_len = sizeof(addr6_v4mapped);
379 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400380
381 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera82950e2015-09-22 12:33:20 -0700382 if (grpc_sockaddr_is_wildcard(addr, &port)) {
383 grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400384
Craig Tillera82950e2015-09-22 12:33:20 -0700385 /* Try listening on IPv6 first. */
386 addr = (struct sockaddr *)&wild6;
387 addr_len = sizeof(wild6);
Robbie Shade7e8b4172016-06-30 15:06:12 -0400388 // TODO(rjshade): Test and propagate the returned grpc_error*:
389 grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
Robbie Shade9aa6f402016-05-12 13:28:04 -0400390 allocated_port1 =
391 add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb);
Craig Tillera82950e2015-09-22 12:33:20 -0700392 if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
393 goto done;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400394 }
395
Craig Tillera82950e2015-09-22 12:33:20 -0700396 /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
397 if (port == 0 && allocated_port1 > 0) {
398 grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400399 }
Craig Tillera82950e2015-09-22 12:33:20 -0700400 addr = (struct sockaddr *)&wild4;
401 addr_len = sizeof(wild4);
402 }
403
Robbie Shade7e8b4172016-06-30 15:06:12 -0400404 // TODO(rjshade): Test and propagate the returned grpc_error*:
405 grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
Craig Tillera82950e2015-09-22 12:33:20 -0700406 if (fd < 0) {
407 gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
408 }
409 if (dsmode == GRPC_DSMODE_IPV4 &&
410 grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
411 addr = (struct sockaddr *)&addr4_copy;
412 addr_len = sizeof(addr4_copy);
413 }
Robbie Shade9aa6f402016-05-12 13:28:04 -0400414 allocated_port2 =
415 add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400416
417done:
Craig Tillera82950e2015-09-22 12:33:20 -0700418 gpr_free(allocated_addr);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400419 return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
420}
421
Vijay Pai7b080ba2015-09-29 22:22:36 +0000422int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) {
423 return (port_index < s->nports) ? s->ports[port_index].fd : -1;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400424}
425
Craig Tillera82950e2015-09-22 12:33:20 -0700426void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
Robbie Shade147fe702015-09-25 15:04:40 -0400427 grpc_pollset **pollsets, size_t pollset_count,
Robbie Shade109a8dc2015-09-25 15:18:49 -0400428 grpc_server *server) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400429 size_t i, j;
Craig Tillera82950e2015-09-22 12:33:20 -0700430 gpr_mu_lock(&s->mu);
431 GPR_ASSERT(s->active_ports == 0);
Robbie Shade1cef6dc2015-07-15 14:16:48 -0400432 s->pollsets = pollsets;
Robbie Shade109a8dc2015-09-25 15:18:49 -0400433 s->grpc_server = server;
Craig Tillera82950e2015-09-22 12:33:20 -0700434 for (i = 0; i < s->nports; i++) {
435 for (j = 0; j < pollset_count; j++) {
436 grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400437 }
Craig Tillera82950e2015-09-22 12:33:20 -0700438 s->ports[i].read_closure.cb = on_read;
439 s->ports[i].read_closure.cb_arg = &s->ports[i];
440 grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
441 &s->ports[i].read_closure);
442 s->active_ports++;
443 }
444 gpr_mu_unlock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400445}
446
Robbie Shadea4e21a12015-07-10 14:16:31 -0400447#endif