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