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