1/* $NetBSD: svc_generic.c,v 1.11 2012/01/02 21:29:29 dholland 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 43static 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 2012/01/02 21:29:29 dholland 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 76extern 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 */ 87int 88svc_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 */ 161SVCXPRT * 162svc_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 */ 201SVCXPRT * 202svc_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 318freedata: 319 if (madefd) 320 (void) close(fd); 321 return (NULL); 322} 323