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