1 | /* _hurd_socket_server - Find the server for a socket domain. |
2 | Copyright (C) 1991-2024 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 | return __hurd_fail (EAFNOSUPPORT), MACH_PORT_NULL; |
52 | |
53 | retry: |
54 | HURD_CRITICAL_BEGIN; |
55 | __mutex_lock (&lock); |
56 | |
57 | if (domain > max_domain) |
58 | { |
59 | error_t save = errno; |
60 | file_t *new = realloc (servers, (domain + 1) * sizeof (file_t)); |
61 | if (new != NULL) |
62 | { |
63 | do |
64 | new[++max_domain] = MACH_PORT_NULL; |
65 | while (max_domain < domain); |
66 | servers = new; |
67 | } |
68 | else |
69 | /* No space to cache the port; we will just fetch it anew below. */ |
70 | errno = save; |
71 | } |
72 | |
73 | if (dead && domain <= max_domain) |
74 | { |
75 | /* The user says the port we returned earlier (now in SERVERS[DOMAIN]) |
76 | was dead. Clear the cache and fetch a new one below. */ |
77 | __mach_port_deallocate (__mach_task_self (), servers[domain]); |
78 | servers[domain] = MACH_PORT_NULL; |
79 | } |
80 | |
81 | if (domain > max_domain || servers[domain] == MACH_PORT_NULL) |
82 | { |
83 | char name[sizeof (_SERVERS_SOCKET) + 100]; |
84 | char *np = &name[sizeof (name)]; |
85 | *--np = '\0'; |
86 | np = _itoa (domain, np, 10, 0); |
87 | *--np = '/'; |
88 | np -= sizeof (_SERVERS_SOCKET) - 1; |
89 | memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); |
90 | server = __file_name_lookup (np, 0, 0); |
91 | if (domain <= max_domain) |
92 | servers[domain] = server; |
93 | } |
94 | else |
95 | server = servers[domain]; |
96 | |
97 | if (server == MACH_PORT_NULL && errno == ENOENT) |
98 | /* If the server node is absent, we don't support that protocol. */ |
99 | __hurd_fail (EAFNOSUPPORT); |
100 | |
101 | __mutex_unlock (&lock); |
102 | HURD_CRITICAL_END; |
103 | if (server == MACH_PORT_NULL && errno == EINTR) |
104 | /* Got a signal while inside an RPC of the critical section, retry again */ |
105 | goto retry; |
106 | |
107 | return server; |
108 | } |
109 | |
110 | static void attribute_used_retain |
111 | init (void) |
112 | { |
113 | int i; |
114 | |
115 | __mutex_init (&lock); |
116 | |
117 | for (i = 0; i < max_domain; ++i) |
118 | servers[i] = MACH_PORT_NULL; |
119 | } |
120 | SET_RELHOOK (_hurd_preinit_hook, init); |
121 | |