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 "opt_inet6.h" 49 50 #include <sys/param.h> 51 #include <sys/lock.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 #include <sys/mutex.h> 55 #include <sys/protosw.h> 56 #include <sys/queue.h> 57 #include <sys/socket.h> 58 #include <sys/socketvar.h> 59 #include <sys/systm.h> 60 #include <sys/sx.h> 61 #include <sys/ucred.h> 62 63 #include <rpc/rpc.h> 64 #include <rpc/rpcb_clnt.h> 65 #include <rpc/nettype.h> 66 67 #include <rpc/rpc_com.h> 68 69 extern int __svc_vc_setflag(SVCXPRT *, int); 70 71 /* 72 * The highest level interface for server creation. 73 * It tries for all the nettokens in that particular class of token 74 * and returns the number of handles it can create and/or find. 75 * 76 * It creates a link list of all the handles it could create. 77 * If svc_create() is called multiple times, it uses the handle 78 * created earlier instead of creating a new handle every time. 79 */ 80 int 81 svc_create( 82 SVCPOOL *pool, 83 void (*dispatch)(struct svc_req *, SVCXPRT *), 84 rpcprog_t prognum, /* Program number */ 85 rpcvers_t versnum, /* Version number */ 86 const char *nettype) /* Networktype token */ 87 { 88 int num = 0; 89 SVCXPRT *xprt; 90 struct netconfig *nconf; 91 void *handle; 92 93 if ((handle = __rpc_setconf(nettype)) == NULL) { 94 printf("svc_create: unknown protocol"); 95 return (0); 96 } 97 while ((nconf = __rpc_getconf(handle)) != NULL) { 98 mtx_lock(&pool->sp_lock); 99 TAILQ_FOREACH(xprt, &pool->sp_xlist, xp_link) { 100 if (strcmp(xprt->xp_netid, nconf->nc_netid) == 0) { 101 /* Found an old one, use it */ 102 mtx_unlock(&pool->sp_lock); 103 (void) rpcb_unset(prognum, versnum, nconf); 104 if (svc_reg(xprt, prognum, versnum, 105 dispatch, nconf) == FALSE) { 106 printf( 107 "svc_create: could not register prog %u vers %u on %s\n", 108 (unsigned)prognum, (unsigned)versnum, 109 nconf->nc_netid); 110 mtx_lock(&pool->sp_lock); 111 } else { 112 num++; 113 mtx_lock(&pool->sp_lock); 114 break; 115 } 116 } 117 } 118 mtx_unlock(&pool->sp_lock); 119 if (xprt == NULL) { 120 /* It was not found. Now create a new one */ 121 xprt = svc_tp_create(pool, dispatch, prognum, versnum, 122 NULL, nconf); 123 if (xprt) 124 num++; 125 } 126 } 127 __rpc_endconf(handle); 128 /* 129 * In case of num == 0; the error messages are generated by the 130 * underlying layers; and hence not needed here. 131 */ 132 return (num); 133 } 134 135 /* 136 * The high level interface to svc_tli_create(). 137 * It tries to create a server for "nconf" and registers the service 138 * with the rpcbind. It calls svc_tli_create(); 139 */ 140 SVCXPRT * 141 svc_tp_create( 142 SVCPOOL *pool, 143 void (*dispatch)(struct svc_req *, SVCXPRT *), 144 rpcprog_t prognum, /* Program number */ 145 rpcvers_t versnum, /* Version number */ 146 const char *uaddr, /* Address (or null for default) */ 147 const struct netconfig *nconf) /* Netconfig structure for the network */ 148 { 149 struct netconfig nconfcopy; 150 struct netbuf *taddr; 151 struct t_bind bind; 152 SVCXPRT *xprt; 153 154 if (nconf == NULL) { 155 printf( 156 "svc_tp_create: invalid netconfig structure for prog %u vers %u\n", 157 (unsigned)prognum, (unsigned)versnum); 158 return (NULL); 159 } 160 if (uaddr) { 161 taddr = uaddr2taddr(nconf, uaddr); 162 bind.addr = *taddr; 163 free(taddr, M_RPC); 164 bind.qlen = SOMAXCONN; 165 xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0); 166 free(bind.addr.buf, M_RPC); 167 } else { 168 xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0); 169 } 170 if (xprt == NULL) { 171 return (NULL); 172 } 173 /*LINTED const castaway*/ 174 nconfcopy = *nconf; 175 (void) rpcb_unset(prognum, versnum, &nconfcopy); 176 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 177 printf( 178 "svc_tp_create: Could not register prog %u vers %u on %s\n", 179 (unsigned)prognum, (unsigned)versnum, 180 nconf->nc_netid); 181 SVC_DESTROY(xprt); 182 return (NULL); 183 } 184 return (xprt); 185 } 186 187 /* 188 * Bind a socket to a privileged IP port 189 */ 190 int bindresvport(struct socket *so, struct sockaddr *sa); 191 int 192 bindresvport(struct socket *so, struct sockaddr *sa) 193 { 194 int old, error, af; 195 bool_t freesa = FALSE; 196 struct sockaddr_in *sin; 197 #ifdef INET6 198 struct sockaddr_in6 *sin6; 199 #endif 200 struct sockopt opt; 201 int proto, portrange, portlow; 202 u_int16_t *portp; 203 socklen_t salen; 204 205 if (sa == NULL) { 206 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 207 if (error) 208 return (error); 209 freesa = TRUE; 210 af = sa->sa_family; 211 salen = sa->sa_len; 212 memset(sa, 0, sa->sa_len); 213 } else { 214 af = sa->sa_family; 215 salen = sa->sa_len; 216 } 217 218 switch (af) { 219 case AF_INET: 220 proto = IPPROTO_IP; 221 portrange = IP_PORTRANGE; 222 portlow = IP_PORTRANGE_LOW; 223 sin = (struct sockaddr_in *)sa; 224 portp = &sin->sin_port; 225 break; 226 #ifdef INET6 227 case AF_INET6: 228 proto = IPPROTO_IPV6; 229 portrange = IPV6_PORTRANGE; 230 portlow = IPV6_PORTRANGE_LOW; 231 sin6 = (struct sockaddr_in6 *)sa; 232 portp = &sin6->sin6_port; 233 break; 234 #endif 235 default: 236 return (EPFNOSUPPORT); 237 } 238 239 sa->sa_family = af; 240 sa->sa_len = salen; 241 242 if (*portp == 0) { 243 bzero(&opt, sizeof(opt)); 244 opt.sopt_dir = SOPT_GET; 245 opt.sopt_level = proto; 246 opt.sopt_name = portrange; 247 opt.sopt_val = &old; 248 opt.sopt_valsize = sizeof(old); 249 error = sogetopt(so, &opt); 250 if (error) 251 goto out; 252 253 opt.sopt_dir = SOPT_SET; 254 opt.sopt_val = &portlow; 255 error = sosetopt(so, &opt); 256 if (error) 257 goto out; 258 } 259 260 error = sobind(so, sa, curthread); 261 262 if (*portp == 0) { 263 if (error) { 264 opt.sopt_dir = SOPT_SET; 265 opt.sopt_val = &old; 266 sosetopt(so, &opt); 267 } 268 } 269 out: 270 if (freesa) 271 free(sa, M_SONAME); 272 273 return (error); 274 } 275 276 /* 277 * If so is NULL, then it opens a socket for the given transport 278 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 279 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 280 * NULL bindadr and Connection oriented transports, the value of qlen 281 * is set to 8. 282 * 283 * If sendsz or recvsz are zero, their default values are chosen. 284 */ 285 SVCXPRT * 286 svc_tli_create( 287 SVCPOOL *pool, 288 struct socket *so, /* Connection end point */ 289 const struct netconfig *nconf, /* Netconfig struct for nettoken */ 290 const struct t_bind *bindaddr, /* Local bind address */ 291 size_t sendsz, /* Max sendsize */ 292 size_t recvsz) /* Max recvsize */ 293 { 294 SVCXPRT *xprt = NULL; /* service handle */ 295 bool_t madeso = FALSE; /* whether so opened here */ 296 struct __rpc_sockinfo si; 297 struct sockaddr_storage ss; 298 299 if (!so) { 300 if (nconf == NULL) { 301 printf("svc_tli_create: invalid netconfig\n"); 302 return (NULL); 303 } 304 so = __rpc_nconf2socket(nconf); 305 if (!so) { 306 printf( 307 "svc_tli_create: could not open connection for %s\n", 308 nconf->nc_netid); 309 return (NULL); 310 } 311 __rpc_nconf2sockinfo(nconf, &si); 312 madeso = TRUE; 313 } else { 314 /* 315 * It is an open socket. Get the transport info. 316 */ 317 if (!__rpc_socket2sockinfo(so, &si)) { 318 printf( 319 "svc_tli_create: could not get transport information\n"); 320 return (NULL); 321 } 322 } 323 324 /* 325 * If the socket is unbound, try to bind it. 326 */ 327 if (madeso || !__rpc_sockisbound(so)) { 328 if (bindaddr == NULL) { 329 if (bindresvport(so, NULL)) { 330 memset(&ss, 0, sizeof ss); 331 ss.ss_family = si.si_af; 332 ss.ss_len = si.si_alen; 333 if (sobind(so, (struct sockaddr *)&ss, 334 curthread)) { 335 printf( 336 "svc_tli_create: could not bind to anonymous port\n"); 337 goto freedata; 338 } 339 } 340 solisten(so, SOMAXCONN, curthread); 341 } else { 342 if (bindresvport(so, 343 (struct sockaddr *)bindaddr->addr.buf)) { 344 printf( 345 "svc_tli_create: could not bind to requested address\n"); 346 goto freedata; 347 } 348 solisten(so, (int)bindaddr->qlen, curthread); 349 } 350 351 } 352 /* 353 * call transport specific function. 354 */ 355 switch (si.si_socktype) { 356 case SOCK_STREAM: 357 #if 0 358 slen = sizeof ss; 359 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 360 == 0) { 361 /* accepted socket */ 362 xprt = svc_fd_create(fd, sendsz, recvsz); 363 } else 364 #endif 365 xprt = svc_vc_create(pool, so, sendsz, recvsz); 366 if (!nconf || !xprt) 367 break; 368 #if 0 369 /* XXX fvdl */ 370 if (strcmp(nconf->nc_protofmly, "inet") == 0 || 371 strcmp(nconf->nc_protofmly, "inet6") == 0) 372 (void) __svc_vc_setflag(xprt, TRUE); 373 #endif 374 break; 375 case SOCK_DGRAM: 376 xprt = svc_dg_create(pool, so, sendsz, recvsz); 377 break; 378 default: 379 printf("svc_tli_create: bad service type"); 380 goto freedata; 381 } 382 383 if (xprt == NULL) 384 /* 385 * The error messages here are spitted out by the lower layers: 386 * svc_vc_create(), svc_fd_create() and svc_dg_create(). 387 */ 388 goto freedata; 389 390 /* Fill in type of service */ 391 xprt->xp_type = __rpc_socktype2seman(si.si_socktype); 392 393 if (nconf) { 394 xprt->xp_netid = strdup(nconf->nc_netid, M_RPC); 395 } 396 return (xprt); 397 398 freedata: 399 if (madeso) 400 (void)soclose(so); 401 if (xprt) { 402 if (!madeso) /* so that svc_destroy doesnt close fd */ 403 xprt->xp_socket = NULL; 404 SVC_DESTROY(xprt); 405 } 406 return (NULL); 407 } 408