Home | History | Annotate | Line # | Download | only in rpc
svc_generic.c revision 1.11.2.1
      1 /*	$NetBSD: svc_generic.c,v 1.11.2.1 2013/03/14 22:03:10 riz Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2010, Oracle America, Inc.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are
      8  * met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  *       notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  *       copyright notice, this list of conditions and the following
     14  *       disclaimer in the documentation and/or other materials
     15  *       provided with the distribution.
     16  *     * Neither the name of the "Oracle America, Inc." nor the names of its
     17  *       contributors may be used to endorse or promote products derived
     18  *       from this software without specific prior written permission.
     19  *
     20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
     36  */
     37 
     38 /* #ident	"@(#)svc_generic.c	1.19	94/04/24 SMI" */
     39 
     40 #include <sys/cdefs.h>
     41 #if defined(LIBC_SCCS) && !defined(lint)
     42 #if 0
     43 static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
     44 #else
     45 __RCSID("$NetBSD: svc_generic.c,v 1.11.2.1 2013/03/14 22:03:10 riz Exp $");
     46 #endif
     47 #endif
     48 
     49 /*
     50  * svc_generic.c, Server side for RPC.
     51  *
     52  */
     53 
     54 #include "namespace.h"
     55 #include "reentrant.h"
     56 #include <sys/types.h>
     57 #include <sys/socket.h>
     58 #include <netinet/in.h>
     59 #include <rpc/rpc.h>
     60 #include <rpc/nettype.h>
     61 #include <stdio.h>
     62 #include <errno.h>
     63 #include <stdlib.h>
     64 #include <string.h>
     65 #include <unistd.h>
     66 #include <err.h>
     67 
     68 #include "rpc_internal.h"
     69 
     70 #ifdef __weak_alias
     71 __weak_alias(svc_create,_svc_create)
     72 __weak_alias(svc_tp_create,_svc_tp_create)
     73 __weak_alias(svc_tli_create,_svc_tli_create)
     74 #endif
     75 
     76 extern int __svc_vc_setflag __P((SVCXPRT *, int));
     77 
     78 /*
     79  * The highest level interface for server creation.
     80  * It tries for all the nettokens in that particular class of token
     81  * and returns the number of handles it can create and/or find.
     82  *
     83  * It creates a link list of all the handles it could create.
     84  * If svc_create() is called multiple times, it uses the handle
     85  * created earlier instead of creating a new handle every time.
     86  */
     87 int
     88 svc_create(dispatch, prognum, versnum, nettype)
     89 	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
     90 	rpcprog_t prognum;		/* Program number */
     91 	rpcvers_t versnum;		/* Version number */
     92 	const char *nettype;		/* Networktype token */
     93 {
     94 	struct xlist {
     95 		SVCXPRT *xprt;		/* Server handle */
     96 		struct xlist *next;	/* Next item */
     97 	} *l;
     98 	static struct xlist *xprtlist;	/* A link list of all the handles */
     99 	int num = 0;
    100 	SVCXPRT *xprt;
    101 	struct netconfig *nconf;
    102 	void *handle;
    103 #ifdef _REENTRANT
    104 	extern mutex_t xprtlist_lock;
    105 #endif
    106 
    107 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
    108 
    109 	if ((handle = __rpc_setconf(nettype)) == NULL) {
    110 		warnx("svc_create: unknown protocol");
    111 		return (0);
    112 	}
    113 	while ((nconf = __rpc_getconf(handle)) != NULL) {
    114 		mutex_lock(&xprtlist_lock);
    115 		for (l = xprtlist; l; l = l->next) {
    116 			if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
    117 				/* Found an old one, use it */
    118 				(void) rpcb_unset(prognum, versnum, nconf);
    119 				if (svc_reg(l->xprt, prognum, versnum,
    120 					dispatch, nconf) == FALSE)
    121 					warnx(
    122 		"svc_create: could not register prog %u vers %u on %s",
    123 					(unsigned)prognum, (unsigned)versnum,
    124 					 nconf->nc_netid);
    125 				else
    126 					num++;
    127 				break;
    128 			}
    129 		}
    130 		if (l == NULL) {
    131 			/* It was not found. Now create a new one */
    132 			xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
    133 			if (xprt) {
    134 				l = malloc(sizeof(*l));
    135 				if (l == NULL) {
    136 					warnx("svc_create: no memory");
    137 					mutex_unlock(&xprtlist_lock);
    138 					return (0);
    139 				}
    140 				l->xprt = xprt;
    141 				l->next = xprtlist;
    142 				xprtlist = l;
    143 				num++;
    144 			}
    145 		}
    146 		mutex_unlock(&xprtlist_lock);
    147 	}
    148 	__rpc_endconf(handle);
    149 	/*
    150 	 * In case of num == 0; the error messages are generated by the
    151 	 * underlying layers; and hence not needed here.
    152 	 */
    153 	return (num);
    154 }
    155 
    156 /*
    157  * The high level interface to svc_tli_create().
    158  * It tries to create a server for "nconf" and registers the service
    159  * with the rpcbind. It calls svc_tli_create();
    160  */
    161 SVCXPRT *
    162 svc_tp_create(dispatch, prognum, versnum, nconf)
    163 	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
    164 	rpcprog_t prognum;		/* Program number */
    165 	rpcvers_t versnum;		/* Version number */
    166 	const struct netconfig *nconf; /* Netconfig structure for the network */
    167 {
    168 	SVCXPRT *xprt;
    169 
    170 	if (nconf == NULL) {
    171 		warnx(
    172 	"svc_tp_create: invalid netconfig structure for prog %u vers %u",
    173 				(unsigned)prognum, (unsigned)versnum);
    174 		return (NULL);
    175 	}
    176 	xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
    177 	if (xprt == NULL) {
    178 		return (NULL);
    179 	}
    180 	(void) rpcb_unset(prognum, versnum, __UNCONST(nconf));
    181 	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
    182 		warnx(
    183 		"svc_tp_create: Could not register prog %u vers %u on %s",
    184 				(unsigned)prognum, (unsigned)versnum,
    185 				nconf->nc_netid);
    186 		SVC_DESTROY(xprt);
    187 		return (NULL);
    188 	}
    189 	return (xprt);
    190 }
    191 
    192 /*
    193  * If fd is RPC_ANYFD, then it opens a fd for the given transport
    194  * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
    195  * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
    196  * NULL bindadr and Connection oriented transports, the value of qlen
    197  * is set to 8.
    198  *
    199  * If sendsz or recvsz are zero, their default values are chosen.
    200  */
    201 SVCXPRT *
    202 svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz)
    203 	int fd;				/* Connection end point */
    204 	const struct netconfig *nconf;	/* Netconfig struct for nettoken */
    205 	const struct t_bind *bindaddr;	/* Local bind address */
    206 	u_int sendsz;			/* Max sendsize */
    207 	u_int recvsz;			/* Max recvsize */
    208 {
    209 	SVCXPRT *xprt = NULL;		/* service handle */
    210 	bool_t madefd = FALSE;		/* whether fd opened here  */
    211 	struct __rpc_sockinfo si;
    212 	struct sockaddr_storage ss;
    213 	socklen_t slen;
    214 
    215 	if (fd == RPC_ANYFD) {
    216 		if (nconf == NULL) {
    217 			warnx("svc_tli_create: invalid netconfig");
    218 			return (NULL);
    219 		}
    220 		fd = __rpc_nconf2fd(nconf);
    221 		if (fd == -1) {
    222 			warnx(
    223 			    "svc_tli_create: could not open connection for %s",
    224 					nconf->nc_netid);
    225 			return (NULL);
    226 		}
    227 		__rpc_nconf2sockinfo(nconf, &si);
    228 		madefd = TRUE;
    229 	} else {
    230 		/*
    231 		 * It is an open descriptor. Get the transport info.
    232 		 */
    233 		if (!__rpc_fd2sockinfo(fd, &si)) {
    234 			warnx(
    235 		"svc_tli_create: could not get transport information");
    236 			return (NULL);
    237 		}
    238 	}
    239 
    240 	/*
    241 	 * If the fd is unbound, try to bind it.
    242 	 */
    243 	if (madefd || !__rpc_sockisbound(fd)) {
    244 		if (bindaddr == NULL) {
    245 			if (bindresvport(fd, NULL) < 0) {
    246 				memset(&ss, 0, sizeof ss);
    247 				ss.ss_family = si.si_af;
    248 				ss.ss_len = si.si_alen;
    249 				if (bind(fd, (struct sockaddr *)(void *)&ss,
    250 				    (socklen_t)si.si_alen) < 0) {
    251 					warnx(
    252 			"svc_tli_create: could not bind to anonymous port");
    253 					goto freedata;
    254 				}
    255 			}
    256 			listen(fd, SOMAXCONN);
    257 		} else {
    258 			if (bind(fd,
    259 			    (struct sockaddr *)bindaddr->addr.buf,
    260 			    (socklen_t)si.si_alen) < 0) {
    261 				warnx(
    262 		"svc_tli_create: could not bind to requested address");
    263 				goto freedata;
    264 			}
    265 			listen(fd, (int)bindaddr->qlen);
    266 		}
    267 
    268 	}
    269 	/*
    270 	 * call transport specific function.
    271 	 */
    272 	switch (si.si_socktype) {
    273 		case SOCK_STREAM:
    274 			slen = sizeof ss;
    275 			if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
    276 			    == 0) {
    277 				/* accepted socket */
    278 				xprt = svc_fd_create(fd, sendsz, recvsz);
    279 			} else
    280 				xprt = svc_vc_create(fd, sendsz, recvsz);
    281 			if (!nconf || !xprt)
    282 				break;
    283 #if 0
    284 			/* XXX fvdl */
    285 			if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
    286 			    strcmp(nconf->nc_protofmly, "inet6") == 0)
    287 				(void) __svc_vc_setflag(xprt, TRUE);
    288 #endif
    289 			break;
    290 		case SOCK_DGRAM:
    291 			xprt = svc_dg_create(fd, sendsz, recvsz);
    292 			break;
    293 		default:
    294 			warnx("svc_tli_create: bad service type");
    295 			goto freedata;
    296 	}
    297 
    298 	if (xprt == NULL)
    299 		/*
    300 		 * The error messages here are spitted out by the lower layers:
    301 		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
    302 		 */
    303 		goto freedata;
    304 
    305 	/* Fill in type of service */
    306 	xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
    307 
    308 	if (nconf) {
    309 		xprt->xp_netid = strdup(nconf->nc_netid);
    310 		xprt->xp_tp = strdup(nconf->nc_device);
    311 		if (xprt->xp_netid == NULL || xprt->xp_tp == NULL) {
    312 			svc_destroy(xprt);
    313 			return NULL;
    314 		}
    315 	}
    316 	return (xprt);
    317 
    318 freedata:
    319 	if (madefd)
    320 		(void) close(fd);
    321 	return (NULL);
    322 }
    323