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 /* 38 * svc_generic.c, Server side for RPC. 39 * 40 */ 41 42 #include "opt_inet6.h" 43 44 #include <sys/param.h> 45 #include <sys/lock.h> 46 #include <sys/kernel.h> 47 #include <sys/malloc.h> 48 #include <sys/mutex.h> 49 #include <sys/protosw.h> 50 #include <sys/queue.h> 51 #include <sys/socket.h> 52 #include <sys/socketvar.h> 53 #include <sys/systm.h> 54 #include <sys/sx.h> 55 #include <sys/ucred.h> 56 57 #include <net/vnet.h> 58 59 #include <rpc/rpc.h> 60 #include <rpc/rpcb_clnt.h> 61 #include <rpc/nettype.h> 62 63 #include <rpc/rpc_com.h> 64 65 extern int __svc_vc_setflag(SVCXPRT *, int); 66 67 /* 68 * The highest level interface for server creation. 69 * It tries for all the nettokens in that particular class of token 70 * and returns the number of handles it can create and/or find. 71 * 72 * It creates a link list of all the handles it could create. 73 * If svc_create() is called multiple times, it uses the handle 74 * created earlier instead of creating a new handle every time. 75 */ 76 int 77 svc_create( 78 SVCPOOL *pool, 79 void (*dispatch)(struct svc_req *, SVCXPRT *), 80 rpcprog_t prognum, /* Program number */ 81 rpcvers_t versnum, /* Version number */ 82 const char *nettype) /* Networktype token */ 83 { 84 int g, num = 0; 85 SVCGROUP *grp; 86 SVCXPRT *xprt; 87 struct netconfig *nconf; 88 void *handle; 89 90 if ((handle = __rpc_setconf(nettype)) == NULL) { 91 printf("svc_create: unknown protocol"); 92 return (0); 93 } 94 while ((nconf = __rpc_getconf(handle)) != NULL) { 95 for (g = 0; g < SVC_MAXGROUPS; g++) { 96 grp = &pool->sp_groups[g]; 97 mtx_lock(&grp->sg_lock); 98 TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) { 99 if (strcmp(xprt->xp_netid, nconf->nc_netid)) 100 continue; 101 /* Found an old one, use it */ 102 mtx_unlock(&grp->sg_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(&grp->sg_lock); 111 } else { 112 num++; 113 mtx_lock(&grp->sg_lock); 114 break; 115 } 116 } 117 mtx_unlock(&grp->sg_lock); 118 } 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 SVC_RELEASE(xprt); 126 } 127 } 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( 144 SVCPOOL *pool, 145 void (*dispatch)(struct svc_req *, SVCXPRT *), 146 rpcprog_t prognum, /* Program number */ 147 rpcvers_t versnum, /* Version number */ 148 const char *uaddr, /* Address (or null for default) */ 149 const struct netconfig *nconf) /* Netconfig structure for the network */ 150 { 151 struct netconfig nconfcopy; 152 struct netbuf *taddr; 153 struct t_bind bind; 154 SVCXPRT *xprt; 155 156 if (nconf == NULL) { 157 printf( 158 "svc_tp_create: invalid netconfig structure for prog %u vers %u\n", 159 (unsigned)prognum, (unsigned)versnum); 160 return (NULL); 161 } 162 if (uaddr) { 163 taddr = uaddr2taddr(nconf, uaddr); 164 bind.addr = *taddr; 165 free(taddr, M_RPC); 166 bind.qlen = -1; 167 xprt = svc_tli_create(pool, nconf, &bind, 0, 0); 168 free(bind.addr.buf, M_RPC); 169 } else { 170 xprt = svc_tli_create(pool, nconf, NULL, 0, 0); 171 } 172 if (xprt == NULL) { 173 return (NULL); 174 } 175 /*LINTED const castaway*/ 176 nconfcopy = *nconf; 177 (void) rpcb_unset(prognum, versnum, &nconfcopy); 178 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { 179 printf( 180 "svc_tp_create: Could not register prog %u vers %u on %s\n", 181 (unsigned)prognum, (unsigned)versnum, 182 nconf->nc_netid); 183 xprt_unregister(xprt); 184 SVC_RELEASE(xprt); 185 return (NULL); 186 } 187 return (xprt); 188 } 189 190 /* 191 * If so is NULL, then it opens a socket for the given transport 192 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and 193 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For 194 * NULL bindadr and Connection oriented transports, the value of qlen 195 * is set to 8. 196 * 197 * If sendsz or recvsz are zero, their default values are chosen. 198 */ 199 SVCXPRT * 200 svc_tli_create( 201 SVCPOOL *pool, 202 const struct netconfig *nconf, /* Netconfig struct for nettoken */ 203 const struct t_bind *bindaddr, /* Local bind address */ 204 size_t sendsz, /* Max sendsize */ 205 size_t recvsz) /* Max recvsize */ 206 { 207 struct socket *so; 208 SVCXPRT *xprt = NULL; /* service handle */ 209 struct __rpc_sockinfo si; 210 struct sockaddr_storage ss; 211 212 if (nconf == NULL) { 213 printf("svc_tli_create: invalid netconfig\n"); 214 return (NULL); 215 } 216 so = __rpc_nconf2socket(nconf); 217 if (!so) { 218 printf( 219 "svc_tli_create: could not open connection for %s\n", 220 nconf->nc_netid); 221 return (NULL); 222 } 223 __rpc_nconf2sockinfo(nconf, &si); 224 225 if (bindaddr == NULL) { 226 if (bindresvport(so, NULL)) { 227 memset(&ss, 0, sizeof ss); 228 ss.ss_family = si.si_af; 229 ss.ss_len = si.si_alen; 230 if (sobind(so, (struct sockaddr *)&ss, 231 curthread)) { 232 printf( 233 "svc_tli_create: could not bind to anonymous port\n"); 234 goto freedata; 235 } 236 } 237 solisten(so, -1, curthread); 238 } else { 239 if (bindresvport(so, 240 (struct sockaddr *)bindaddr->addr.buf)) { 241 printf( 242 "svc_tli_create: could not bind to requested address\n"); 243 goto freedata; 244 } 245 solisten(so, (int)bindaddr->qlen, curthread); 246 } 247 248 /* 249 * call transport specific function. 250 */ 251 switch (si.si_socktype) { 252 case SOCK_STREAM: 253 #if 0 254 slen = sizeof ss; 255 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) 256 == 0) { 257 /* accepted socket */ 258 xprt = svc_fd_create(fd, sendsz, recvsz); 259 } else 260 #endif 261 xprt = svc_vc_create(pool, so, 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(pool, so, sendsz, recvsz); 273 break; 274 default: 275 printf("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, M_RPC); 291 } 292 return (xprt); 293 294 freedata: 295 (void)soclose(so); 296 if (xprt) 297 xprt_unregister(xprt); 298 return (NULL); 299 } 300