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 g, num = 0; 90 SVCGROUP *grp; 91 SVCXPRT *xprt; 92 struct netconfig *nconf; 93 void *handle; 94 95 if ((handle = __rpc_setconf(nettype)) == NULL) { 96 printf("svc_create: unknown protocol"); 97 return (0); 98 } 99 while ((nconf = __rpc_getconf(handle)) != NULL) { 100 for (g = 0; g < SVC_MAXGROUPS; g++) { 101 grp = &pool->sp_groups[g]; 102 mtx_lock(&grp->sg_lock); 103 TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) { 104 if (strcmp(xprt->xp_netid, nconf->nc_netid)) 105 continue; 106 /* Found an old one, use it */ 107 mtx_unlock(&grp->sg_lock); 108 (void) rpcb_unset(prognum, versnum, nconf); 109 if (svc_reg(xprt, prognum, versnum, 110 dispatch, nconf) == FALSE) { 111 printf( 112 "svc_create: could not register prog %u vers %u on %s\n", 113 (unsigned)prognum, (unsigned)versnum, 114 nconf->nc_netid); 115 mtx_lock(&grp->sg_lock); 116 } else { 117 num++; 118 mtx_lock(&grp->sg_lock); 119 break; 120 } 121 } 122 mtx_unlock(&grp->sg_lock); 123 } 124 if (xprt == NULL) { 125 /* It was not found. Now create a new one */ 126 xprt = svc_tp_create(pool, dispatch, prognum, versnum, 127 NULL, nconf); 128 if (xprt) { 129 num++; 130 SVC_RELEASE(xprt); 131 } 132 } 133 } 134 __rpc_endconf(handle); 135 /* 136 * In case of num == 0; the error messages are generated by the 137 * underlying layers; and hence not needed here. 138 */ 139 return (num); 140 } 141 142 /* 143 * The high level interface to svc_tli_create(). 144 * It tries to create a server for "nconf" and registers the service 145 * with the rpcbind. It calls svc_tli_create(); 146 */ 147 SVCXPRT * 148 svc_tp_create( 149 SVCPOOL *pool, 150 void (*dispatch)(struct svc_req *, SVCXPRT *), 151 rpcprog_t prognum, /* Program number */ 152 rpcvers_t versnum, /* Version number */ 153 const char *uaddr, /* Address (or null for default) */ 154 const struct netconfig *nconf) /* Netconfig structure for the network */ 155 { 156 struct netconfig nconfcopy; 157 struct netbuf *taddr; 158 struct t_bind bind; 159 SVCXPRT *xprt; 160 161 if (nconf == NULL) { 162 printf( 163 "svc_tp_create: invalid netconfig structure for prog %u vers %u\n", 164 (unsigned)prognum, (unsigned)versnum); 165 return (NULL); 166 } 167 if (uaddr) { 168 taddr = uaddr2taddr(nconf, uaddr); 169 bind.addr = *taddr; 170 free(taddr, M_RPC); 171 bind.qlen = SOMAXCONN; 172 xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0); 173 free(bind.addr.buf, M_RPC); 174 } else { 175 xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0); 176 } 177 if (xprt == NULL) { 178 return (NULL); 179 } 180 /*LINTED const castaway*/ 181 nconfcopy = *nconf; 182 (void) rpcb_unset(prognum, versnum, &nconfcopy); 183 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 184 printf( 185 "svc_tp_create: Could not register prog %u vers %u on %s\n", 186 (unsigned)prognum, (unsigned)versnum, 187 nconf->nc_netid); 188 xprt_unregister(xprt); 189 SVC_RELEASE(xprt); 190 return (NULL); 191 } 192 return (xprt); 193 } 194 195 /* 196 * If so is NULL, then it opens a socket for the given transport 197 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 198 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 199 * NULL bindadr and Connection oriented transports, the value of qlen 200 * is set to 8. 201 * 202 * If sendsz or recvsz are zero, their default values are chosen. 203 */ 204 SVCXPRT * 205 svc_tli_create( 206 SVCPOOL *pool, 207 struct socket *so, /* Connection end point */ 208 const struct netconfig *nconf, /* Netconfig struct for nettoken */ 209 const struct t_bind *bindaddr, /* Local bind address */ 210 size_t sendsz, /* Max sendsize */ 211 size_t recvsz) /* Max recvsize */ 212 { 213 SVCXPRT *xprt = NULL; /* service handle */ 214 bool_t madeso = FALSE; /* whether so opened here */ 215 struct __rpc_sockinfo si; 216 struct sockaddr_storage ss; 217 218 if (!so) { 219 if (nconf == NULL) { 220 printf("svc_tli_create: invalid netconfig\n"); 221 return (NULL); 222 } 223 so = __rpc_nconf2socket(nconf); 224 if (!so) { 225 printf( 226 "svc_tli_create: could not open connection for %s\n", 227 nconf->nc_netid); 228 return (NULL); 229 } 230 __rpc_nconf2sockinfo(nconf, &si); 231 madeso = TRUE; 232 } else { 233 /* 234 * It is an open socket. Get the transport info. 235 */ 236 if (!__rpc_socket2sockinfo(so, &si)) { 237 printf( 238 "svc_tli_create: could not get transport information\n"); 239 return (NULL); 240 } 241 } 242 243 /* 244 * If the socket is unbound, try to bind it. 245 */ 246 if (madeso || !__rpc_sockisbound(so)) { 247 if (bindaddr == NULL) { 248 if (bindresvport(so, NULL)) { 249 memset(&ss, 0, sizeof ss); 250 ss.ss_family = si.si_af; 251 ss.ss_len = si.si_alen; 252 if (sobind(so, (struct sockaddr *)&ss, 253 curthread)) { 254 printf( 255 "svc_tli_create: could not bind to anonymous port\n"); 256 goto freedata; 257 } 258 } 259 solisten(so, SOMAXCONN, curthread); 260 } else { 261 if (bindresvport(so, 262 (struct sockaddr *)bindaddr->addr.buf)) { 263 printf( 264 "svc_tli_create: could not bind to requested address\n"); 265 goto freedata; 266 } 267 solisten(so, (int)bindaddr->qlen, curthread); 268 } 269 270 } 271 /* 272 * call transport specific function. 273 */ 274 switch (si.si_socktype) { 275 case SOCK_STREAM: 276 #if 0 277 slen = sizeof ss; 278 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 279 == 0) { 280 /* accepted socket */ 281 xprt = svc_fd_create(fd, sendsz, recvsz); 282 } else 283 #endif 284 xprt = svc_vc_create(pool, so, sendsz, recvsz); 285 if (!nconf || !xprt) 286 break; 287 #if 0 288 /* XXX fvdl */ 289 if (strcmp(nconf->nc_protofmly, "inet") == 0 || 290 strcmp(nconf->nc_protofmly, "inet6") == 0) 291 (void) __svc_vc_setflag(xprt, TRUE); 292 #endif 293 break; 294 case SOCK_DGRAM: 295 xprt = svc_dg_create(pool, so, sendsz, recvsz); 296 break; 297 default: 298 printf("svc_tli_create: bad service type"); 299 goto freedata; 300 } 301 302 if (xprt == NULL) 303 /* 304 * The error messages here are spitted out by the lower layers: 305 * svc_vc_create(), svc_fd_create() and svc_dg_create(). 306 */ 307 goto freedata; 308 309 /* Fill in type of service */ 310 xprt->xp_type = __rpc_socktype2seman(si.si_socktype); 311 312 if (nconf) { 313 xprt->xp_netid = strdup(nconf->nc_netid, M_RPC); 314 } 315 return (xprt); 316 317 freedata: 318 if (madeso) 319 (void)soclose(so); 320 if (xprt) { 321 if (!madeso) /* so that svc_destroy doesnt close fd */ 322 xprt->xp_socket = NULL; 323 xprt_unregister(xprt); 324 } 325 return (NULL); 326 } 327