1*ce0e08e2SPeter Avalos /* 2*ce0e08e2SPeter Avalos * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3*ce0e08e2SPeter Avalos * unrestricted use provided that this legend is included on all tape 4*ce0e08e2SPeter Avalos * media and as a part of the software program in whole or part. Users 5*ce0e08e2SPeter Avalos * may copy or modify Sun RPC without charge, but are not authorized 6*ce0e08e2SPeter Avalos * to license or distribute it to anyone else except as part of a product or 7*ce0e08e2SPeter Avalos * program developed by the user. 8*ce0e08e2SPeter Avalos * 9*ce0e08e2SPeter Avalos * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10*ce0e08e2SPeter Avalos * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11*ce0e08e2SPeter Avalos * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12*ce0e08e2SPeter Avalos * 13*ce0e08e2SPeter Avalos * Sun RPC is provided with no support and without any obligation on the 14*ce0e08e2SPeter Avalos * part of Sun Microsystems, Inc. to assist in its use, correction, 15*ce0e08e2SPeter Avalos * modification or enhancement. 16*ce0e08e2SPeter Avalos * 17*ce0e08e2SPeter Avalos * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18*ce0e08e2SPeter Avalos * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19*ce0e08e2SPeter Avalos * OR ANY PART THEREOF. 20*ce0e08e2SPeter Avalos * 21*ce0e08e2SPeter Avalos * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22*ce0e08e2SPeter Avalos * or profits or other special, indirect and consequential damages, even if 23*ce0e08e2SPeter Avalos * Sun has been advised of the possibility of such damages. 24*ce0e08e2SPeter Avalos * 25*ce0e08e2SPeter Avalos * Sun Microsystems, Inc. 26*ce0e08e2SPeter Avalos * 2550 Garcia Avenue 27*ce0e08e2SPeter Avalos * Mountain View, California 94043 28*ce0e08e2SPeter Avalos * 29*ce0e08e2SPeter Avalos * @(#)svc_generic.c 1.19 94/04/24 SMI; 1.21 89/02/28 Copyr 1988 Sun Micro 30*ce0e08e2SPeter Avalos * $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ 31*ce0e08e2SPeter Avalos * $FreeBSD: src/lib/libc/rpc/svc_generic.c,v 1.7 2006/02/27 22:10:59 deischen Exp $ 32*ce0e08e2SPeter Avalos * $DragonFly$ 33*ce0e08e2SPeter Avalos */ 34*ce0e08e2SPeter Avalos 35*ce0e08e2SPeter Avalos /* 36*ce0e08e2SPeter Avalos * Copyright (c) 1986-1991 by Sun Microsystems Inc. 37*ce0e08e2SPeter Avalos */ 38*ce0e08e2SPeter Avalos 39*ce0e08e2SPeter Avalos /* 40*ce0e08e2SPeter Avalos * svc_generic.c, Server side for RPC. 41*ce0e08e2SPeter Avalos */ 42*ce0e08e2SPeter Avalos 43*ce0e08e2SPeter Avalos #include "namespace.h" 44*ce0e08e2SPeter Avalos #include "reentrant.h" 45*ce0e08e2SPeter Avalos #include <sys/types.h> 46*ce0e08e2SPeter Avalos #include <sys/socket.h> 47*ce0e08e2SPeter Avalos #include <netinet/in.h> 48*ce0e08e2SPeter Avalos #include <rpc/rpc.h> 49*ce0e08e2SPeter Avalos #include <rpc/nettype.h> 50*ce0e08e2SPeter Avalos #include <stdio.h> 51*ce0e08e2SPeter Avalos #include <errno.h> 52*ce0e08e2SPeter Avalos #include <stdlib.h> 53*ce0e08e2SPeter Avalos #include <string.h> 54*ce0e08e2SPeter Avalos #include <unistd.h> 55*ce0e08e2SPeter Avalos #include <err.h> 56*ce0e08e2SPeter Avalos #include "un-namespace.h" 57*ce0e08e2SPeter Avalos 58*ce0e08e2SPeter Avalos #include "rpc_com.h" 59*ce0e08e2SPeter Avalos #include "mt_misc.h" 60*ce0e08e2SPeter Avalos 61*ce0e08e2SPeter Avalos extern int __svc_vc_setflag(SVCXPRT *, int); 62*ce0e08e2SPeter Avalos 63*ce0e08e2SPeter Avalos /* 64*ce0e08e2SPeter Avalos * The highest level interface for server creation. 65*ce0e08e2SPeter Avalos * It tries for all the nettokens in that particular class of token 66*ce0e08e2SPeter Avalos * and returns the number of handles it can create and/or find. 67*ce0e08e2SPeter Avalos * 68*ce0e08e2SPeter Avalos * It creates a link list of all the handles it could create. 69*ce0e08e2SPeter Avalos * If svc_create() is called multiple times, it uses the handle 70*ce0e08e2SPeter Avalos * created earlier instead of creating a new handle every time. 71*ce0e08e2SPeter Avalos */ 72*ce0e08e2SPeter Avalos int 73*ce0e08e2SPeter Avalos svc_create(void (*dispatch)(struct svc_req *, SVCXPRT *), 74*ce0e08e2SPeter Avalos rpcprog_t prognum, /* Program number */ 75*ce0e08e2SPeter Avalos rpcvers_t versnum, /* Version number */ 76*ce0e08e2SPeter Avalos const char *nettype) /* Networktype token */ 77*ce0e08e2SPeter Avalos { 78*ce0e08e2SPeter Avalos struct xlist { 79*ce0e08e2SPeter Avalos SVCXPRT *xprt; /* Server handle */ 80*ce0e08e2SPeter Avalos struct xlist *next; /* Next item */ 81*ce0e08e2SPeter Avalos } *l; 82*ce0e08e2SPeter Avalos static struct xlist *xprtlist; /* A link list of all the handles */ 83*ce0e08e2SPeter Avalos int num = 0; 84*ce0e08e2SPeter Avalos SVCXPRT *xprt; 85*ce0e08e2SPeter Avalos struct netconfig *nconf; 86*ce0e08e2SPeter Avalos void *handle; 87*ce0e08e2SPeter Avalos 88*ce0e08e2SPeter Avalos /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */ 89*ce0e08e2SPeter Avalos 90*ce0e08e2SPeter Avalos if ((handle = __rpc_setconf(nettype)) == NULL) { 91*ce0e08e2SPeter Avalos warnx("svc_create: unknown protocol"); 92*ce0e08e2SPeter Avalos return (0); 93*ce0e08e2SPeter Avalos } 94*ce0e08e2SPeter Avalos while ((nconf = __rpc_getconf(handle)) != NULL) { 95*ce0e08e2SPeter Avalos mutex_lock(&xprtlist_lock); 96*ce0e08e2SPeter Avalos for (l = xprtlist; l; l = l->next) { 97*ce0e08e2SPeter Avalos if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) { 98*ce0e08e2SPeter Avalos /* Found an old one, use it */ 99*ce0e08e2SPeter Avalos rpcb_unset(prognum, versnum, nconf); 100*ce0e08e2SPeter Avalos if (svc_reg(l->xprt, prognum, versnum, 101*ce0e08e2SPeter Avalos dispatch, nconf) == FALSE) 102*ce0e08e2SPeter Avalos warnx( 103*ce0e08e2SPeter Avalos "svc_create: could not register prog %u vers %u on %s", 104*ce0e08e2SPeter Avalos (unsigned)prognum, (unsigned)versnum, 105*ce0e08e2SPeter Avalos nconf->nc_netid); 106*ce0e08e2SPeter Avalos else 107*ce0e08e2SPeter Avalos num++; 108*ce0e08e2SPeter Avalos break; 109*ce0e08e2SPeter Avalos } 110*ce0e08e2SPeter Avalos } 111*ce0e08e2SPeter Avalos if (l == NULL) { 112*ce0e08e2SPeter Avalos /* It was not found. Now create a new one */ 113*ce0e08e2SPeter Avalos xprt = svc_tp_create(dispatch, prognum, versnum, nconf); 114*ce0e08e2SPeter Avalos if (xprt) { 115*ce0e08e2SPeter Avalos l = (struct xlist *)malloc(sizeof (*l)); 116*ce0e08e2SPeter Avalos if (l == NULL) { 117*ce0e08e2SPeter Avalos warnx("svc_create: no memory"); 118*ce0e08e2SPeter Avalos mutex_unlock(&xprtlist_lock); 119*ce0e08e2SPeter Avalos return (0); 120*ce0e08e2SPeter Avalos } 121*ce0e08e2SPeter Avalos l->xprt = xprt; 122*ce0e08e2SPeter Avalos l->next = xprtlist; 123*ce0e08e2SPeter Avalos xprtlist = l; 124*ce0e08e2SPeter Avalos num++; 125*ce0e08e2SPeter Avalos } 126*ce0e08e2SPeter Avalos } 127*ce0e08e2SPeter Avalos mutex_unlock(&xprtlist_lock); 128*ce0e08e2SPeter Avalos } 129*ce0e08e2SPeter Avalos __rpc_endconf(handle); 130*ce0e08e2SPeter Avalos /* 131*ce0e08e2SPeter Avalos * In case of num == 0; the error messages are generated by the 132*ce0e08e2SPeter Avalos * underlying layers; and hence not needed here. 133*ce0e08e2SPeter Avalos */ 134*ce0e08e2SPeter Avalos return (num); 135*ce0e08e2SPeter Avalos } 136*ce0e08e2SPeter Avalos 137*ce0e08e2SPeter Avalos /* 138*ce0e08e2SPeter Avalos * The high level interface to svc_tli_create(). 139*ce0e08e2SPeter Avalos * It tries to create a server for "nconf" and registers the service 140*ce0e08e2SPeter Avalos * with the rpcbind. It calls svc_tli_create(); 141*ce0e08e2SPeter Avalos */ 142*ce0e08e2SPeter Avalos SVCXPRT * 143*ce0e08e2SPeter Avalos svc_tp_create(void (*dispatch)(struct svc_req *, SVCXPRT *), 144*ce0e08e2SPeter Avalos rpcprog_t prognum, /* Program number */ 145*ce0e08e2SPeter Avalos rpcvers_t versnum, /* Version number */ 146*ce0e08e2SPeter Avalos const struct netconfig *nconf) /* Netconfig structure for the network */ 147*ce0e08e2SPeter Avalos { 148*ce0e08e2SPeter Avalos SVCXPRT *xprt; 149*ce0e08e2SPeter Avalos 150*ce0e08e2SPeter Avalos if (nconf == NULL) { 151*ce0e08e2SPeter Avalos warnx( 152*ce0e08e2SPeter Avalos "svc_tp_create: invalid netconfig structure for prog %u vers %u", 153*ce0e08e2SPeter Avalos (unsigned)prognum, (unsigned)versnum); 154*ce0e08e2SPeter Avalos return (NULL); 155*ce0e08e2SPeter Avalos } 156*ce0e08e2SPeter Avalos xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 157*ce0e08e2SPeter Avalos if (xprt == NULL) { 158*ce0e08e2SPeter Avalos return (NULL); 159*ce0e08e2SPeter Avalos } 160*ce0e08e2SPeter Avalos /*LINTED const castaway*/ 161*ce0e08e2SPeter Avalos rpcb_unset(prognum, versnum, (struct netconfig *) nconf); 162*ce0e08e2SPeter Avalos if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 163*ce0e08e2SPeter Avalos warnx( 164*ce0e08e2SPeter Avalos "svc_tp_create: Could not register prog %u vers %u on %s", 165*ce0e08e2SPeter Avalos (unsigned)prognum, (unsigned)versnum, 166*ce0e08e2SPeter Avalos nconf->nc_netid); 167*ce0e08e2SPeter Avalos SVC_DESTROY(xprt); 168*ce0e08e2SPeter Avalos return (NULL); 169*ce0e08e2SPeter Avalos } 170*ce0e08e2SPeter Avalos return (xprt); 171*ce0e08e2SPeter Avalos } 172*ce0e08e2SPeter Avalos 173*ce0e08e2SPeter Avalos /* 174*ce0e08e2SPeter Avalos * If fd is RPC_ANYFD, then it opens a fd for the given transport 175*ce0e08e2SPeter Avalos * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 176*ce0e08e2SPeter Avalos * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 177*ce0e08e2SPeter Avalos * NULL bindadr and Connection oriented transports, the value of qlen 178*ce0e08e2SPeter Avalos * is set to 8. 179*ce0e08e2SPeter Avalos * 180*ce0e08e2SPeter Avalos * If sendsz or recvsz are zero, their default values are chosen. 181*ce0e08e2SPeter Avalos */ 182*ce0e08e2SPeter Avalos SVCXPRT * 183*ce0e08e2SPeter Avalos svc_tli_create( 184*ce0e08e2SPeter Avalos int fd, /* Connection end point */ 185*ce0e08e2SPeter Avalos const struct netconfig *nconf, /* Netconfig struct for nettoken */ 186*ce0e08e2SPeter Avalos const struct t_bind *bindaddr, /* Local bind address */ 187*ce0e08e2SPeter Avalos u_int sendsz, /* Max sendsize */ 188*ce0e08e2SPeter Avalos u_int recvsz) /* Max recvsize */ 189*ce0e08e2SPeter Avalos { 190*ce0e08e2SPeter Avalos SVCXPRT *xprt = NULL; /* service handle */ 191*ce0e08e2SPeter Avalos bool_t madefd = FALSE; /* whether fd opened here */ 192*ce0e08e2SPeter Avalos struct __rpc_sockinfo si; 193*ce0e08e2SPeter Avalos struct sockaddr_storage ss; 194*ce0e08e2SPeter Avalos socklen_t slen; 195*ce0e08e2SPeter Avalos 196*ce0e08e2SPeter Avalos if (fd == RPC_ANYFD) { 197*ce0e08e2SPeter Avalos if (nconf == NULL) { 198*ce0e08e2SPeter Avalos warnx("svc_tli_create: invalid netconfig"); 199*ce0e08e2SPeter Avalos return (NULL); 200*ce0e08e2SPeter Avalos } 201*ce0e08e2SPeter Avalos fd = __rpc_nconf2fd(nconf); 202*ce0e08e2SPeter Avalos if (fd == -1) { 203*ce0e08e2SPeter Avalos warnx( 204*ce0e08e2SPeter Avalos "svc_tli_create: could not open connection for %s", 205*ce0e08e2SPeter Avalos nconf->nc_netid); 206*ce0e08e2SPeter Avalos return (NULL); 207*ce0e08e2SPeter Avalos } 208*ce0e08e2SPeter Avalos __rpc_nconf2sockinfo(nconf, &si); 209*ce0e08e2SPeter Avalos madefd = TRUE; 210*ce0e08e2SPeter Avalos } else { 211*ce0e08e2SPeter Avalos /* 212*ce0e08e2SPeter Avalos * It is an open descriptor. Get the transport info. 213*ce0e08e2SPeter Avalos */ 214*ce0e08e2SPeter Avalos if (!__rpc_fd2sockinfo(fd, &si)) { 215*ce0e08e2SPeter Avalos warnx( 216*ce0e08e2SPeter Avalos "svc_tli_create: could not get transport information"); 217*ce0e08e2SPeter Avalos return (NULL); 218*ce0e08e2SPeter Avalos } 219*ce0e08e2SPeter Avalos } 220*ce0e08e2SPeter Avalos 221*ce0e08e2SPeter Avalos /* 222*ce0e08e2SPeter Avalos * If the fd is unbound, try to bind it. 223*ce0e08e2SPeter Avalos */ 224*ce0e08e2SPeter Avalos if (madefd || !__rpc_sockisbound(fd)) { 225*ce0e08e2SPeter Avalos if (bindaddr == NULL) { 226*ce0e08e2SPeter Avalos if (bindresvport(fd, NULL) < 0) { 227*ce0e08e2SPeter Avalos memset(&ss, 0, sizeof ss); 228*ce0e08e2SPeter Avalos ss.ss_family = si.si_af; 229*ce0e08e2SPeter Avalos ss.ss_len = si.si_alen; 230*ce0e08e2SPeter Avalos if (_bind(fd, (struct sockaddr *)(void *)&ss, 231*ce0e08e2SPeter Avalos (socklen_t)si.si_alen) < 0) { 232*ce0e08e2SPeter Avalos warnx( 233*ce0e08e2SPeter Avalos "svc_tli_create: could not bind to anonymous port"); 234*ce0e08e2SPeter Avalos goto freedata; 235*ce0e08e2SPeter Avalos } 236*ce0e08e2SPeter Avalos } 237*ce0e08e2SPeter Avalos _listen(fd, SOMAXCONN); 238*ce0e08e2SPeter Avalos } else { 239*ce0e08e2SPeter Avalos if (_bind(fd, 240*ce0e08e2SPeter Avalos (struct sockaddr *)bindaddr->addr.buf, 241*ce0e08e2SPeter Avalos (socklen_t)si.si_alen) < 0) { 242*ce0e08e2SPeter Avalos warnx( 243*ce0e08e2SPeter Avalos "svc_tli_create: could not bind to requested address"); 244*ce0e08e2SPeter Avalos goto freedata; 245*ce0e08e2SPeter Avalos } 246*ce0e08e2SPeter Avalos _listen(fd, (int)bindaddr->qlen); 247*ce0e08e2SPeter Avalos } 248*ce0e08e2SPeter Avalos 249*ce0e08e2SPeter Avalos } 250*ce0e08e2SPeter Avalos /* 251*ce0e08e2SPeter Avalos * call transport specific function. 252*ce0e08e2SPeter Avalos */ 253*ce0e08e2SPeter Avalos switch (si.si_socktype) { 254*ce0e08e2SPeter Avalos case SOCK_STREAM: 255*ce0e08e2SPeter Avalos slen = sizeof ss; 256*ce0e08e2SPeter Avalos if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 257*ce0e08e2SPeter Avalos == 0) { 258*ce0e08e2SPeter Avalos /* accepted socket */ 259*ce0e08e2SPeter Avalos xprt = svc_fd_create(fd, sendsz, recvsz); 260*ce0e08e2SPeter Avalos } else 261*ce0e08e2SPeter Avalos xprt = svc_vc_create(fd, sendsz, recvsz); 262*ce0e08e2SPeter Avalos if (!nconf || !xprt) 263*ce0e08e2SPeter Avalos break; 264*ce0e08e2SPeter Avalos #if 0 265*ce0e08e2SPeter Avalos /* XXX fvdl */ 266*ce0e08e2SPeter Avalos if (strcmp(nconf->nc_protofmly, "inet") == 0 || 267*ce0e08e2SPeter Avalos strcmp(nconf->nc_protofmly, "inet6") == 0) 268*ce0e08e2SPeter Avalos (void) __svc_vc_setflag(xprt, TRUE); 269*ce0e08e2SPeter Avalos #endif 270*ce0e08e2SPeter Avalos break; 271*ce0e08e2SPeter Avalos case SOCK_DGRAM: 272*ce0e08e2SPeter Avalos xprt = svc_dg_create(fd, sendsz, recvsz); 273*ce0e08e2SPeter Avalos break; 274*ce0e08e2SPeter Avalos default: 275*ce0e08e2SPeter Avalos warnx("svc_tli_create: bad service type"); 276*ce0e08e2SPeter Avalos goto freedata; 277*ce0e08e2SPeter Avalos } 278*ce0e08e2SPeter Avalos 279*ce0e08e2SPeter Avalos if (xprt == NULL) 280*ce0e08e2SPeter Avalos /* 281*ce0e08e2SPeter Avalos * The error messages here are spitted out by the lower layers: 282*ce0e08e2SPeter Avalos * svc_vc_create(), svc_fd_create() and svc_dg_create(). 283*ce0e08e2SPeter Avalos */ 284*ce0e08e2SPeter Avalos goto freedata; 285*ce0e08e2SPeter Avalos 286*ce0e08e2SPeter Avalos /* Fill in type of service */ 287*ce0e08e2SPeter Avalos xprt->xp_type = __rpc_socktype2seman(si.si_socktype); 288*ce0e08e2SPeter Avalos 289*ce0e08e2SPeter Avalos if (nconf) { 290*ce0e08e2SPeter Avalos xprt->xp_netid = strdup(nconf->nc_netid); 291*ce0e08e2SPeter Avalos xprt->xp_tp = strdup(nconf->nc_device); 292*ce0e08e2SPeter Avalos } 293*ce0e08e2SPeter Avalos return (xprt); 294*ce0e08e2SPeter Avalos 295*ce0e08e2SPeter Avalos freedata: 296*ce0e08e2SPeter Avalos if (madefd) 297*ce0e08e2SPeter Avalos _close(fd); 298*ce0e08e2SPeter Avalos if (xprt) { 299*ce0e08e2SPeter Avalos if (!madefd) /* so that svc_destroy doesnt close fd */ 300*ce0e08e2SPeter Avalos xprt->xp_fd = RPC_ANYFD; 301*ce0e08e2SPeter Avalos SVC_DESTROY(xprt); 302*ce0e08e2SPeter Avalos } 303*ce0e08e2SPeter Avalos return (NULL); 304*ce0e08e2SPeter Avalos } 305