1 /* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos 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 #if defined(LIBC_SCCS) && !defined(lint) 37 #ident "@(#)svc_generic.c 1.19 94/04/24 SMI" 38 static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro"; 39 #endif 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 /* 44 * svc_generic.c, Server side for RPC. 45 * 46 */ 47 48 #include "namespace.h" 49 #include "reentrant.h" 50 #include <sys/types.h> 51 #include <sys/socket.h> 52 #include <netinet/in.h> 53 #include <rpc/rpc.h> 54 #include <rpc/nettype.h> 55 #include <stdio.h> 56 #include <errno.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 #include <err.h> 61 #include "un-namespace.h" 62 63 #include "rpc_com.h" 64 #include "mt_misc.h" 65 66 extern int __svc_vc_setflag(SVCXPRT *, int); 67 68 /* 69 * The highest level interface for server creation. 70 * It tries for all the nettokens in that particular class of token 71 * and returns the number of handles it can create and/or find. 72 * 73 * It creates a link list of all the handles it could create. 74 * If svc_create() is called multiple times, it uses the handle 75 * created earlier instead of creating a new handle every time. 76 */ 77 int 78 svc_create(dispatch, prognum, versnum, nettype) 79 void (*dispatch)(struct svc_req *, SVCXPRT *); 80 rpcprog_t prognum; /* Program number */ 81 rpcvers_t versnum; /* Version number */ 82 const char *nettype; /* Networktype token */ 83 { 84 struct xlist { 85 SVCXPRT *xprt; /* Server handle */ 86 struct xlist *next; /* Next item */ 87 } *l; 88 static struct xlist *xprtlist; /* A link list of all the handles */ 89 int num = 0; 90 SVCXPRT *xprt; 91 struct netconfig *nconf; 92 void *handle; 93 94 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */ 95 96 if ((handle = __rpc_setconf(nettype)) == NULL) { 97 warnx("svc_create: unknown protocol"); 98 return (0); 99 } 100 while ((nconf = __rpc_getconf(handle)) != NULL) { 101 mutex_lock(&xprtlist_lock); 102 for (l = xprtlist; l; l = l->next) { 103 if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) { 104 /* Found an old one, use it */ 105 (void) rpcb_unset(prognum, versnum, nconf); 106 if (svc_reg(l->xprt, prognum, versnum, 107 dispatch, nconf) == FALSE) 108 warnx( 109 "svc_create: could not register prog %u vers %u on %s", 110 (unsigned)prognum, (unsigned)versnum, 111 nconf->nc_netid); 112 else 113 num++; 114 break; 115 } 116 } 117 if (l == NULL) { 118 /* It was not found. Now create a new one */ 119 xprt = svc_tp_create(dispatch, prognum, versnum, nconf); 120 if (xprt) { 121 l = (struct xlist *)malloc(sizeof (*l)); 122 if (l == NULL) { 123 warnx("svc_create: no memory"); 124 mutex_unlock(&xprtlist_lock); 125 return (0); 126 } 127 l->xprt = xprt; 128 l->next = xprtlist; 129 xprtlist = l; 130 num++; 131 } 132 } 133 mutex_unlock(&xprtlist_lock); 134 } 135 __rpc_endconf(handle); 136 /* 137 * In case of num == 0; the error messages are generated by the 138 * underlying layers; and hence not needed here. 139 */ 140 return (num); 141 } 142 143 /* 144 * The high level interface to svc_tli_create(). 145 * It tries to create a server for "nconf" and registers the service 146 * with the rpcbind. It calls svc_tli_create(); 147 */ 148 SVCXPRT * 149 svc_tp_create(dispatch, prognum, versnum, nconf) 150 void (*dispatch)(struct svc_req *, SVCXPRT *); 151 rpcprog_t prognum; /* Program number */ 152 rpcvers_t versnum; /* Version number */ 153 const struct netconfig *nconf; /* Netconfig structure for the network */ 154 { 155 SVCXPRT *xprt; 156 157 if (nconf == NULL) { 158 warnx( 159 "svc_tp_create: invalid netconfig structure for prog %u vers %u", 160 (unsigned)prognum, (unsigned)versnum); 161 return (NULL); 162 } 163 xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 164 if (xprt == NULL) { 165 return (NULL); 166 } 167 /*LINTED const castaway*/ 168 (void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf); 169 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 170 warnx( 171 "svc_tp_create: Could not register prog %u vers %u on %s", 172 (unsigned)prognum, (unsigned)versnum, 173 nconf->nc_netid); 174 SVC_DESTROY(xprt); 175 return (NULL); 176 } 177 return (xprt); 178 } 179 180 /* 181 * If fd is RPC_ANYFD, then it opens a fd for the given transport 182 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 183 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 184 * NULL bindadr and Connection oriented transports, the value of qlen 185 * is set to 8. 186 * 187 * If sendsz or recvsz are zero, their default values are chosen. 188 */ 189 SVCXPRT * 190 svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz) 191 int fd; /* Connection end point */ 192 const struct netconfig *nconf; /* Netconfig struct for nettoken */ 193 const struct t_bind *bindaddr; /* Local bind address */ 194 u_int sendsz; /* Max sendsize */ 195 u_int recvsz; /* Max recvsize */ 196 { 197 SVCXPRT *xprt = NULL; /* service handle */ 198 bool_t madefd = FALSE; /* whether fd opened here */ 199 struct __rpc_sockinfo si; 200 struct sockaddr_storage ss; 201 socklen_t slen; 202 203 if (fd == RPC_ANYFD) { 204 if (nconf == NULL) { 205 warnx("svc_tli_create: invalid netconfig"); 206 return (NULL); 207 } 208 fd = __rpc_nconf2fd(nconf); 209 if (fd == -1) { 210 warnx( 211 "svc_tli_create: could not open connection for %s", 212 nconf->nc_netid); 213 return (NULL); 214 } 215 __rpc_nconf2sockinfo(nconf, &si); 216 madefd = TRUE; 217 } else { 218 /* 219 * It is an open descriptor. Get the transport info. 220 */ 221 if (!__rpc_fd2sockinfo(fd, &si)) { 222 warnx( 223 "svc_tli_create: could not get transport information"); 224 return (NULL); 225 } 226 } 227 228 /* 229 * If the fd is unbound, try to bind it. 230 */ 231 if (madefd || !__rpc_sockisbound(fd)) { 232 if (bindaddr == NULL) { 233 if (bindresvport(fd, NULL) < 0) { 234 memset(&ss, 0, sizeof ss); 235 ss.ss_family = si.si_af; 236 ss.ss_len = si.si_alen; 237 if (_bind(fd, (struct sockaddr *)(void *)&ss, 238 (socklen_t)si.si_alen) < 0) { 239 warnx( 240 "svc_tli_create: could not bind to anonymous port"); 241 goto freedata; 242 } 243 } 244 _listen(fd, SOMAXCONN); 245 } else { 246 if (_bind(fd, 247 (struct sockaddr *)bindaddr->addr.buf, 248 (socklen_t)si.si_alen) < 0) { 249 warnx( 250 "svc_tli_create: could not bind to requested address"); 251 goto freedata; 252 } 253 _listen(fd, (int)bindaddr->qlen); 254 } 255 256 } 257 /* 258 * call transport specific function. 259 */ 260 switch (si.si_socktype) { 261 case SOCK_STREAM: 262 slen = sizeof ss; 263 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 264 == 0) { 265 /* accepted socket */ 266 xprt = svc_fd_create(fd, sendsz, recvsz); 267 } else 268 xprt = svc_vc_create(fd, sendsz, recvsz); 269 if (!nconf || !xprt) 270 break; 271 #if 0 272 /* XXX fvdl */ 273 if (strcmp(nconf->nc_protofmly, "inet") == 0 || 274 strcmp(nconf->nc_protofmly, "inet6") == 0) 275 (void) __svc_vc_setflag(xprt, TRUE); 276 #endif 277 break; 278 case SOCK_DGRAM: 279 xprt = svc_dg_create(fd, sendsz, recvsz); 280 break; 281 default: 282 warnx("svc_tli_create: bad service type"); 283 goto freedata; 284 } 285 286 if (xprt == NULL) 287 /* 288 * The error messages here are spitted out by the lower layers: 289 * svc_vc_create(), svc_fd_create() and svc_dg_create(). 290 */ 291 goto freedata; 292 293 /* Fill in type of service */ 294 xprt->xp_type = __rpc_socktype2seman(si.si_socktype); 295 296 if (nconf) { 297 xprt->xp_netid = strdup(nconf->nc_netid); 298 xprt->xp_tp = strdup(nconf->nc_device); 299 } 300 return (xprt); 301 302 freedata: 303 if (madefd) 304 (void)_close(fd); 305 if (xprt) { 306 if (!madefd) /* so that svc_destroy doesnt close fd */ 307 xprt->xp_fd = RPC_ANYFD; 308 SVC_DESTROY(xprt); 309 } 310 return (NULL); 311 } 312