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