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