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