1 | /* _hurd_socket_server - Find the server for a socket domain. |
2 | Copyright (C) 1991-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <hurd.h> |
20 | #include <sys/socket.h> |
21 | #include <stdlib.h> |
22 | #include <string.h> |
23 | #include <hurd/paths.h> |
24 | #include <stdio.h> |
25 | #include <_itoa.h> |
26 | #include <lock-intern.h> /* For `struct mutex'. */ |
27 | #include "hurdmalloc.h" /* XXX */ |
28 | #include "set-hooks.h" |
29 | |
30 | static struct mutex lock; |
31 | |
32 | static file_t *servers; |
33 | static int max_domain = -1; |
34 | |
35 | /* Return a port to the socket server for DOMAIN. |
36 | Socket servers translate nodes in the directory _SERVERS_SOCKET |
37 | (canonically /servers/socket). These naming point nodes are named |
38 | by the simplest decimal representation of the socket domain number, |
39 | for example "/servers/socket/3". |
40 | |
41 | Socket servers are assumed not to change very often. |
42 | The library keeps all the server socket ports it has ever looked up, |
43 | and does not look them up in /servers/socket more than once. */ |
44 | |
45 | socket_t |
46 | _hurd_socket_server (int domain, int dead) |
47 | { |
48 | socket_t server; |
49 | |
50 | if (domain < 0) |
51 | { |
52 | errno = EAFNOSUPPORT; |
53 | return MACH_PORT_NULL; |
54 | } |
55 | |
56 | retry: |
57 | HURD_CRITICAL_BEGIN; |
58 | __mutex_lock (&lock); |
59 | |
60 | if (domain > max_domain) |
61 | { |
62 | error_t save = errno; |
63 | file_t *new = realloc (servers, (domain + 1) * sizeof (file_t)); |
64 | if (new != NULL) |
65 | { |
66 | do |
67 | new[++max_domain] = MACH_PORT_NULL; |
68 | while (max_domain < domain); |
69 | servers = new; |
70 | } |
71 | else |
72 | /* No space to cache the port; we will just fetch it anew below. */ |
73 | errno = save; |
74 | } |
75 | |
76 | if (dead && domain <= max_domain) |
77 | { |
78 | /* The user says the port we returned earlier (now in SERVERS[DOMAIN]) |
79 | was dead. Clear the cache and fetch a new one below. */ |
80 | __mach_port_deallocate (__mach_task_self (), servers[domain]); |
81 | servers[domain] = MACH_PORT_NULL; |
82 | } |
83 | |
84 | if (domain > max_domain || servers[domain] == MACH_PORT_NULL) |
85 | { |
86 | char name[sizeof (_SERVERS_SOCKET) + 100]; |
87 | char *np = &name[sizeof (name)]; |
88 | *--np = '\0'; |
89 | np = _itoa (domain, np, 10, 0); |
90 | *--np = '/'; |
91 | np -= sizeof (_SERVERS_SOCKET) - 1; |
92 | memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); |
93 | server = __file_name_lookup (np, 0, 0); |
94 | if (domain <= max_domain) |
95 | servers[domain] = server; |
96 | } |
97 | else |
98 | server = servers[domain]; |
99 | |
100 | if (server == MACH_PORT_NULL && errno == ENOENT) |
101 | /* If the server node is absent, we don't support that protocol. */ |
102 | errno = EAFNOSUPPORT; |
103 | |
104 | __mutex_unlock (&lock); |
105 | HURD_CRITICAL_END; |
106 | if (server == MACH_PORT_NULL && errno == EINTR) |
107 | /* Got a signal while inside an RPC of the critical section, retry again */ |
108 | goto retry; |
109 | |
110 | return server; |
111 | } |
112 | |
113 | static void attribute_used_retain |
114 | init (void) |
115 | { |
116 | int i; |
117 | |
118 | __mutex_init (&lock); |
119 | |
120 | for (i = 0; i < max_domain; ++i) |
121 | servers[i] = MACH_PORT_NULL; |
122 | } |
123 | SET_RELHOOK (_hurd_preinit_hook, init); |
124 | |