Pre-2.0 release: Sync with HAMMER 64 - NFS and cross-device link fixes.
[dragonfly.git] / contrib / amd / conf / transp / transp_sockets.c
blob3dbd9dc33768807d451aaa8b2dbe34fc42d379b5
1 /*
2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 * %W% (Berkeley) %G%
41 * $Id: transp_sockets.c,v 1.5 1999/08/22 21:12:31 ezk Exp $
43 * Socket specific utilities.
44 * -Erez Zadok <ezk@cs.columbia.edu>
47 #ifdef HAVE_CONFIG_H
48 # include <config.h>
49 #endif /* HAVE_CONFIG_H */
50 #include <am_defs.h>
51 #include <amu.h>
55 * find the IP address that can be used to connect to the local host
57 void
58 amu_get_myaddress(struct in_addr *iap)
60 struct sockaddr_in sin;
62 memset((char *) &sin, 0, sizeof(sin));
63 get_myaddress(&sin);
64 iap->s_addr = sin.sin_addr.s_addr;
69 * How to bind to reserved ports.
71 int
72 bind_resv_port(int so, u_short *pp)
74 struct sockaddr_in sin;
75 int rc;
76 u_short port;
78 memset((voidp) &sin, 0, sizeof(sin));
79 sin.sin_family = AF_INET;
81 port = IPPORT_RESERVED;
83 do {
84 --port;
85 sin.sin_port = htons(port);
86 rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
87 } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
89 if (pp && rc == 0)
90 *pp = port;
92 return rc;
97 * close a descriptor, Sockets style
99 int
100 amu_close(int fd)
102 return close(fd);
107 * Create an rpc client attached to the mount daemon.
109 CLIENT *
110 get_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version)
112 CLIENT *client;
115 * First try a TCP socket
117 if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) {
119 * Bind to a privileged port
121 if (bind_resv_port(*sock, (u_short *) 0) < 0)
122 plog(XLOG_ERROR, "can't bind privileged port");
125 * Find mountd port to connect to.
126 * Connect to mountd.
127 * Create a tcp client.
129 if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) {
130 if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0
131 && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL))
132 return client;
135 * Failed so close socket
137 (void) close(*sock);
138 } /* tcp socket opened */
139 /* TCP failed so try UDP */
140 if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
141 plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m");
142 *sock = RPC_ANYSOCK;
143 return NULL;
146 * Bind to a privileged port
148 if (bind_resv_port(*sock, (u_short *) 0) < 0)
149 plog(XLOG_ERROR, "can't bind privileged port");
152 * Zero out the port - make sure we recompute
154 sin->sin_port = 0;
157 * Make a UDP client
159 if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) {
160 (void) close(*sock);
161 *sock = RPC_ANYSOCK;
162 return NULL;
164 #ifdef DEBUG
165 dlog("get_mount_client: Using udp, port %d", sin->sin_port);
166 #endif /* DEBUG */
167 return client;
172 * find the address of the caller of an RPC procedure.
174 struct sockaddr_in *
175 amu_svc_getcaller(SVCXPRT *xprt)
177 return svc_getcaller(xprt);
182 * Create the nfs service for amd
185 create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
188 *soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
190 if (*soNFSp < 0 || bind_resv_port(*soNFSp, NULL) < 0) {
191 plog(XLOG_FATAL, "Can't create privileged nfs port");
192 return 1;
194 if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
195 plog(XLOG_FATAL, "cannot create rpc/udp service");
196 return 2;
198 if ((*nfs_portp = (*nfs_xprtp)->xp_port) >= IPPORT_RESERVED) {
199 plog(XLOG_FATAL, "Can't create privileged nfs port");
200 return 1;
202 if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) {
203 plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
204 return 3;
207 return 0; /* all is well */
212 * Create the amq service for amd (both TCP and UDP)
215 create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp)
217 /* first create TCP service */
218 if (tcp_soAMQp) {
219 *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0);
220 if (*tcp_soAMQp < 0) {
221 plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m");
222 return 1;
225 /* now create RPC service handle for amq */
226 if (tcp_amqpp &&
227 (*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
228 plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp);
229 return 2;
233 /* next create UDP service */
234 if (udp_soAMQp) {
235 *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0);
236 if (*udp_soAMQp < 0) {
237 plog(XLOG_FATAL, "cannot create udp socket for amq service: %m");
238 return 3;
241 /* now create RPC service handle for amq */
242 if (udp_amqpp &&
243 (*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
244 plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp);
245 return 4;
249 return 0; /* all is well */
254 * Ping the portmapper on a remote system by calling the nullproc
256 enum clnt_stat
257 pmap_ping(struct sockaddr_in *address)
259 CLIENT *client;
260 enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
261 int socket = RPC_ANYSOCK;
262 struct timeval timeout;
264 timeout.tv_sec = 3;
265 timeout.tv_usec = 0;
266 address->sin_port = htons(PMAPPORT);
267 client = clntudp_create(address, PMAPPROG, PMAPVERS, timeout, &socket);
268 if (client != (CLIENT *) NULL) {
269 clnt_stat = clnt_call(client,
270 PMAPPROC_NULL,
271 (XDRPROC_T_TYPE) xdr_void,
272 NULL,
273 (XDRPROC_T_TYPE) xdr_void,
274 NULL,
275 timeout);
276 clnt_destroy(client);
278 close(socket);
279 address->sin_port = 0;
281 return clnt_stat;
286 * Find the best NFS version for a host and protocol.
288 u_long
289 get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto)
291 CLIENT *clnt;
292 int again = 0;
293 enum clnt_stat clnt_stat;
294 struct timeval tv;
295 int sock;
298 * If not set or set wrong, then try from NFS_VERS_MAX on down. If
299 * set, then try from nfs_version on down.
301 if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) {
302 nfs_version = NFS_VERS_MAX;
303 again = 1;
305 tv.tv_sec = 3; /* retry every 3 seconds, but also timeout */
306 tv.tv_usec = 0;
309 * First check if remote portmapper is up (verify if remote host is up).
311 clnt_stat = pmap_ping(sin);
312 if (clnt_stat == RPC_TIMEDOUT) {
313 plog(XLOG_ERROR, "get_nfs_version: failed to contact portmapper on host \"%s\": %s", host, clnt_sperrno(clnt_stat));
314 return 0;
317 #ifdef HAVE_FS_NFS3
318 try_again:
319 #endif /* HAVE_FS_NFS3 */
321 sock = RPC_ANYSOCK;
322 if (STREQ(proto, "tcp"))
323 clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0);
324 else if (STREQ(proto, "udp"))
325 clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock);
326 else
327 clnt = NULL;
329 if (clnt == NULL) {
330 #ifdef HAVE_CLNT_SPCREATEERROR
331 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s :%s",
332 (int) nfs_version, proto, host, clnt_spcreateerror(""));
333 #else /* not HAVE_CLNT_SPCREATEERROR */
334 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
335 (int) nfs_version, proto, host);
336 #endif /* not HAVE_CLNT_SPCREATEERROR */
337 return 0;
340 /* Try a couple times to verify the CLIENT handle. */
341 tv.tv_sec = 6;
342 clnt_stat = clnt_call(clnt,
343 NFSPROC_NULL,
344 (XDRPROC_T_TYPE) xdr_void,
346 (XDRPROC_T_TYPE) xdr_void,
348 tv);
349 close(sock);
350 clnt_destroy(clnt);
351 if (clnt_stat != RPC_SUCCESS) {
352 if (again) {
353 #ifdef HAVE_FS_NFS3
354 if (nfs_version == NFS_VERSION3) {
355 plog(XLOG_INFO, "get_nfs_version trying a lower version");
356 nfs_version = NFS_VERSION;
357 again = 0;
359 goto try_again;
360 #endif /* HAVE_FS_NFS3 */
362 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
363 (int) nfs_version, proto, host);
364 return 0;
367 plog(XLOG_INFO, "get_nfs_version: returning (%d,%s) on host %s",
368 (int) nfs_version, proto, host);
369 return nfs_version;
374 * AUTOFS FUNCTIONS FOR SOCKETS:
376 #ifdef HAVE_FS_AUTOFS
378 * Create the nfs service for amd
381 create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
383 /* NOT IMPLEMENTED! */
384 return -1;
386 #endif /* HAVE_FS_AUTOFS */