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