1 /*
2 * binding.c - server to port binding implementation
3 *
4 * Copyright (C) 2011-2013 Thien-Thi Nguyen
5 * Copyright (C) 2001, 2002 Stefan Jahn <stefan@lkcc.org>
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this package. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include "timidity.h"
25 #include <string.h>
26 #include <sys/types.h>
27
28 #ifndef __MINGW32__
29 # include <sys/socket.h>
30 #endif
31 #include "networking-headers.h"
32 #include "libserveez/alloc.h"
33 #include "libserveez/util.h"
34 #include "libserveez/socket.h"
35 #include "libserveez/core.h"
36 #include "libserveez/server.h"
37 #include "libserveez/server-core.h"
38 #include "libserveez/portcfg.h"
39 #include "libserveez/server-socket.h"
40 #include "libserveez/binding.h"
41 #include "libserveez/soprop.h"
42
43 /*
44 * Hash table to map a socket to an array of bindings.
45 */
46 static svz_hash_t *all_ears;
47
48 static void *
all_ears_x(const svz_socket_t * sock,svz_array_t * bindings)49 all_ears_x (const svz_socket_t *sock, svz_array_t *bindings)
50 {
51 return svz_soprop_put (all_ears, sock, bindings);
52 }
53
54 svz_array_t *
svz_sock_bindings(const svz_socket_t * sock)55 svz_sock_bindings (const svz_socket_t *sock)
56 {
57 return svz_soprop_get (all_ears, sock);
58 }
59
60 static int
portcfg_exactly_equal(svz_portcfg_t * a,svz_portcfg_t * b)61 portcfg_exactly_equal (svz_portcfg_t *a, svz_portcfg_t *b)
62 {
63 return SVZ_PORTCFG_EQUAL
64 == svz_portcfg_equal (a, b);
65 }
66
67 static int
portcfg_matching_or_equal(svz_portcfg_t * a,svz_portcfg_t * b)68 portcfg_matching_or_equal (svz_portcfg_t *a, svz_portcfg_t *b)
69 {
70 return (SVZ_PORTCFG_EQUAL | SVZ_PORTCFG_MATCH)
71 & svz_portcfg_equal (a, b);
72 }
73
74 /*
75 * Searches through the bindings of the given listening server socket
76 * structure @var{sock} and checks whether the server instance @var{server}
77 * is bound to this socket structure. The function returns these binding and
78 * returns @code{NULL} otherwise. The caller is responsible for freeing
79 * the returned array.
80 */
81 static svz_array_t *
from_server(svz_socket_t * sock,svz_server_t * server)82 from_server (svz_socket_t *sock, svz_server_t *server)
83 {
84 svz_array_t *bindings = svz_array_create (1, NULL);
85 svz_binding_t *binding;
86 size_t i;
87
88 svz_array_foreach (svz_sock_bindings (sock), binding, i)
89 if (binding->server == server)
90 svz_array_add (bindings, binding);
91 return svz_array_destroy_zero (bindings);
92 }
93
94 /**
95 * Return an array of port configurations to which the server instance
96 * @var{server} is currently bound to, or @code{NULL} if there is no such
97 * binding. Caller should @code{svz_array_destroy} the returned array
98 * when done.
99 */
100 svz_array_t *
svz_server_portcfgs(svz_server_t * server)101 svz_server_portcfgs (svz_server_t *server)
102 {
103 svz_array_t *ports = svz_array_create (1, NULL);
104 svz_binding_t *binding;
105 svz_array_t *bindings;
106 svz_socket_t *sock;
107 size_t i;
108
109 svz_sock_foreach_listener (sock)
110 if ((bindings = from_server (sock, server)) != NULL)
111 {
112 svz_array_foreach (bindings, binding, i)
113 svz_array_add (ports, binding->port);
114 svz_array_destroy (bindings);
115 }
116 return svz_array_destroy_zero (ports);
117 }
118
119 /**
120 * Return an array of listening socket structures to which the server
121 * instance @var{server} is currently bound to, or @code{NULL} if there
122 * is no such binding. Caller should @code{svz_array_destroy} the
123 * returned array when done.
124 */
125 svz_array_t *
svz_server_listeners(svz_server_t * server)126 svz_server_listeners (svz_server_t *server)
127 {
128 svz_array_t *listeners = svz_array_create (1, NULL);
129 svz_socket_t *sock;
130
131 svz_sock_foreach_listener (sock)
132 if (svz_binding_contains_server (sock, server))
133 svz_array_add (listeners, sock);
134 return svz_array_destroy_zero (listeners);
135 }
136
137 /*
138 * Returns a socket structure representing a listening server socket with
139 * the port configuration @var{port}. If there is no such socket with this
140 * kind of port configuration yet then @code{NULL} is returned.
141 */
142 static svz_socket_t *
socket_with_portcfg(svz_portcfg_t * port)143 socket_with_portcfg (svz_portcfg_t *port)
144 {
145 svz_socket_t *sock;
146
147 svz_sock_foreach_listener (sock)
148 if (portcfg_matching_or_equal (sock->port, port))
149 return sock;
150 return NULL;
151 }
152
153 /*
154 * This functions goes through the list of listening server socket
155 * structures and returns an array of matching socket structures for the
156 * given port configuration @var{port}. The caller is responsible for
157 * freeing the array by running @code{svz_array_destroy}. If there are
158 * no such listening server socket structures @code{NULL} is returned.
159 */
160 static svz_array_t *
sockets_with_portcfg(svz_portcfg_t * port)161 sockets_with_portcfg (svz_portcfg_t *port)
162 {
163 svz_array_t *listeners = svz_array_create (1, NULL);
164 svz_socket_t *sock;
165
166 svz_sock_foreach_listener (sock)
167 if (portcfg_matching_or_equal (sock->port, port))
168 svz_array_add (listeners, sock);
169 return svz_array_destroy_zero (listeners);
170 }
171
172 /*
173 * Creates and returns a listening server socket structure. The kind of
174 * listener which gets created depends on the given port configuration
175 * @var{port} which must be a duplicated copy of one out of the list of
176 * known port configurations. On success the function enqueues the
177 * returned socket structure and assigns the port configuration. Initially
178 * there are no bindings. In case of an error the given port configuration
179 * is freed and @code{NULL} is returned.
180 */
181 static svz_socket_t *
make_listener_socket(svz_portcfg_t * port)182 make_listener_socket (svz_portcfg_t *port)
183 {
184 svz_socket_t *sock;
185
186 /* Try creating a server socket. */
187 if ((sock = svz_server_create (port)) != NULL)
188 {
189 /* Enqueue the server socket and put the port configuration into
190 the socket structure. */
191 svz_sock_enqueue (sock);
192 sock->port = port;
193 return sock;
194 }
195
196 /* Could not create this port configuration listener. */
197 svz_portcfg_free (port);
198 return NULL;
199 }
200
201 /*
202 * Creates a bind structure. The binding contains the given server instance
203 * @var{server} and the port configuration @var{port}. The caller is
204 * responsible for freeing the returned pointer.
205 */
206 static svz_binding_t *
make_binding(svz_server_t * server,svz_portcfg_t * port)207 make_binding (svz_server_t *server, svz_portcfg_t *port)
208 {
209 svz_binding_t *binding = svz_malloc (sizeof (svz_binding_t));
210 binding->server = server;
211 binding->port = port;
212 return binding;
213 }
214
215 /*
216 * Goes through the listening server sockets @var{sock} bindings and checks
217 * whether it contains the given binding consisting of @var{server} and
218 * @var{port}. If there is no such binding yet @code{NULL} is returned
219 * otherwise the appropriate binding.
220 */
221 static svz_binding_t *
find_binding(svz_socket_t * sock,svz_server_t * server,svz_portcfg_t * port)222 find_binding (svz_socket_t *sock, svz_server_t *server,
223 svz_portcfg_t *port)
224 {
225 svz_binding_t *binding;
226 size_t i;
227
228 svz_array_foreach (svz_sock_bindings (sock), binding, i)
229 if (binding->server == server)
230 if (portcfg_exactly_equal (binding->port, port))
231 return binding;
232 return NULL;
233 }
234
235 /*
236 * This function attaches the given server instance @var{server} to the
237 * listening socket structure @var{sock}. It returns zero on success and
238 * non-zero if the server is already bound to the socket.
239 */
240 static int
add_server(svz_socket_t * sock,svz_server_t * server,svz_portcfg_t * port)241 add_server (svz_socket_t *sock, svz_server_t *server, svz_portcfg_t *port)
242 {
243 svz_binding_t *binding = make_binding (server, port);
244 svz_array_t *bindings = svz_sock_bindings (sock);
245
246 /* Create server array if necessary. */
247 if (bindings == NULL)
248 {
249 bindings = svz_array_create (1, (svz_free_func_t) svz_binding_destroy);
250 svz_array_add (bindings, binding);
251 all_ears_x (sock, bindings);
252 return 0;
253 }
254 /* Attach a server/port binding to a single listener only once. */
255 else if (find_binding (sock, server, port) == NULL)
256 {
257 /* Extend the server array. */
258 svz_array_add (bindings, binding);
259 return 0;
260 }
261 /* Binding already done. */
262 svz_log (SVZ_LOG_WARNING, "skipped duplicate binding of `%s'\n", server->name);
263 svz_binding_destroy (binding);
264 return -1;
265 }
266
267 /*
268 * Destroys the given binding @var{binding}. This includes the explicit
269 * destruction of the port configuration. If @var{binding} is @code{NULL}
270 * no operation is performed.
271 */
272 void
svz_binding_destroy(svz_binding_t * binding)273 svz_binding_destroy (svz_binding_t *binding)
274 {
275 if (binding != NULL)
276 {
277 svz_portcfg_free (binding->port);
278 svz_free (binding);
279 }
280 }
281
282 /*
283 * This function checks whether the server instance binding @var{binding}
284 * is part of one of the bindings in the array @var{bindings} and returns
285 * non-zero if so. Otherwise zero is returned.
286 */
287 static int
bindings_contain(svz_array_t * bindings,svz_binding_t * binding)288 bindings_contain (svz_array_t *bindings, svz_binding_t *binding)
289 {
290 svz_binding_t *search;
291 size_t i;
292
293 svz_array_foreach (bindings, search, i)
294 if (search->server == binding->server)
295 if (portcfg_exactly_equal (search->port, binding->port))
296 return 1;
297 return 0;
298 }
299
300 /*
301 * Returns the binding array of the listening server socket structure
302 * @var{sock} or @code{NULL} if there are no such bindings.
303 */
304 static svz_array_t *
sock_bindings(svz_socket_t * sock)305 sock_bindings (svz_socket_t *sock)
306 {
307 if (sock && sock->flags & SVZ_SOFLG_LISTENING && sock->port != NULL)
308 return svz_sock_bindings (sock);
309 return NULL;
310 }
311
312 /*
313 * Make @var{sock} have no bindings.
314 */
315 void
svz_sock_bindings_set(svz_socket_t * sock,svz_socket_t * from)316 svz_sock_bindings_set (svz_socket_t *sock, svz_socket_t *from)
317 {
318 svz_array_t *bindings = from
319 ? svz_sock_bindings (from)
320 : NULL;
321
322 all_ears_x (sock, bindings);
323 }
324
325 /*
326 * Removes the server instance @var{server} from the listening socket
327 * structure @var{sock} and returns the remaining number of servers bound
328 * to the socket structure.
329 */
330 size_t
svz_sock_bindings_zonk_server(svz_socket_t * sock,svz_server_t * server)331 svz_sock_bindings_zonk_server (svz_socket_t *sock, svz_server_t *server)
332 {
333 svz_array_t *bindings = svz_sock_bindings (sock);
334 svz_binding_t *binding;
335 size_t i;
336
337 svz_array_foreach (bindings, binding, i)
338 if (binding->server == server)
339 {
340 svz_binding_destroy (binding);
341 svz_array_del (bindings, i);
342 i--;
343 }
344 return svz_array_size (bindings);
345 }
346
347 /*
348 * This function adds the bindings stored in the listening server socket
349 * structure @var{sock} to the binding array @var{bindings} and returns the
350 * resulting array. If @var{bindings} is @code{NULL} a new array is created.
351 * If the socket structure @var{sock} is not a listening server socket
352 * structure no operation is performed.
353 */
354 static svz_array_t *
adjoin(svz_array_t * bindings,svz_socket_t * sock)355 adjoin (svz_array_t *bindings, svz_socket_t *sock)
356 {
357 svz_array_t *old = sock_bindings (sock);
358 svz_binding_t *binding;
359 size_t i;
360
361 /* Is this a listening server socket? */
362 if (!((sock->flags & SVZ_SOFLG_LISTENING) && (sock->port != NULL)))
363 return bindings;
364
365 /* Create an array if necessary. */
366 if (bindings == NULL)
367 bindings = svz_array_create (1, (svz_free_func_t) svz_binding_destroy);
368
369 /* Join both arrays. */
370 svz_array_foreach (old, binding, i)
371 if (!bindings_contain (bindings, binding))
372 {
373 svz_server_t *server = binding->server;
374 svz_portcfg_t *port = svz_portcfg_dup (binding->port);
375 svz_array_add (bindings, make_binding (server, port));
376 }
377
378 /* Destroy the old bindings. */
379 svz_array_destroy (old);
380
381 /* Invalidate the binding array. */
382 svz_sock_bindings_set (sock, NULL);
383 return bindings;
384 }
385
386 /**
387 * Bind the server instance @var{server} to the port configuration
388 * @var{port} if possible. Return non-zero on errors, otherwise zero.
389 * It might occur that a single server is bound to more than one network
390 * port if, e.g., the TCP/IP address is specified by @samp{*} (asterisk)
391 * since this gets expanded to the known list of interfaces.
392 */
393 int
svz_server_bind(svz_server_t * server,svz_portcfg_t * port)394 svz_server_bind (svz_server_t *server, svz_portcfg_t *port)
395 {
396 svz_array_t *ports;
397 svz_socket_t *sock;
398 svz_portcfg_t *copy, *portcfg;
399 size_t n, i;
400
401 /* First expand the given port configuration. */
402 ports = svz_portcfg_expand (port);
403 svz_array_foreach (ports, copy, n)
404 {
405 /* Prepare port configuration. */
406 svz_portcfg_prepare (copy);
407
408 /* Find appropriate socket structure for this port configuration. */
409 if ((sock = socket_with_portcfg (copy)) == NULL)
410 {
411 if ((sock = make_listener_socket (copy)) != NULL)
412 add_server (sock, server, copy);
413 }
414 /* Port configuration already exists. */
415 else
416 {
417 /* Is this a more general network port? Is the new port an
418 INADDR_ANY binding and the picked one not? */
419 portcfg = sock->port;
420 if ((copy->flags & PORTCFG_FLAG_ANY) &&
421 !(portcfg->flags & PORTCFG_FLAG_ANY))
422 {
423 svz_array_t *sockets = sockets_with_portcfg (port);
424 svz_array_t *bindings = NULL;
425 svz_socket_t *xsock;
426
427 /* Join the bindings of the previous listeners and destroy
428 these at once. */
429 svz_log (SVZ_LOG_NOTICE, "destroying previous bindings\n");
430 svz_array_foreach (sockets, xsock, i)
431 {
432 bindings = adjoin (bindings, xsock);
433 svz_sock_shutdown (xsock);
434 }
435 svz_array_destroy (sockets);
436
437 /* Create a fresh listener. */
438 if ((sock = make_listener_socket (copy)) != NULL)
439 {
440 all_ears_x (sock, bindings);
441 add_server (sock, server, copy);
442 }
443 else
444 {
445 svz_array_destroy (bindings);
446 }
447 }
448 /* No. This is either a specific network interface or both have
449 an INADDR_ANY binding. */
450 else
451 add_server (sock, server, copy);
452 }
453 }
454
455 /* Now we can destroy the expanded port configuration array. */
456 svz_array_destroy (ports);
457 return 0;
458 }
459
460 /**
461 * Checks whether the server instance @var{server} is
462 * bound to the server socket structure @var{sock}.
463 * Return one if so, otherwise zero.
464 */
465 int
svz_binding_contains_server(svz_socket_t * sock,svz_server_t * server)466 svz_binding_contains_server (svz_socket_t *sock, svz_server_t *server)
467 {
468 svz_binding_t *binding;
469 size_t i;
470
471 svz_array_foreach (svz_sock_bindings (sock), binding, i)
472 if (binding->server == server)
473 return 1;
474 return 0;
475 }
476
477 /**
478 * Return the array of server instances bound to the listening
479 * @var{sock}, or @code{NULL} if there are no bindings. Caller
480 * should @code{svz_array_destroy} the returned array when done.
481 */
482 svz_array_t *
svz_sock_servers(svz_socket_t * sock)483 svz_sock_servers (svz_socket_t *sock)
484 {
485 svz_array_t *servers = svz_array_create (1, NULL);
486 svz_array_t *bindings = sock_bindings (sock);
487 svz_binding_t *binding;
488 size_t i;
489
490 svz_array_foreach (bindings, binding, i)
491 svz_array_add (servers, binding->server);
492 return svz_array_destroy_zero (servers);
493 }
494
495 /*
496 * This is the accept filter for the listening server socket structures
497 * @var{sock} with pipe port configurations. It returns all bindings. The
498 * caller is responsible for freeing the returned array by running
499 * @code{svz_array_destroy}.
500 */
501 static svz_array_t *
filter_pipe(svz_socket_t * sock)502 filter_pipe (svz_socket_t *sock)
503 {
504 svz_array_t *filter = svz_array_create (1, NULL);
505 svz_array_t *bindings = svz_sock_bindings (sock);
506 svz_binding_t *binding;
507 size_t i;
508
509 svz_array_foreach (bindings, binding, i)
510 svz_array_add (filter, binding);
511 return svz_array_destroy_zero (filter);
512 }
513
514 /*
515 * This is the accept filter for the listening server socket structures
516 * @var{sock} with network port configurations. It returns the bindings
517 * allowed to be accepted. The caller is responsible for freeing the returned
518 * array by running @code{svz_array_destroy}. Which of the bindings are
519 * allowed depends on the network interface address @var{addr} and the
520 * network port @var{port}.
521 */
522 static svz_array_t *
filter_net(svz_socket_t * sock,in_addr_t addr,in_port_t port)523 filter_net (svz_socket_t *sock, in_addr_t addr, in_port_t port)
524 {
525 svz_array_t *filter = svz_array_create (1, NULL);
526 svz_array_t *bindings = svz_sock_bindings (sock);
527 struct sockaddr_in *portaddr;
528 svz_binding_t *binding;
529 size_t i;
530
531 /* Go through all bindings. */
532 svz_array_foreach (bindings, binding, i)
533 {
534 portaddr = svz_portcfg_addr (binding->port);
535 #if DEVEL
536 printf ("portaddr: %s == ", svz_inet_ntoa (portaddr->sin_addr.s_addr));
537 printf ("%s\n", svz_inet_ntoa (addr));
538 printf ("port: %u == %u\n", ntohs (portaddr->sin_port), ntohs (port));
539 #endif
540 if (portaddr->sin_addr.s_addr == addr ||
541 binding->port->flags & (PORTCFG_FLAG_ANY | PORTCFG_FLAG_DEVICE))
542 {
543 #if DEVEL
544 printf ("addr ok\n");
545 #endif
546 if (binding->port->proto & (SVZ_PROTO_RAW | SVZ_PROTO_ICMP) ||
547 portaddr->sin_port == port)
548 {
549 #if DEVEL
550 printf ("port ok\n");
551 #endif
552 svz_array_add (filter, binding);
553 }
554 }
555 }
556 return svz_array_destroy_zero (filter);
557 }
558
559 /*
560 * This function returns the local network address and port for the given
561 * client socket structure @var{sock}. It returns non-zero if there no
562 * connection established.
563 */
564 static int
local_info(svz_socket_t * sock,in_addr_t * addr,in_port_t * port)565 local_info (svz_socket_t *sock, in_addr_t *addr, in_port_t *port)
566 {
567 struct sockaddr_in s;
568 socklen_t size = sizeof (s);
569
570 if (!getsockname (sock->sock_desc, (struct sockaddr *) &s, &size))
571 {
572 if (addr)
573 *addr = s.sin_addr.s_addr;
574 if (port)
575 *port = s.sin_port;
576 return 0;
577 }
578 return -1;
579 }
580
581 /*
582 * This is the main filter routine running either
583 * @code{filter_net} or @code{filter_pipe}
584 * depending on the type of port configuration the given socket @var{sock}
585 * contains.
586 */
587 svz_array_t *
svz_binding_filter(svz_socket_t * sock)588 svz_binding_filter (svz_socket_t *sock)
589 {
590 in_addr_t addr;
591 in_port_t port;
592
593 if (sock->proto & SVZ_PROTO_PIPE)
594 return filter_pipe (sock);
595 if (local_info (sock, &addr, &port))
596 return NULL;
597 return filter_net (sock, addr, port);
598 }
599
600 /**
601 * Format a space-separated list of current port configuration
602 * bindings for @var{server} into @var{buf}, which has @var{size}
603 * bytes. The string is guaranteed to be nul-terminated. Return the
604 * length (at most @code{@var{size} - 1}) of the formatted string.
605 */
606 size_t
svz_pp_server_bindings(char * buf,size_t size,svz_server_t * server)607 svz_pp_server_bindings (char *buf, size_t size, svz_server_t *server)
608 {
609 svz_socket_t *sock;
610 svz_array_t *bindings;
611 svz_binding_t *binding;
612 size_t i;
613 int lose = 0;
614 char *w = buf;
615 int firstp = 1;
616
617 *w = '\0';
618
619 /* Go through the list of socket structures. */
620 svz_sock_foreach_listener (sock)
621 {
622 /* The server in the array of servers? */
623 if ((bindings = from_server (sock, server)) != NULL)
624 {
625 /* Yes. Get port configurations. */
626 svz_array_foreach (bindings, binding, i)
627 {
628 char pretty[128];
629 size_t len = svz_pp_portcfg (pretty, 128, binding->port);
630
631 if (size <= len + !firstp)
632 {
633 lose = 1;
634 break;
635 }
636 if (!firstp)
637 {
638 *w++ = ' ';
639 size--;
640 }
641 memcpy (w, pretty, len);
642 w += len;
643 size -= len;
644 firstp = 0;
645 }
646 svz_array_destroy (bindings);
647 *w = '\0';
648 if (lose)
649 goto out;
650 }
651 }
652
653 out:
654 return w - buf;
655 }
656
657
658 void
zonk_sock_ears(const svz_socket_t * sock)659 zonk_sock_ears (const svz_socket_t *sock)
660 {
661 if (sock->flags & SVZ_SOFLG_LISTENING)
662 {
663 svz_array_t *bindings = all_ears_x (sock, NULL);
664
665 if (bindings != NULL)
666 svz_array_destroy (bindings);
667 }
668 }
669
670 void
svz__bindings_updn(int direction)671 svz__bindings_updn (int direction)
672 {
673 if (direction)
674 {
675 /* We don't specify DESTROY to ‘svz_soprop_create’ because the value
676 (bindings array) is shared by the listener socket w/ those derived
677 from it. Unsharing is implemented by discarding the reference,
678 w/o destroying the bindings. Bindings destruction happens only
679 when the listener socket is destroyed (see ‘zonk_sock_ears’). */
680 all_ears = svz_soprop_create (1, NULL);
681 svz_sock_prefree (1, zonk_sock_ears);
682 }
683 else
684 {
685 svz_sock_prefree (0, zonk_sock_ears);
686 svz_soprop_destroy (all_ears);
687 all_ears = NULL;
688 }
689 }
690