1 /* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 2009, Sun Microsystems, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * - Neither the name of Sun Microsystems, Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 */ 36 37 #if defined(LIBC_SCCS) && !defined(lint) 38 #ident "@(#)svc_generic.c 1.19 94/04/24 SMI" 39 static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro"; 40 #endif 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 /* 45 * svc_generic.c, Server side for RPC. 46 * 47 */ 48 49 #include "opt_inet6.h" 50 51 #include <sys/param.h> 52 #include <sys/lock.h> 53 #include <sys/kernel.h> 54 #include <sys/malloc.h> 55 #include <sys/mutex.h> 56 #include <sys/protosw.h> 57 #include <sys/queue.h> 58 #include <sys/socket.h> 59 #include <sys/socketvar.h> 60 #include <sys/systm.h> 61 #include <sys/sx.h> 62 #include <sys/ucred.h> 63 64 #include <net/vnet.h> 65 66 #include <rpc/rpc.h> 67 #include <rpc/rpcb_clnt.h> 68 #include <rpc/nettype.h> 69 70 #include <rpc/rpc_com.h> 71 72 extern int __svc_vc_setflag(SVCXPRT *, int); 73 74 /* 75 * The highest level interface for server creation. 76 * It tries for all the nettokens in that particular class of token 77 * and returns the number of handles it can create and/or find. 78 * 79 * It creates a link list of all the handles it could create. 80 * If svc_create() is called multiple times, it uses the handle 81 * created earlier instead of creating a new handle every time. 82 */ 83 int 84 svc_create( 85 SVCPOOL *pool, 86 void (*dispatch)(struct svc_req *, SVCXPRT *), 87 rpcprog_t prognum, /* Program number */ 88 rpcvers_t versnum, /* Version number */ 89 const char *nettype) /* Networktype token */ 90 { 91 int g, num = 0; 92 SVCGROUP *grp; 93 SVCXPRT *xprt; 94 struct netconfig *nconf; 95 void *handle; 96 97 if ((handle = __rpc_setconf(nettype)) == NULL) { 98 printf("svc_create: unknown protocol"); 99 return (0); 100 } 101 while ((nconf = __rpc_getconf(handle)) != NULL) { 102 for (g = 0; g < SVC_MAXGROUPS; g++) { 103 grp = &pool->sp_groups[g]; 104 mtx_lock(&grp->sg_lock); 105 TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) { 106 if (strcmp(xprt->xp_netid, nconf->nc_netid)) 107 continue; 108 /* Found an old one, use it */ 109 mtx_unlock(&grp->sg_lock); 110 (void) rpcb_unset(prognum, versnum, nconf); 111 if (svc_reg(xprt, prognum, versnum, 112 dispatch, nconf) == FALSE) { 113 printf( 114 "svc_create: could not register prog %u vers %u on %s\n", 115 (unsigned)prognum, (unsigned)versnum, 116 nconf->nc_netid); 117 mtx_lock(&grp->sg_lock); 118 } else { 119 num++; 120 mtx_lock(&grp->sg_lock); 121 break; 122 } 123 } 124 mtx_unlock(&grp->sg_lock); 125 } 126 if (xprt == NULL) { 127 /* It was not found. Now create a new one */ 128 xprt = svc_tp_create(pool, dispatch, prognum, versnum, 129 NULL, nconf); 130 if (xprt) { 131 num++; 132 SVC_RELEASE(xprt); 133 } 134 } 135 } 136 __rpc_endconf(handle); 137 /* 138 * In case of num == 0; the error messages are generated by the 139 * underlying layers; and hence not needed here. 140 */ 141 return (num); 142 } 143 144 /* 145 * The high level interface to svc_tli_create(). 146 * It tries to create a server for "nconf" and registers the service 147 * with the rpcbind. It calls svc_tli_create(); 148 */ 149 SVCXPRT * 150 svc_tp_create( 151 SVCPOOL *pool, 152 void (*dispatch)(struct svc_req *, SVCXPRT *), 153 rpcprog_t prognum, /* Program number */ 154 rpcvers_t versnum, /* Version number */ 155 const char *uaddr, /* Address (or null for default) */ 156 const struct netconfig *nconf) /* Netconfig structure for the network */ 157 { 158 struct netconfig nconfcopy; 159 struct netbuf *taddr; 160 struct t_bind bind; 161 SVCXPRT *xprt; 162 163 if (nconf == NULL) { 164 printf( 165 "svc_tp_create: invalid netconfig structure for prog %u vers %u\n", 166 (unsigned)prognum, (unsigned)versnum); 167 return (NULL); 168 } 169 if (uaddr) { 170 taddr = uaddr2taddr(nconf, uaddr); 171 bind.addr = *taddr; 172 free(taddr, M_RPC); 173 bind.qlen = -1; 174 xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0); 175 free(bind.addr.buf, M_RPC); 176 } else { 177 xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0); 178 } 179 if (xprt == NULL) { 180 return (NULL); 181 } 182 /*LINTED const castaway*/ 183 nconfcopy = *nconf; 184 (void) rpcb_unset(prognum, versnum, &nconfcopy); 185 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 186 printf( 187 "svc_tp_create: Could not register prog %u vers %u on %s\n", 188 (unsigned)prognum, (unsigned)versnum, 189 nconf->nc_netid); 190 xprt_unregister(xprt); 191 SVC_RELEASE(xprt); 192 return (NULL); 193 } 194 return (xprt); 195 } 196 197 /* 198 * If so is NULL, then it opens a socket for the given transport 199 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 200 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 201 * NULL bindadr and Connection oriented transports, the value of qlen 202 * is set to 8. 203 * 204 * If sendsz or recvsz are zero, their default values are chosen. 205 */ 206 SVCXPRT * 207 svc_tli_create( 208 SVCPOOL *pool, 209 struct socket *so, /* Connection end point */ 210 const struct netconfig *nconf, /* Netconfig struct for nettoken */ 211 const struct t_bind *bindaddr, /* Local bind address */ 212 size_t sendsz, /* Max sendsize */ 213 size_t recvsz) /* Max recvsize */ 214 { 215 SVCXPRT *xprt = NULL; /* service handle */ 216 bool_t madeso = FALSE; /* whether so opened here */ 217 struct __rpc_sockinfo si; 218 struct sockaddr_storage ss; 219 220 if (!so) { 221 if (nconf == NULL) { 222 printf("svc_tli_create: invalid netconfig\n"); 223 return (NULL); 224 } 225 so = __rpc_nconf2socket(nconf); 226 if (!so) { 227 printf( 228 "svc_tli_create: could not open connection for %s\n", 229 nconf->nc_netid); 230 return (NULL); 231 } 232 __rpc_nconf2sockinfo(nconf, &si); 233 madeso = TRUE; 234 } else { 235 /* 236 * It is an open socket. Get the transport info. 237 */ 238 if (!__rpc_socket2sockinfo(so, &si)) { 239 printf( 240 "svc_tli_create: could not get transport information\n"); 241 return (NULL); 242 } 243 } 244 245 /* 246 * If the socket is unbound, try to bind it. 247 */ 248 if (madeso || !__rpc_sockisbound(so)) { 249 if (bindaddr == NULL) { 250 if (bindresvport(so, NULL)) { 251 memset(&ss, 0, sizeof ss); 252 ss.ss_family = si.si_af; 253 ss.ss_len = si.si_alen; 254 if (sobind(so, (struct sockaddr *)&ss, 255 curthread)) { 256 printf( 257 "svc_tli_create: could not bind to anonymous port\n"); 258 goto freedata; 259 } 260 } 261 solisten(so, -1, curthread); 262 } else { 263 if (bindresvport(so, 264 (struct sockaddr *)bindaddr->addr.buf)) { 265 printf( 266 "svc_tli_create: could not bind to requested address\n"); 267 goto freedata; 268 } 269 solisten(so, (int)bindaddr->qlen, curthread); 270 } 271 272 } 273 /* 274 * call transport specific function. 275 */ 276 switch (si.si_socktype) { 277 case SOCK_STREAM: 278 #if 0 279 slen = sizeof ss; 280 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 281 == 0) { 282 /* accepted socket */ 283 xprt = svc_fd_create(fd, sendsz, recvsz); 284 } else 285 #endif 286 xprt = svc_vc_create(pool, so, sendsz, recvsz); 287 if (!nconf || !xprt) 288 break; 289 #if 0 290 /* XXX fvdl */ 291 if (strcmp(nconf->nc_protofmly, "inet") == 0 || 292 strcmp(nconf->nc_protofmly, "inet6") == 0) 293 (void) __svc_vc_setflag(xprt, TRUE); 294 #endif 295 break; 296 case SOCK_DGRAM: 297 xprt = svc_dg_create(pool, so, sendsz, recvsz); 298 break; 299 default: 300 printf("svc_tli_create: bad service type"); 301 goto freedata; 302 } 303 304 if (xprt == NULL) 305 /* 306 * The error messages here are spitted out by the lower layers: 307 * svc_vc_create(), svc_fd_create() and svc_dg_create(). 308 */ 309 goto freedata; 310 311 /* Fill in type of service */ 312 xprt->xp_type = __rpc_socktype2seman(si.si_socktype); 313 314 if (nconf) { 315 xprt->xp_netid = strdup(nconf->nc_netid, M_RPC); 316 } 317 return (xprt); 318 319 freedata: 320 if (madeso) 321 (void)soclose(so); 322 if (xprt) { 323 if (!madeso) /* so that svc_destroy doesnt close fd */ 324 xprt->xp_socket = NULL; 325 xprt_unregister(xprt); 326 } 327 return (NULL); 328 } 329