blob: 174159170f36a76250ca430da2bc07672bdd1dcc [file] [log] [blame]
Robbie Shade8d5196d2015-08-13 19:10:28 -04001/*
2 *
Robbie Shade3d14fd62016-01-28 11:30:42 -05003 * Copyright 2015-2016, 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
Craig Tiller2908a762015-12-10 14:48:24 -080041#ifdef GRPC_NEED_UDP
Robbie Shadea4e21a12015-07-10 14:16:31 -040042#ifdef GPR_POSIX_SOCKET
43
44#include "src/core/iomgr/udp_server.h"
45
46#include <errno.h>
47#include <fcntl.h>
48#include <limits.h>
49#include <netinet/in.h>
50#include <netinet/tcp.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040051#include <string.h>
52#include <sys/socket.h>
53#include <sys/stat.h>
54#include <sys/types.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040055#include <unistd.h>
56
Craig Tillerf40df232016-03-25 13:38:14 -070057#include <grpc/grpc.h>
58#include <grpc/support/alloc.h>
59#include <grpc/support/log.h>
60#include <grpc/support/string_util.h>
61#include <grpc/support/sync.h>
62#include <grpc/support/time.h>
Robbie Shadea4e21a12015-07-10 14:16:31 -040063#include "src/core/iomgr/fd_posix.h"
64#include "src/core/iomgr/pollset_posix.h"
65#include "src/core/iomgr/resolve_address.h"
66#include "src/core/iomgr/sockaddr_utils.h"
67#include "src/core/iomgr/socket_utils_posix.h"
ahedberg80d6b122016-03-17 17:37:35 -040068#include "src/core/iomgr/unix_sockets_posix.h"
Robbie Shadea4e21a12015-07-10 14:16:31 -040069#include "src/core/support/string.h"
Robbie Shadea4e21a12015-07-10 14:16:31 -040070
71#define INIT_PORT_CAP 2
72
73/* one listening port */
Craig Tillera82950e2015-09-22 12:33:20 -070074typedef struct {
Robbie Shadea4e21a12015-07-10 14:16:31 -040075 int fd;
76 grpc_fd *emfd;
77 grpc_udp_server *server;
Craig Tillera82950e2015-09-22 12:33:20 -070078 union {
Craig Tiller7536af02015-12-22 13:49:30 -080079 uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
Robbie Shadea4e21a12015-07-10 14:16:31 -040080 struct sockaddr sockaddr;
Robbie Shadea4e21a12015-07-10 14:16:31 -040081 } addr;
Craig Tillerf96dfc32015-09-10 14:43:18 -070082 size_t addr_len;
Craig Tiller33825112015-09-18 07:44:19 -070083 grpc_closure read_closure;
84 grpc_closure destroyed_closure;
Robbie Shadea4e21a12015-07-10 14:16:31 -040085 grpc_udp_server_read_cb read_cb;
86} server_port;
87
Robbie Shadea4e21a12015-07-10 14:16:31 -040088/* the overall server */
Craig Tillera82950e2015-09-22 12:33:20 -070089struct grpc_udp_server {
Robbie Shadea4e21a12015-07-10 14:16:31 -040090 gpr_mu mu;
91 gpr_cv cv;
92
93 /* active port count: how many ports are actually still listening */
94 size_t active_ports;
95 /* destroyed port count: how many ports are completely destroyed */
96 size_t destroyed_ports;
97
98 /* is this server shutting down? (boolean) */
99 int shutdown;
100
101 /* all listening ports */
102 server_port *ports;
103 size_t nports;
104 size_t port_capacity;
105
106 /* shutdown callback */
Craig Tillerd1bec032015-09-18 17:29:00 -0700107 grpc_closure *shutdown_complete;
Robbie Shade1cef6dc2015-07-15 14:16:48 -0400108
109 /* all pollsets interested in new connections */
110 grpc_pollset **pollsets;
111 /* number of pollsets in the pollsets array */
112 size_t pollset_count;
Robbie Shade147fe702015-09-25 15:04:40 -0400113 /* The parent grpc server */
Craig Tiller71a0f9d2015-09-28 17:22:01 -0700114 grpc_server *grpc_server;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400115};
116
Craig Tillera82950e2015-09-22 12:33:20 -0700117grpc_udp_server *grpc_udp_server_create(void) {
118 grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
119 gpr_mu_init(&s->mu);
120 gpr_cv_init(&s->cv);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400121 s->active_ports = 0;
122 s->destroyed_ports = 0;
123 s->shutdown = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700124 s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400125 s->nports = 0;
126 s->port_capacity = INIT_PORT_CAP;
127
Robbie Shadea4e21a12015-07-10 14:16:31 -0400128 return s;
129}
130
Craig Tillera82950e2015-09-22 12:33:20 -0700131static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
Bogdan Drutuddecc612016-02-16 14:54:35 -0800132 grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400133
Craig Tillera82950e2015-09-22 12:33:20 -0700134 gpr_mu_destroy(&s->mu);
135 gpr_cv_destroy(&s->cv);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400136
Craig Tillera82950e2015-09-22 12:33:20 -0700137 gpr_free(s->ports);
138 gpr_free(s);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400139}
140
Bogdan Drutuf89fdf32016-02-16 14:38:38 -0800141static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
142 bool success) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400143 grpc_udp_server *s = server;
Craig Tillera82950e2015-09-22 12:33:20 -0700144 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400145 s->destroyed_ports++;
Craig Tillera82950e2015-09-22 12:33:20 -0700146 if (s->destroyed_ports == s->nports) {
147 gpr_mu_unlock(&s->mu);
148 finish_shutdown(exec_ctx, s);
149 } else {
150 gpr_mu_unlock(&s->mu);
151 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400152}
153
Robbie Shadea4e21a12015-07-10 14:16:31 -0400154/* called when all listening endpoints have been shutdown, so no further
155 events will be received on them - at this point it's safe to destroy
156 things */
Craig Tillera82950e2015-09-22 12:33:20 -0700157static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400158 size_t i;
159
160 /* delete ALL the things */
Craig Tillera82950e2015-09-22 12:33:20 -0700161 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400162
Craig Tillera82950e2015-09-22 12:33:20 -0700163 if (!s->shutdown) {
164 gpr_mu_unlock(&s->mu);
165 return;
166 }
Craig Tiller45724b32015-09-22 10:42:19 -0700167
Craig Tillera82950e2015-09-22 12:33:20 -0700168 if (s->nports) {
169 for (i = 0; i < s->nports; i++) {
170 server_port *sp = &s->ports[i];
ahedbergfcbcbff2016-03-22 13:23:47 -0400171 grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr);
Craig Tillera82950e2015-09-22 12:33:20 -0700172 sp->destroyed_closure.cb = destroyed_port;
173 sp->destroyed_closure.cb_arg = s;
yang-g5d850372015-12-01 10:32:28 -0800174 grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
Craig Tillera82950e2015-09-22 12:33:20 -0700175 "udp_listener_shutdown");
Craig Tiller45724b32015-09-22 10:42:19 -0700176 }
Craig Tillera82950e2015-09-22 12:33:20 -0700177 gpr_mu_unlock(&s->mu);
178 } else {
179 gpr_mu_unlock(&s->mu);
180 finish_shutdown(exec_ctx, s);
181 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400182}
183
Craig Tillera82950e2015-09-22 12:33:20 -0700184void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
185 grpc_closure *on_done) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400186 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700187 gpr_mu_lock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400188
Craig Tillera82950e2015-09-22 12:33:20 -0700189 GPR_ASSERT(!s->shutdown);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400190 s->shutdown = 1;
191
Craig Tillerd1bec032015-09-18 17:29:00 -0700192 s->shutdown_complete = on_done;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400193
194 /* shutdown all fd's */
Craig Tillera82950e2015-09-22 12:33:20 -0700195 if (s->active_ports) {
196 for (i = 0; i < s->nports; i++) {
197 grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400198 }
Craig Tillera82950e2015-09-22 12:33:20 -0700199 gpr_mu_unlock(&s->mu);
200 } else {
201 gpr_mu_unlock(&s->mu);
202 deactivated_all_ports(exec_ctx, s);
203 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400204}
205
206/* Prepare a recently-created socket for listening. */
Craig Tillera82950e2015-09-22 12:33:20 -0700207static int prepare_socket(int fd, const struct sockaddr *addr,
208 size_t addr_len) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400209 struct sockaddr_storage sockname_temp;
210 socklen_t sockname_len;
211 int get_local_ip;
212 int rc;
213
Craig Tillera82950e2015-09-22 12:33:20 -0700214 if (fd < 0) {
215 goto error;
216 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400217
Craig Tillera82950e2015-09-22 12:33:20 -0700218 if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) {
219 gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
220 strerror(errno));
221 }
Robbie Shade6f03dff2015-09-01 10:35:39 -0400222
Robbie Shadea4e21a12015-07-10 14:16:31 -0400223 get_local_ip = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700224 rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
225 sizeof(get_local_ip));
226 if (rc == 0 && addr->sa_family == AF_INET6) {
Jorge Canizales7069da22015-09-29 11:29:42 -0700227#if !defined(__APPLE__)
Craig Tillera82950e2015-09-22 12:33:20 -0700228 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
229 sizeof(get_local_ip));
murgatroid99049e1df2015-08-24 16:27:21 -0700230#endif
Craig Tillera82950e2015-09-22 12:33:20 -0700231 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400232
Craig Tillera82950e2015-09-22 12:33:20 -0700233 GPR_ASSERT(addr_len < ~(socklen_t)0);
234 if (bind(fd, addr, (socklen_t)addr_len) < 0) {
235 char *addr_str;
236 grpc_sockaddr_to_string(&addr_str, addr, 0);
237 gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
238 gpr_free(addr_str);
239 goto error;
240 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400241
Craig Tillera82950e2015-09-22 12:33:20 -0700242 sockname_len = sizeof(sockname_temp);
243 if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
244 goto error;
245 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400246
Craig Tillera82950e2015-09-22 12:33:20 -0700247 return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400248
249error:
Craig Tillera82950e2015-09-22 12:33:20 -0700250 if (fd >= 0) {
251 close(fd);
252 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400253 return -1;
254}
255
256/* event manager callback when reads are ready */
Bogdan Drutuf89fdf32016-02-16 14:38:38 -0800257static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400258 server_port *sp = arg;
259
Bogdan Drutuf89fdf32016-02-16 14:38:38 -0800260 if (!success) {
Craig Tillera82950e2015-09-22 12:33:20 -0700261 gpr_mu_lock(&sp->server->mu);
262 if (0 == --sp->server->active_ports) {
263 gpr_mu_unlock(&sp->server->mu);
264 deactivated_all_ports(exec_ctx, sp->server);
265 } else {
266 gpr_mu_unlock(&sp->server->mu);
Robbie Shadef2eb48a2015-08-04 19:19:36 -0400267 }
Craig Tillera82950e2015-09-22 12:33:20 -0700268 return;
269 }
Robbie Shadef2eb48a2015-08-04 19:19:36 -0400270
Robbie Shadea4e21a12015-07-10 14:16:31 -0400271 /* Tell the registered callback that data is available to read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700272 GPR_ASSERT(sp->read_cb);
Robbie Shadec6787b22015-10-07 10:13:53 -0400273 sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400274
275 /* Re-arm the notification event so we get another chance to read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700276 grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400277}
278
Craig Tillera82950e2015-09-22 12:33:20 -0700279static int add_socket_to_server(grpc_udp_server *s, int fd,
280 const struct sockaddr *addr, size_t addr_len,
281 grpc_udp_server_read_cb read_cb) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400282 server_port *sp;
283 int port;
284 char *addr_str;
285 char *name;
286
Craig Tillera82950e2015-09-22 12:33:20 -0700287 port = prepare_socket(fd, addr, addr_len);
288 if (port >= 0) {
289 grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
290 gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
Craig Tiller7db24e02015-09-24 23:44:07 -0700291 gpr_free(addr_str);
Craig Tillera82950e2015-09-22 12:33:20 -0700292 gpr_mu_lock(&s->mu);
293 /* append it to the list under a lock */
294 if (s->nports == s->port_capacity) {
295 s->port_capacity *= 2;
296 s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400297 }
Craig Tillera82950e2015-09-22 12:33:20 -0700298 sp = &s->ports[s->nports++];
299 sp->server = s;
300 sp->fd = fd;
301 sp->emfd = grpc_fd_create(fd, name);
302 memcpy(sp->addr.untyped, addr, addr_len);
303 sp->addr_len = addr_len;
304 sp->read_cb = read_cb;
305 GPR_ASSERT(sp->emfd);
306 gpr_mu_unlock(&s->mu);
Craig Tiller7db24e02015-09-24 23:44:07 -0700307 gpr_free(name);
Craig Tillera82950e2015-09-22 12:33:20 -0700308 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400309
310 return port;
311}
312
Craig Tillera82950e2015-09-22 12:33:20 -0700313int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
314 size_t addr_len, grpc_udp_server_read_cb read_cb) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400315 int allocated_port1 = -1;
316 int allocated_port2 = -1;
317 unsigned i;
318 int fd;
319 grpc_dualstack_mode dsmode;
320 struct sockaddr_in6 addr6_v4mapped;
321 struct sockaddr_in wild4;
322 struct sockaddr_in6 wild6;
323 struct sockaddr_in addr4_copy;
324 struct sockaddr *allocated_addr = NULL;
325 struct sockaddr_storage sockname_temp;
326 socklen_t sockname_len;
327 int port;
328
ahedbergfcbcbff2016-03-22 13:23:47 -0400329 grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400330
331 /* Check if this is a wildcard port, and if so, try to keep the port the same
332 as some previously created listener. */
Craig Tillera82950e2015-09-22 12:33:20 -0700333 if (grpc_sockaddr_get_port(addr) == 0) {
334 for (i = 0; i < s->nports; i++) {
335 sockname_len = sizeof(sockname_temp);
336 if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
337 &sockname_len)) {
338 port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
339 if (port > 0) {
340 allocated_addr = malloc(addr_len);
341 memcpy(allocated_addr, addr, addr_len);
342 grpc_sockaddr_set_port(allocated_addr, port);
343 addr = allocated_addr;
344 break;
345 }
346 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400347 }
Craig Tillera82950e2015-09-22 12:33:20 -0700348 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400349
Craig Tillera82950e2015-09-22 12:33:20 -0700350 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
351 addr = (const struct sockaddr *)&addr6_v4mapped;
352 addr_len = sizeof(addr6_v4mapped);
353 }
Robbie Shadea4e21a12015-07-10 14:16:31 -0400354
355 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
Craig Tillera82950e2015-09-22 12:33:20 -0700356 if (grpc_sockaddr_is_wildcard(addr, &port)) {
357 grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400358
Craig Tillera82950e2015-09-22 12:33:20 -0700359 /* Try listening on IPv6 first. */
360 addr = (struct sockaddr *)&wild6;
361 addr_len = sizeof(wild6);
362 fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
363 allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
364 if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
365 goto done;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400366 }
367
Craig Tillera82950e2015-09-22 12:33:20 -0700368 /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
369 if (port == 0 && allocated_port1 > 0) {
370 grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400371 }
Craig Tillera82950e2015-09-22 12:33:20 -0700372 addr = (struct sockaddr *)&wild4;
373 addr_len = sizeof(wild4);
374 }
375
376 fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
377 if (fd < 0) {
378 gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
379 }
380 if (dsmode == GRPC_DSMODE_IPV4 &&
381 grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
382 addr = (struct sockaddr *)&addr4_copy;
383 addr_len = sizeof(addr4_copy);
384 }
385 allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400386
387done:
Craig Tillera82950e2015-09-22 12:33:20 -0700388 gpr_free(allocated_addr);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400389 return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
390}
391
Vijay Pai7b080ba2015-09-29 22:22:36 +0000392int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) {
393 return (port_index < s->nports) ? s->ports[port_index].fd : -1;
Robbie Shadea4e21a12015-07-10 14:16:31 -0400394}
395
Craig Tillera82950e2015-09-22 12:33:20 -0700396void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
Robbie Shade147fe702015-09-25 15:04:40 -0400397 grpc_pollset **pollsets, size_t pollset_count,
Robbie Shade109a8dc2015-09-25 15:18:49 -0400398 grpc_server *server) {
Robbie Shadea4e21a12015-07-10 14:16:31 -0400399 size_t i, j;
Craig Tillera82950e2015-09-22 12:33:20 -0700400 gpr_mu_lock(&s->mu);
401 GPR_ASSERT(s->active_ports == 0);
Robbie Shade1cef6dc2015-07-15 14:16:48 -0400402 s->pollsets = pollsets;
Robbie Shade109a8dc2015-09-25 15:18:49 -0400403 s->grpc_server = server;
Craig Tillera82950e2015-09-22 12:33:20 -0700404 for (i = 0; i < s->nports; i++) {
405 for (j = 0; j < pollset_count; j++) {
406 grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400407 }
Craig Tillera82950e2015-09-22 12:33:20 -0700408 s->ports[i].read_closure.cb = on_read;
409 s->ports[i].read_closure.cb_arg = &s->ports[i];
410 grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
411 &s->ports[i].read_closure);
412 s->active_ports++;
413 }
414 gpr_mu_unlock(&s->mu);
Robbie Shadea4e21a12015-07-10 14:16:31 -0400415}
416
Robbie Shadea4e21a12015-07-10 14:16:31 -0400417#endif
Craig Tiller2908a762015-12-10 14:48:24 -0800418#endif