1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 /* 28 * Portions of this source code were derived from Berkeley 29 * 4.3 BSD under license from the Regents of the University of 30 * California. 31 */ 32 33 /* 34 * svc_simple.c 35 * Simplified front end to rpc. 36 */ 37 38 /* 39 * This interface creates a virtual listener for all the services 40 * started thru rpc_reg(). It listens on the same endpoint for 41 * all the services and then executes the corresponding service 42 * for the given prognum and procnum. 43 */ 44 45 #include "mt.h" 46 #include "rpc_mt.h" 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <rpc/rpc.h> 52 #include <sys/types.h> 53 #include <syslog.h> 54 #include <rpc/nettype.h> 55 56 static struct proglst { 57 char *(*p_progname)(); 58 rpcprog_t p_prognum; 59 rpcvers_t p_versnum; 60 rpcproc_t p_procnum; 61 SVCXPRT *p_transp; 62 char *p_netid; 63 char *p_xdrbuf; 64 int p_recvsz; 65 xdrproc_t p_inproc, p_outproc; 66 struct proglst *p_nxt; 67 } *proglst; 68 69 static void universal(); 70 71 static const char rpc_reg_err[] = "%s: %s"; 72 static const char rpc_reg_msg[] = "rpc_reg: "; 73 static const char __reg_err1[] = "can't find appropriate transport"; 74 static const char __reg_err3[] = "unsupported transport size"; 75 static const char __no_mem_str[] = "out of memory"; 76 /* 77 * For simplified, easy to use kind of rpc interfaces. 78 * nettype indicates the type of transport on which the service will be 79 * listening. Used for conservation of the system resource. Only one 80 * handle is created for all the services (actually one of each netid) 81 * and same xdrbuf is used for same netid. The size of the arguments 82 * is also limited by the recvsize for that transport, even if it is 83 * a COTS transport. This may be wrong, but for cases like these, they 84 * should not use the simplified interfaces like this. 85 */ 86 87 int 88 rpc_reg(const rpcprog_t prognum, const rpcvers_t versnum, 89 const rpcproc_t procnum, char *(*progname)(), const xdrproc_t inproc, 90 const xdrproc_t outproc, const char *nettype) 91 { 92 struct netconfig *nconf; 93 int done = FALSE; 94 void *handle; 95 extern mutex_t proglst_lock; 96 97 if (procnum == NULLPROC) { 98 (void) syslog(LOG_ERR, (const char *) "%s: %s %d", 99 rpc_reg_msg, 100 (const char *) "can't reassign procedure number %d", 101 NULLPROC); 102 return (-1); 103 } 104 105 if (nettype == NULL) 106 nettype = "netpath"; /* The default behavior */ 107 if ((handle = __rpc_setconf((char *)nettype)) == NULL) { 108 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err1); 109 return (-1); 110 } 111 /* VARIABLES PROTECTED BY proglst_lock: proglst */ 112 (void) mutex_lock(&proglst_lock); 113 while (nconf = __rpc_getconf(handle)) { 114 struct proglst *pl; 115 SVCXPRT *svcxprt; 116 int madenow; 117 uint_t recvsz; 118 char *xdrbuf; 119 char *netid; 120 121 madenow = FALSE; 122 svcxprt = NULL; 123 for (pl = proglst; pl; pl = pl->p_nxt) 124 if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { 125 svcxprt = pl->p_transp; 126 xdrbuf = pl->p_xdrbuf; 127 recvsz = pl->p_recvsz; 128 netid = pl->p_netid; 129 break; 130 } 131 132 if (svcxprt == NULL) { 133 struct t_info tinfo; 134 135 svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 136 if (svcxprt == NULL) 137 continue; 138 if (t_getinfo(svcxprt->xp_fd, &tinfo) == -1) { 139 char errorstr[100]; 140 141 __tli_sys_strerror(errorstr, sizeof (errorstr), 142 t_errno, errno); 143 (void) syslog(LOG_ERR, "%s : %s : %s", 144 rpc_reg_msg, "t_getinfo failed", 145 errorstr); 146 SVC_DESTROY(svcxprt); 147 continue; 148 } 149 if ((recvsz = __rpc_get_t_size(0, tinfo.tsdu)) == 0) { 150 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 151 __reg_err3); 152 SVC_DESTROY(svcxprt); 153 continue; 154 } 155 if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || 156 ((netid = strdup(nconf->nc_netid)) == NULL)) { 157 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 158 __no_mem_str); 159 SVC_DESTROY(svcxprt); 160 break; 161 } 162 madenow = TRUE; 163 } 164 /* 165 * Check if this (program, version, netid) had already been 166 * registered. The check may save a few RPC calls to rpcbind 167 */ 168 for (pl = proglst; pl; pl = pl->p_nxt) 169 if ((pl->p_prognum == prognum) && 170 (pl->p_versnum == versnum) && 171 (strcmp(pl->p_netid, netid) == 0)) 172 break; 173 if (pl == NULL) { /* Not yet */ 174 (void) rpcb_unset(prognum, versnum, nconf); 175 } else { 176 /* so that svc_reg does not call rpcb_set() */ 177 nconf = NULL; 178 } 179 180 if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { 181 (void) syslog(LOG_ERR, 182 "%s couldn't register prog %d vers %d for %s", 183 rpc_reg_msg, prognum, versnum, netid); 184 if (madenow) { 185 SVC_DESTROY(svcxprt); 186 free(xdrbuf); 187 free(netid); 188 } 189 continue; 190 } 191 192 pl = malloc(sizeof (struct proglst)); 193 if (pl == NULL) { 194 (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, 195 __no_mem_str); 196 if (madenow) { 197 SVC_DESTROY(svcxprt); 198 free(xdrbuf); 199 free(netid); 200 } 201 break; 202 } 203 pl->p_progname = progname; 204 pl->p_prognum = prognum; 205 pl->p_versnum = versnum; 206 pl->p_procnum = procnum; 207 pl->p_inproc = inproc; 208 pl->p_outproc = outproc; 209 pl->p_transp = svcxprt; 210 pl->p_xdrbuf = xdrbuf; 211 pl->p_recvsz = recvsz; 212 pl->p_netid = netid; 213 pl->p_nxt = proglst; 214 proglst = pl; 215 done = TRUE; 216 } 217 __rpc_endconf(handle); 218 (void) mutex_unlock(&proglst_lock); 219 220 if (done == FALSE) { 221 (void) syslog(LOG_ERR, 222 (const char *) "%s cant find suitable transport for %s", 223 rpc_reg_msg, nettype); 224 return (-1); 225 } 226 return (0); 227 } 228 229 /* 230 * The universal handler for the services registered using registerrpc. 231 * It handles both the connectionless and the connection oriented cases. 232 */ 233 234 static void 235 universal(struct svc_req *rqstp, SVCXPRT *transp) 236 { 237 rpcprog_t prog; 238 rpcvers_t vers; 239 rpcproc_t proc; 240 char *outdata; 241 char *xdrbuf; 242 struct proglst *pl; 243 extern mutex_t proglst_lock; 244 245 /* 246 * enforce "procnum 0 is echo" convention 247 */ 248 if (rqstp->rq_proc == NULLPROC) { 249 if (svc_sendreply(transp, (xdrproc_t)xdr_void, NULL) == FALSE) { 250 (void) syslog(LOG_ERR, 251 (const char *) "svc_sendreply failed"); 252 } 253 return; 254 } 255 prog = rqstp->rq_prog; 256 vers = rqstp->rq_vers; 257 proc = rqstp->rq_proc; 258 (void) mutex_lock(&proglst_lock); 259 for (pl = proglst; pl; pl = pl->p_nxt) { 260 if (pl->p_prognum == prog && pl->p_procnum == proc && 261 pl->p_versnum == vers && 262 (strcmp(pl->p_netid, transp->xp_netid) == 0)) { 263 /* decode arguments into a CLEAN buffer */ 264 xdrbuf = pl->p_xdrbuf; 265 /* Zero the arguments: reqd ! */ 266 (void) memset(xdrbuf, 0, pl->p_recvsz); 267 /* 268 * Assuming that sizeof (xdrbuf) would be enough 269 * for the arguments; if not then the program 270 * may bomb. BEWARE! 271 */ 272 if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { 273 svcerr_decode(transp); 274 (void) mutex_unlock(&proglst_lock); 275 return; 276 } 277 outdata = (*(pl->p_progname))(xdrbuf); 278 if (outdata == NULL && 279 pl->p_outproc != (xdrproc_t)xdr_void) { 280 /* there was an error */ 281 (void) mutex_unlock(&proglst_lock); 282 return; 283 } 284 if (!svc_sendreply(transp, pl->p_outproc, outdata)) { 285 (void) syslog(LOG_ERR, (const char *) 286 "rpc: rpc_reg trouble replying to prog %d vers %d", 287 prog, vers); 288 (void) mutex_unlock(&proglst_lock); 289 return; 290 } 291 /* free the decoded arguments */ 292 (void) svc_freeargs(transp, pl->p_inproc, xdrbuf); 293 (void) mutex_unlock(&proglst_lock); 294 return; 295 } 296 } 297 (void) mutex_unlock(&proglst_lock); 298 /* This should never happen */ 299 (void) syslog(LOG_ERR, (const char *) 300 "rpc: rpc_reg: never registered prog %d vers %d", 301 prog, vers); 302 } 303