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