2 * Copyright 2009 Oracle. All rights reserved.
4 * This file is part of nfs-utils.
6 * nfs-utils is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * nfs-utils is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
32 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #include <sys/resource.h>
40 #ifdef HAVE_TCP_WRAPPER
41 #include "tcpwrapper.h"
50 * Set up an appropriate bind address, given @port and @nconf.
52 * Returns getaddrinfo(3) results if successful. Caller must
53 * invoke freeaddrinfo(3) on these results.
55 * Otherwise NULL is returned if an error occurs.
58 static struct addrinfo *
59 svc_create_bindaddr(struct netconfig *nconf, const uint16_t port)
61 struct addrinfo *ai = NULL;
62 struct addrinfo hint = {
63 .ai_flags = AI_PASSIVE | AI_NUMERICSERV,
68 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
69 hint.ai_family = AF_INET;
71 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
72 hint.ai_family = AF_INET6;
73 #endif /* IPV6_SUPPORTED */
75 xlog(L_ERROR, "Unrecognized bind address family: %s",
80 if (strcmp(nconf->nc_proto, NC_UDP) == 0)
81 hint.ai_protocol = (int)IPPROTO_UDP;
82 else if (strcmp(nconf->nc_proto, NC_TCP) == 0)
83 hint.ai_protocol = (int)IPPROTO_TCP;
85 xlog(L_ERROR, "Unrecognized bind address protocol: %s",
90 (void)snprintf(buf, sizeof(buf), "%u", port);
91 error = getaddrinfo(NULL, buf, &hint, &ai);
96 xlog(L_ERROR, "Failed to construct bind address: %m");
99 xlog(L_ERROR, "Failed to construct bind address: %s",
100 gai_strerror(error));
108 svc_create_nconf(const char *name, const rpcprog_t program,
109 const rpcvers_t version,
110 void (*dispatch)(struct svc_req *, SVCXPRT *),
111 const uint16_t port, struct netconfig *nconf)
113 struct t_bind bindaddr;
117 ai = svc_create_bindaddr(nconf, port);
121 bindaddr.addr.buf = ai->ai_addr;
122 bindaddr.qlen = SOMAXCONN;
124 xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0);
127 xlog(D_GENERAL, "Failed to create listener xprt "
128 "(%s, %u, %s)", name, version, nconf->nc_netid);
132 if (!svc_reg(xprt, program, version, dispatch, nconf)) {
133 /* svc_reg(3) destroys @xprt in this case */
134 xlog(D_GENERAL, "Failed to register (%s, %u, %s)",
135 name, version, nconf->nc_netid);
143 * nfs_svc_create - start up RPC svc listeners
144 * @name: C string containing name of new service
145 * @program: RPC program number to register
146 * @version: RPC version number to register
147 * @dispatch: address of function that handles incoming RPC requests
148 * @port: if not zero, transport listens on this port
150 * Sets up network transports for receiving RPC requests, and starts
151 * the RPC dispatcher. Returns the number of started network transports.
154 nfs_svc_create(__attribute__((unused)) char *name,
155 const rpcprog_t program, const rpcvers_t version,
156 void (*dispatch)(struct svc_req *, SVCXPRT *),
159 const struct sigaction create_sigaction = {
160 .sa_handler = SIG_IGN,
162 unsigned int visible, up;
163 struct netconfig *nconf;
167 * Ignore SIGPIPE to avoid exiting sideways when peers
168 * close their TCP connection while we're trying to reply
171 (void)sigaction(SIGPIPE, &create_sigaction, NULL);
173 handlep = setnetconfig();
174 if (handlep == NULL) {
175 xlog(L_ERROR, "Failed to access local netconfig database: %s",
182 while ((nconf = getnetconfig(handlep)) != NULL) {
183 if (!(nconf->nc_flag & NC_VISIBLE))
186 up += svc_create_nconf(name, program, version, dispatch,
191 xlog(L_ERROR, "Failed to find any visible netconfig entries");
193 if (endnetconfig(handlep) == -1)
194 xlog(L_ERROR, "Failed to close local netconfig database: %s",
201 * nfs_svc_unregister - remove service registrations from local rpcbind database
202 * @program: RPC program number to unregister
203 * @version: RPC version number to unregister
205 * Removes all registrations for [ @program, @version ] .
208 nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version)
210 if (rpcb_unset(program, version, NULL) == FALSE)
211 xlog(D_GENERAL, "Failed to unregister program %lu, version %lu",
212 (unsigned long)program, (unsigned long)version);
215 #else /* !HAVE_LIBTIRPC */
218 * nfs_svc_create - start up RPC svc listeners
219 * @name: C string containing name of new service
220 * @program: RPC program number to register
221 * @version: RPC version number to register
222 * @dispatch: address of function that handles incoming RPC requests
223 * @port: if not zero, transport listens on this port
225 * Sets up network transports for receiving RPC requests, and starts
226 * the RPC dispatcher. Returns the number of started network transports.
229 nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
230 void (*dispatch)(struct svc_req *, SVCXPRT *),
233 rpc_init(name, (int)program, (int)version, dispatch, (int)port);
238 * nfs_svc_unregister - remove service registrations from local rpcbind database
239 * @program: RPC program number to unregister
240 * @version: RPC version number to unregister
242 * Removes all registrations for [ @program, @version ] .
245 nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version)
247 if (pmap_unset((unsigned long)program, (unsigned long)version) == FALSE)
248 xlog(D_GENERAL, "Failed to unregister program %lu, version %lu",
249 (unsigned long)program, (unsigned long)version);
252 #endif /* !HAVE_LIBTIRPC */