1/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */
| 1/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */
|
2/* $FreeBSD: head/lib/libc/rpc/clnt_dg.c 74462 2001-03-19 12:50:13Z alfred $ */
| 2/* $FreeBSD: head/lib/libc/rpc/clnt_dg.c 74879 2001-03-27 21:27:33Z wpaul $ */
|
3 4/* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32/* 33 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34 */ 35 36/* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 37 38#if 0 39#if !defined(lint) && defined(SCCSIDS) 40static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 41#endif 42#endif 43 44/* 45 * Implements a connectionless client side RPC. 46 */ 47 48#include "reentrant.h" 49#include "namespace.h" 50#include <sys/poll.h> 51#include <sys/types.h> 52#include <sys/time.h> 53#include <sys/socket.h> 54#include <sys/ioctl.h> 55#include <rpc/rpc.h> 56#include <errno.h> 57#include <stdlib.h> 58#include <string.h> 59#include <signal.h> 60#include <unistd.h> 61#include <err.h> 62#include "un-namespace.h" 63#include "rpc_com.h" 64 65 66#define RPC_MAX_BACKOFF 30 /* seconds */ 67 68 69static struct clnt_ops *clnt_dg_ops __P((void)); 70static bool_t time_not_ok __P((struct timeval *)); 71static enum clnt_stat clnt_dg_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 72 xdrproc_t, caddr_t, struct timeval)); 73static void clnt_dg_geterr __P((CLIENT *, struct rpc_err *)); 74static bool_t clnt_dg_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 75static void clnt_dg_abort __P((CLIENT *)); 76static bool_t clnt_dg_control __P((CLIENT *, u_int, char *)); 77static void clnt_dg_destroy __P((CLIENT *)); 78static int __rpc_timeval_to_msec __P((struct timeval *)); 79 80 81 82 83/* 84 * This machinery implements per-fd locks for MT-safety. It is not 85 * sufficient to do per-CLIENT handle locks for MT-safety because a 86 * user may create more than one CLIENT handle with the same fd behind 87 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 88 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 89 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 90 * CLIENT handle created for that fd. 91 * The current implementation holds locks across the entire RPC and reply, 92 * including retransmissions. Yes, this is silly, and as soon as this 93 * code is proven to work, this should be the first thing fixed. One step 94 * at a time. 95 */ 96static int *dg_fd_locks; 97extern mutex_t clnt_fd_lock; 98static cond_t *dg_cv; 99#define release_fd_lock(fd, mask) { \ 100 mutex_lock(&clnt_fd_lock); \ 101 if (__isthreaded) \ 102 dg_fd_locks[fd] = 0; \ 103 mutex_unlock(&clnt_fd_lock); \ 104 thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 105 cond_signal(&dg_cv[fd]); \ 106} 107 108static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 109 110/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 111 112/* 113 * Private data kept per client handle 114 */ 115struct cu_data { 116 int cu_fd; /* connections fd */ 117 bool_t cu_closeit; /* opened by library */ 118 struct sockaddr_storage cu_raddr; /* remote address */ 119 int cu_rlen; 120 struct timeval cu_wait; /* retransmit interval */ 121 struct timeval cu_total; /* total time for the call */ 122 struct rpc_err cu_error; 123 XDR cu_outxdrs; 124 u_int cu_xdrpos; 125 u_int cu_sendsz; /* send size */ 126 char *cu_outbuf; 127 u_int cu_recvsz; /* recv size */ 128 struct pollfd pfdp;
| 3 4/* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32/* 33 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34 */ 35 36/* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 37 38#if 0 39#if !defined(lint) && defined(SCCSIDS) 40static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 41#endif 42#endif 43 44/* 45 * Implements a connectionless client side RPC. 46 */ 47 48#include "reentrant.h" 49#include "namespace.h" 50#include <sys/poll.h> 51#include <sys/types.h> 52#include <sys/time.h> 53#include <sys/socket.h> 54#include <sys/ioctl.h> 55#include <rpc/rpc.h> 56#include <errno.h> 57#include <stdlib.h> 58#include <string.h> 59#include <signal.h> 60#include <unistd.h> 61#include <err.h> 62#include "un-namespace.h" 63#include "rpc_com.h" 64 65 66#define RPC_MAX_BACKOFF 30 /* seconds */ 67 68 69static struct clnt_ops *clnt_dg_ops __P((void)); 70static bool_t time_not_ok __P((struct timeval *)); 71static enum clnt_stat clnt_dg_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 72 xdrproc_t, caddr_t, struct timeval)); 73static void clnt_dg_geterr __P((CLIENT *, struct rpc_err *)); 74static bool_t clnt_dg_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 75static void clnt_dg_abort __P((CLIENT *)); 76static bool_t clnt_dg_control __P((CLIENT *, u_int, char *)); 77static void clnt_dg_destroy __P((CLIENT *)); 78static int __rpc_timeval_to_msec __P((struct timeval *)); 79 80 81 82 83/* 84 * This machinery implements per-fd locks for MT-safety. It is not 85 * sufficient to do per-CLIENT handle locks for MT-safety because a 86 * user may create more than one CLIENT handle with the same fd behind 87 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 88 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 89 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 90 * CLIENT handle created for that fd. 91 * The current implementation holds locks across the entire RPC and reply, 92 * including retransmissions. Yes, this is silly, and as soon as this 93 * code is proven to work, this should be the first thing fixed. One step 94 * at a time. 95 */ 96static int *dg_fd_locks; 97extern mutex_t clnt_fd_lock; 98static cond_t *dg_cv; 99#define release_fd_lock(fd, mask) { \ 100 mutex_lock(&clnt_fd_lock); \ 101 if (__isthreaded) \ 102 dg_fd_locks[fd] = 0; \ 103 mutex_unlock(&clnt_fd_lock); \ 104 thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 105 cond_signal(&dg_cv[fd]); \ 106} 107 108static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 109 110/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 111 112/* 113 * Private data kept per client handle 114 */ 115struct cu_data { 116 int cu_fd; /* connections fd */ 117 bool_t cu_closeit; /* opened by library */ 118 struct sockaddr_storage cu_raddr; /* remote address */ 119 int cu_rlen; 120 struct timeval cu_wait; /* retransmit interval */ 121 struct timeval cu_total; /* total time for the call */ 122 struct rpc_err cu_error; 123 XDR cu_outxdrs; 124 u_int cu_xdrpos; 125 u_int cu_sendsz; /* send size */ 126 char *cu_outbuf; 127 u_int cu_recvsz; /* recv size */ 128 struct pollfd pfdp;
|
| 129 int cu_async;
|
129 char cu_inbuf[1]; 130}; 131 132/* 133 * Connection less client creation returns with client handle parameters. 134 * Default options are set, which the user can change using clnt_control(). 135 * fd should be open and bound. 136 * NB: The rpch->cl_auth is initialized to null authentication. 137 * Caller may wish to set this something more useful. 138 * 139 * sendsz and recvsz are the maximum allowable packet sizes that can be 140 * sent and received. Normally they are the same, but they can be 141 * changed to improve the program efficiency and buffer allocation. 142 * If they are 0, use the transport default. 143 * 144 * If svcaddr is NULL, returns NULL. 145 */ 146CLIENT * 147clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 148 int fd; /* open file descriptor */ 149 const struct netbuf *svcaddr; /* servers address */ 150 rpcprog_t program; /* program number */ 151 rpcvers_t version; /* version number */ 152 u_int sendsz; /* buffer recv size */ 153 u_int recvsz; /* buffer send size */ 154{ 155 CLIENT *cl = NULL; /* client handle */ 156 struct cu_data *cu = NULL; /* private data */ 157 struct timeval now; 158 struct rpc_msg call_msg; 159 sigset_t mask; 160 sigset_t newmask; 161 struct __rpc_sockinfo si; 162 int one = 1; 163 164 sigfillset(&newmask); 165 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 166 mutex_lock(&clnt_fd_lock); 167 if (dg_fd_locks == (int *) NULL) { 168 int cv_allocsz; 169 size_t fd_allocsz; 170 int dtbsize = __rpc_dtbsize(); 171 172 fd_allocsz = dtbsize * sizeof (int); 173 dg_fd_locks = (int *) mem_alloc(fd_allocsz); 174 if (dg_fd_locks == (int *) NULL) { 175 mutex_unlock(&clnt_fd_lock); 176 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 177 goto err1; 178 } else 179 memset(dg_fd_locks, '\0', fd_allocsz); 180 181 cv_allocsz = dtbsize * sizeof (cond_t); 182 dg_cv = (cond_t *) mem_alloc(cv_allocsz); 183 if (dg_cv == (cond_t *) NULL) { 184 mem_free(dg_fd_locks, fd_allocsz); 185 dg_fd_locks = (int *) NULL; 186 mutex_unlock(&clnt_fd_lock); 187 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 188 goto err1; 189 } else { 190 int i; 191 192 for (i = 0; i < dtbsize; i++) 193 cond_init(&dg_cv[i], 0, (void *) 0); 194 } 195 } 196 197 mutex_unlock(&clnt_fd_lock); 198 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 199 200 if (svcaddr == NULL) { 201 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 202 return (NULL); 203 } 204 205 if (!__rpc_fd2sockinfo(fd, &si)) { 206 rpc_createerr.cf_stat = RPC_TLIERROR; 207 rpc_createerr.cf_error.re_errno = 0; 208 return (NULL); 209 } 210 /* 211 * Find the receive and the send size 212 */ 213 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 214 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 215 if ((sendsz == 0) || (recvsz == 0)) { 216 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 217 rpc_createerr.cf_error.re_errno = 0; 218 return (NULL); 219 } 220 221 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 222 goto err1; 223 /* 224 * Should be multiple of 4 for XDR. 225 */ 226 sendsz = ((sendsz + 3) / 4) * 4; 227 recvsz = ((recvsz + 3) / 4) * 4; 228 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 229 if (cu == NULL) 230 goto err1; 231 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 232 cu->cu_rlen = svcaddr->len; 233 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 234 /* Other values can also be set through clnt_control() */ 235 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 236 cu->cu_wait.tv_usec = 0; 237 cu->cu_total.tv_sec = -1; 238 cu->cu_total.tv_usec = -1; 239 cu->cu_sendsz = sendsz; 240 cu->cu_recvsz = recvsz;
| 130 char cu_inbuf[1]; 131}; 132 133/* 134 * Connection less client creation returns with client handle parameters. 135 * Default options are set, which the user can change using clnt_control(). 136 * fd should be open and bound. 137 * NB: The rpch->cl_auth is initialized to null authentication. 138 * Caller may wish to set this something more useful. 139 * 140 * sendsz and recvsz are the maximum allowable packet sizes that can be 141 * sent and received. Normally they are the same, but they can be 142 * changed to improve the program efficiency and buffer allocation. 143 * If they are 0, use the transport default. 144 * 145 * If svcaddr is NULL, returns NULL. 146 */ 147CLIENT * 148clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 149 int fd; /* open file descriptor */ 150 const struct netbuf *svcaddr; /* servers address */ 151 rpcprog_t program; /* program number */ 152 rpcvers_t version; /* version number */ 153 u_int sendsz; /* buffer recv size */ 154 u_int recvsz; /* buffer send size */ 155{ 156 CLIENT *cl = NULL; /* client handle */ 157 struct cu_data *cu = NULL; /* private data */ 158 struct timeval now; 159 struct rpc_msg call_msg; 160 sigset_t mask; 161 sigset_t newmask; 162 struct __rpc_sockinfo si; 163 int one = 1; 164 165 sigfillset(&newmask); 166 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 167 mutex_lock(&clnt_fd_lock); 168 if (dg_fd_locks == (int *) NULL) { 169 int cv_allocsz; 170 size_t fd_allocsz; 171 int dtbsize = __rpc_dtbsize(); 172 173 fd_allocsz = dtbsize * sizeof (int); 174 dg_fd_locks = (int *) mem_alloc(fd_allocsz); 175 if (dg_fd_locks == (int *) NULL) { 176 mutex_unlock(&clnt_fd_lock); 177 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 178 goto err1; 179 } else 180 memset(dg_fd_locks, '\0', fd_allocsz); 181 182 cv_allocsz = dtbsize * sizeof (cond_t); 183 dg_cv = (cond_t *) mem_alloc(cv_allocsz); 184 if (dg_cv == (cond_t *) NULL) { 185 mem_free(dg_fd_locks, fd_allocsz); 186 dg_fd_locks = (int *) NULL; 187 mutex_unlock(&clnt_fd_lock); 188 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 189 goto err1; 190 } else { 191 int i; 192 193 for (i = 0; i < dtbsize; i++) 194 cond_init(&dg_cv[i], 0, (void *) 0); 195 } 196 } 197 198 mutex_unlock(&clnt_fd_lock); 199 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 200 201 if (svcaddr == NULL) { 202 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 203 return (NULL); 204 } 205 206 if (!__rpc_fd2sockinfo(fd, &si)) { 207 rpc_createerr.cf_stat = RPC_TLIERROR; 208 rpc_createerr.cf_error.re_errno = 0; 209 return (NULL); 210 } 211 /* 212 * Find the receive and the send size 213 */ 214 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 215 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 216 if ((sendsz == 0) || (recvsz == 0)) { 217 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 218 rpc_createerr.cf_error.re_errno = 0; 219 return (NULL); 220 } 221 222 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 223 goto err1; 224 /* 225 * Should be multiple of 4 for XDR. 226 */ 227 sendsz = ((sendsz + 3) / 4) * 4; 228 recvsz = ((recvsz + 3) / 4) * 4; 229 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 230 if (cu == NULL) 231 goto err1; 232 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 233 cu->cu_rlen = svcaddr->len; 234 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 235 /* Other values can also be set through clnt_control() */ 236 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 237 cu->cu_wait.tv_usec = 0; 238 cu->cu_total.tv_sec = -1; 239 cu->cu_total.tv_usec = -1; 240 cu->cu_sendsz = sendsz; 241 cu->cu_recvsz = recvsz;
|
| 242 cu->cu_async = FALSE;
|
241 (void) gettimeofday(&now, NULL); 242 call_msg.rm_xid = __RPC_GETXID(&now); 243 call_msg.rm_call.cb_prog = program; 244 call_msg.rm_call.cb_vers = version; 245 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 246 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 247 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 248 rpc_createerr.cf_error.re_errno = 0; 249 goto err2; 250 } 251 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 252 253 /* XXX fvdl - do we still want this? */ 254#if 0 255 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 256#endif 257 _ioctl(fd, FIONBIO, (char *)(void *)&one); 258 259 /* 260 * By default, closeit is always FALSE. It is users responsibility 261 * to do a close on it, else the user may use clnt_control 262 * to let clnt_destroy do it for him/her. 263 */ 264 cu->cu_closeit = FALSE; 265 cu->cu_fd = fd; 266 cl->cl_ops = clnt_dg_ops(); 267 cl->cl_private = (caddr_t)(void *)cu; 268 cl->cl_auth = authnone_create(); 269 cl->cl_tp = NULL; 270 cl->cl_netid = NULL; 271 cu->pfdp.fd = cu->cu_fd; 272 cu->pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 273 return (cl); 274err1: 275 warnx(mem_err_clnt_dg); 276 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 277 rpc_createerr.cf_error.re_errno = errno; 278err2: 279 if (cl) { 280 mem_free(cl, sizeof (CLIENT)); 281 if (cu) 282 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 283 } 284 return (NULL); 285} 286 287static enum clnt_stat 288clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 289 CLIENT *cl; /* client handle */ 290 rpcproc_t proc; /* procedure number */ 291 xdrproc_t xargs; /* xdr routine for args */ 292 caddr_t argsp; /* pointer to args */ 293 xdrproc_t xresults; /* xdr routine for results */ 294 caddr_t resultsp; /* pointer to results */ 295 struct timeval utimeout; /* seconds to wait before giving up */ 296{ 297 struct cu_data *cu = (struct cu_data *)cl->cl_private; 298 XDR *xdrs; 299 size_t outlen; 300 struct rpc_msg reply_msg; 301 XDR reply_xdrs; 302 struct timeval time_waited; 303 bool_t ok; 304 int nrefreshes = 2; /* number of times to refresh cred */ 305 struct timeval timeout; 306 struct timeval retransmit_time; 307 struct timeval startime, curtime; 308 int firsttimeout = 1; 309 int dtbsize = __rpc_dtbsize(); 310 sigset_t mask; 311 sigset_t newmask; 312 socklen_t fromlen, inlen; 313 ssize_t recvlen = 0; 314 int rpc_lock_value;
| 243 (void) gettimeofday(&now, NULL); 244 call_msg.rm_xid = __RPC_GETXID(&now); 245 call_msg.rm_call.cb_prog = program; 246 call_msg.rm_call.cb_vers = version; 247 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 248 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 249 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 250 rpc_createerr.cf_error.re_errno = 0; 251 goto err2; 252 } 253 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 254 255 /* XXX fvdl - do we still want this? */ 256#if 0 257 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 258#endif 259 _ioctl(fd, FIONBIO, (char *)(void *)&one); 260 261 /* 262 * By default, closeit is always FALSE. It is users responsibility 263 * to do a close on it, else the user may use clnt_control 264 * to let clnt_destroy do it for him/her. 265 */ 266 cu->cu_closeit = FALSE; 267 cu->cu_fd = fd; 268 cl->cl_ops = clnt_dg_ops(); 269 cl->cl_private = (caddr_t)(void *)cu; 270 cl->cl_auth = authnone_create(); 271 cl->cl_tp = NULL; 272 cl->cl_netid = NULL; 273 cu->pfdp.fd = cu->cu_fd; 274 cu->pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 275 return (cl); 276err1: 277 warnx(mem_err_clnt_dg); 278 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 279 rpc_createerr.cf_error.re_errno = errno; 280err2: 281 if (cl) { 282 mem_free(cl, sizeof (CLIENT)); 283 if (cu) 284 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 285 } 286 return (NULL); 287} 288 289static enum clnt_stat 290clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 291 CLIENT *cl; /* client handle */ 292 rpcproc_t proc; /* procedure number */ 293 xdrproc_t xargs; /* xdr routine for args */ 294 caddr_t argsp; /* pointer to args */ 295 xdrproc_t xresults; /* xdr routine for results */ 296 caddr_t resultsp; /* pointer to results */ 297 struct timeval utimeout; /* seconds to wait before giving up */ 298{ 299 struct cu_data *cu = (struct cu_data *)cl->cl_private; 300 XDR *xdrs; 301 size_t outlen; 302 struct rpc_msg reply_msg; 303 XDR reply_xdrs; 304 struct timeval time_waited; 305 bool_t ok; 306 int nrefreshes = 2; /* number of times to refresh cred */ 307 struct timeval timeout; 308 struct timeval retransmit_time; 309 struct timeval startime, curtime; 310 int firsttimeout = 1; 311 int dtbsize = __rpc_dtbsize(); 312 sigset_t mask; 313 sigset_t newmask; 314 socklen_t fromlen, inlen; 315 ssize_t recvlen = 0; 316 int rpc_lock_value;
|
| 317 u_int32_t xid;
|
315 316 sigfillset(&newmask); 317 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 318 mutex_lock(&clnt_fd_lock); 319 while (dg_fd_locks[cu->cu_fd]) 320 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 321 if (__isthreaded) 322 rpc_lock_value = 1; 323 else 324 rpc_lock_value = 0; 325 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 326 mutex_unlock(&clnt_fd_lock); 327 if (cu->cu_total.tv_usec == -1) { 328 timeout = utimeout; /* use supplied timeout */ 329 } else { 330 timeout = cu->cu_total; /* use default timeout */ 331 } 332 333 time_waited.tv_sec = 0; 334 time_waited.tv_usec = 0; 335 retransmit_time = cu->cu_wait; 336 337call_again: 338 xdrs = &(cu->cu_outxdrs);
| 318 319 sigfillset(&newmask); 320 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 321 mutex_lock(&clnt_fd_lock); 322 while (dg_fd_locks[cu->cu_fd]) 323 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 324 if (__isthreaded) 325 rpc_lock_value = 1; 326 else 327 rpc_lock_value = 0; 328 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 329 mutex_unlock(&clnt_fd_lock); 330 if (cu->cu_total.tv_usec == -1) { 331 timeout = utimeout; /* use supplied timeout */ 332 } else { 333 timeout = cu->cu_total; /* use default timeout */ 334 } 335 336 time_waited.tv_sec = 0; 337 time_waited.tv_usec = 0; 338 retransmit_time = cu->cu_wait; 339 340call_again: 341 xdrs = &(cu->cu_outxdrs);
|
| 342 if (cu->cu_async == TRUE && xargs == NULL) 343 goto get_reply;
|
339 xdrs->x_op = XDR_ENCODE; 340 XDR_SETPOS(xdrs, cu->cu_xdrpos); 341 /* 342 * the transaction is the first thing in the out buffer
| 344 xdrs->x_op = XDR_ENCODE; 345 XDR_SETPOS(xdrs, cu->cu_xdrpos); 346 /* 347 * the transaction is the first thing in the out buffer
|
| 348 * XXX Yes, and it's in network byte order, so we should to 349 * be careful when we increment it, shouldn't we.
|
343 */
| 350 */
|
344 (*(u_int32_t *)(void *)(cu->cu_outbuf))++;
| 351 xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); 352 xid++; 353 *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); 354
|
345 if ((! XDR_PUTINT32(xdrs, &proc)) || 346 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 347 (! (*xargs)(xdrs, argsp))) { 348 release_fd_lock(cu->cu_fd, mask); 349 return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 350 } 351 outlen = (size_t)XDR_GETPOS(xdrs); 352 353send_again: 354 if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, 355 (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) 356 != outlen) { 357 cu->cu_error.re_errno = errno; 358 release_fd_lock(cu->cu_fd, mask); 359 return (cu->cu_error.re_status = RPC_CANTSEND); 360 } 361 362 /* 363 * Hack to provide rpc-based message passing 364 */ 365 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 366 release_fd_lock(cu->cu_fd, mask); 367 return (cu->cu_error.re_status = RPC_TIMEDOUT); 368 }
| 355 if ((! XDR_PUTINT32(xdrs, &proc)) || 356 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 357 (! (*xargs)(xdrs, argsp))) { 358 release_fd_lock(cu->cu_fd, mask); 359 return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 360 } 361 outlen = (size_t)XDR_GETPOS(xdrs); 362 363send_again: 364 if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, 365 (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) 366 != outlen) { 367 cu->cu_error.re_errno = errno; 368 release_fd_lock(cu->cu_fd, mask); 369 return (cu->cu_error.re_status = RPC_CANTSEND); 370 } 371 372 /* 373 * Hack to provide rpc-based message passing 374 */ 375 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 376 release_fd_lock(cu->cu_fd, mask); 377 return (cu->cu_error.re_status = RPC_TIMEDOUT); 378 }
|
| 379 380get_reply: 381
|
369 /* 370 * sub-optimal code appears here because we have 371 * some clock time to spare while the packets are in flight. 372 * (We assume that this is actually only executed once.) 373 */ 374 reply_msg.acpted_rply.ar_verf = _null_auth; 375 reply_msg.acpted_rply.ar_results.where = resultsp; 376 reply_msg.acpted_rply.ar_results.proc = xresults; 377 378 379 for (;;) { 380 switch (_poll(&cu->pfdp, 1, 381 __rpc_timeval_to_msec(&retransmit_time))) { 382 case 0: 383 time_waited.tv_sec += retransmit_time.tv_sec; 384 time_waited.tv_usec += retransmit_time.tv_usec; 385 while (time_waited.tv_usec >= 1000000) { 386 time_waited.tv_sec++; 387 time_waited.tv_usec -= 1000000; 388 } 389 /* update retransmit_time */ 390 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) { 391 retransmit_time.tv_usec *= 2; 392 retransmit_time.tv_sec *= 2; 393 while (retransmit_time.tv_usec >= 1000000) { 394 retransmit_time.tv_sec++; 395 retransmit_time.tv_usec -= 1000000; 396 } 397 } 398 399 if ((time_waited.tv_sec < timeout.tv_sec) || 400 ((time_waited.tv_sec == timeout.tv_sec) && 401 (time_waited.tv_usec < timeout.tv_usec))) 402 goto send_again; 403 release_fd_lock(cu->cu_fd, mask); 404 return (cu->cu_error.re_status = RPC_TIMEDOUT); 405 406 case -1: 407 if (errno == EBADF) { 408 cu->cu_error.re_errno = errno; 409 release_fd_lock(cu->cu_fd, mask); 410 return (cu->cu_error.re_status = RPC_CANTRECV); 411 } 412 if (errno != EINTR) { 413 errno = 0; /* reset it */ 414 continue; 415 } 416 /* interrupted by another signal, update time_waited */ 417 if (firsttimeout) { 418 /* 419 * Could have done gettimeofday before clnt_call 420 * but that means 1 more system call per each 421 * clnt_call, so do it after first time out 422 */ 423 if (gettimeofday(&startime, 424 (struct timezone *) NULL) == -1) { 425 errno = 0; 426 continue; 427 } 428 firsttimeout = 0; 429 errno = 0; 430 continue; 431 }; 432 if (gettimeofday(&curtime, 433 (struct timezone *) NULL) == -1) { 434 errno = 0; 435 continue; 436 }; 437 time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; 438 time_waited.tv_usec += curtime.tv_usec - 439 startime.tv_usec; 440 while (time_waited.tv_usec < 0) { 441 time_waited.tv_sec--; 442 time_waited.tv_usec += 1000000; 443 }; 444 while (time_waited.tv_usec >= 1000000) { 445 time_waited.tv_sec++; 446 time_waited.tv_usec -= 1000000; 447 } 448 startime.tv_sec = curtime.tv_sec; 449 startime.tv_usec = curtime.tv_usec; 450 if ((time_waited.tv_sec > timeout.tv_sec) || 451 ((time_waited.tv_sec == timeout.tv_sec) && 452 (time_waited.tv_usec > timeout.tv_usec))) { 453 release_fd_lock(cu->cu_fd, mask); 454 return (cu->cu_error.re_status = RPC_TIMEDOUT); 455 } 456 errno = 0; /* reset it */ 457 continue; 458 }; 459 460 if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { 461 cu->cu_error.re_status = RPC_CANTRECV; 462 /* 463 * Note: we're faking errno here because we 464 * previously would have expected _poll() to 465 * return -1 with errno EBADF. Poll(BA_OS) 466 * returns 0 and sets the POLLNVAL revents flag 467 * instead. 468 */ 469 cu->cu_error.re_errno = errno = EBADF; 470 release_fd_lock(cu->cu_fd, mask); 471 return (-1); 472 } 473 474 /* We have some data now */ 475 do { 476 if (errno == EINTR) { 477 /* 478 * Must make sure errno was not already 479 * EINTR in case _recvfrom() returns -1. 480 */ 481 errno = 0; 482 } 483 fromlen = sizeof (struct sockaddr_storage); 484 recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, 485 cu->cu_recvsz, 0, (struct sockaddr *)(void *)&cu->cu_raddr, 486 &fromlen); 487 } while (recvlen < 0 && errno == EINTR); 488 if (recvlen < 0) { 489 if (errno == EWOULDBLOCK) 490 continue; 491 cu->cu_error.re_errno = errno; 492 release_fd_lock(cu->cu_fd, mask); 493 return (cu->cu_error.re_status = RPC_CANTRECV); 494 } 495 if (recvlen < sizeof (u_int32_t)) 496 continue; 497 /* see if reply transaction id matches sent id */
| 382 /* 383 * sub-optimal code appears here because we have 384 * some clock time to spare while the packets are in flight. 385 * (We assume that this is actually only executed once.) 386 */ 387 reply_msg.acpted_rply.ar_verf = _null_auth; 388 reply_msg.acpted_rply.ar_results.where = resultsp; 389 reply_msg.acpted_rply.ar_results.proc = xresults; 390 391 392 for (;;) { 393 switch (_poll(&cu->pfdp, 1, 394 __rpc_timeval_to_msec(&retransmit_time))) { 395 case 0: 396 time_waited.tv_sec += retransmit_time.tv_sec; 397 time_waited.tv_usec += retransmit_time.tv_usec; 398 while (time_waited.tv_usec >= 1000000) { 399 time_waited.tv_sec++; 400 time_waited.tv_usec -= 1000000; 401 } 402 /* update retransmit_time */ 403 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) { 404 retransmit_time.tv_usec *= 2; 405 retransmit_time.tv_sec *= 2; 406 while (retransmit_time.tv_usec >= 1000000) { 407 retransmit_time.tv_sec++; 408 retransmit_time.tv_usec -= 1000000; 409 } 410 } 411 412 if ((time_waited.tv_sec < timeout.tv_sec) || 413 ((time_waited.tv_sec == timeout.tv_sec) && 414 (time_waited.tv_usec < timeout.tv_usec))) 415 goto send_again; 416 release_fd_lock(cu->cu_fd, mask); 417 return (cu->cu_error.re_status = RPC_TIMEDOUT); 418 419 case -1: 420 if (errno == EBADF) { 421 cu->cu_error.re_errno = errno; 422 release_fd_lock(cu->cu_fd, mask); 423 return (cu->cu_error.re_status = RPC_CANTRECV); 424 } 425 if (errno != EINTR) { 426 errno = 0; /* reset it */ 427 continue; 428 } 429 /* interrupted by another signal, update time_waited */ 430 if (firsttimeout) { 431 /* 432 * Could have done gettimeofday before clnt_call 433 * but that means 1 more system call per each 434 * clnt_call, so do it after first time out 435 */ 436 if (gettimeofday(&startime, 437 (struct timezone *) NULL) == -1) { 438 errno = 0; 439 continue; 440 } 441 firsttimeout = 0; 442 errno = 0; 443 continue; 444 }; 445 if (gettimeofday(&curtime, 446 (struct timezone *) NULL) == -1) { 447 errno = 0; 448 continue; 449 }; 450 time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; 451 time_waited.tv_usec += curtime.tv_usec - 452 startime.tv_usec; 453 while (time_waited.tv_usec < 0) { 454 time_waited.tv_sec--; 455 time_waited.tv_usec += 1000000; 456 }; 457 while (time_waited.tv_usec >= 1000000) { 458 time_waited.tv_sec++; 459 time_waited.tv_usec -= 1000000; 460 } 461 startime.tv_sec = curtime.tv_sec; 462 startime.tv_usec = curtime.tv_usec; 463 if ((time_waited.tv_sec > timeout.tv_sec) || 464 ((time_waited.tv_sec == timeout.tv_sec) && 465 (time_waited.tv_usec > timeout.tv_usec))) { 466 release_fd_lock(cu->cu_fd, mask); 467 return (cu->cu_error.re_status = RPC_TIMEDOUT); 468 } 469 errno = 0; /* reset it */ 470 continue; 471 }; 472 473 if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { 474 cu->cu_error.re_status = RPC_CANTRECV; 475 /* 476 * Note: we're faking errno here because we 477 * previously would have expected _poll() to 478 * return -1 with errno EBADF. Poll(BA_OS) 479 * returns 0 and sets the POLLNVAL revents flag 480 * instead. 481 */ 482 cu->cu_error.re_errno = errno = EBADF; 483 release_fd_lock(cu->cu_fd, mask); 484 return (-1); 485 } 486 487 /* We have some data now */ 488 do { 489 if (errno == EINTR) { 490 /* 491 * Must make sure errno was not already 492 * EINTR in case _recvfrom() returns -1. 493 */ 494 errno = 0; 495 } 496 fromlen = sizeof (struct sockaddr_storage); 497 recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, 498 cu->cu_recvsz, 0, (struct sockaddr *)(void *)&cu->cu_raddr, 499 &fromlen); 500 } while (recvlen < 0 && errno == EINTR); 501 if (recvlen < 0) { 502 if (errno == EWOULDBLOCK) 503 continue; 504 cu->cu_error.re_errno = errno; 505 release_fd_lock(cu->cu_fd, mask); 506 return (cu->cu_error.re_status = RPC_CANTRECV); 507 } 508 if (recvlen < sizeof (u_int32_t)) 509 continue; 510 /* see if reply transaction id matches sent id */
|
498 if (*((u_int32_t *)(void *)(cu->cu_inbuf)) !=
| 511 if (cu->cu_async == FALSE && 512 *((u_int32_t *)(void *)(cu->cu_inbuf)) !=
|
499 *((u_int32_t *)(void *)(cu->cu_outbuf))) 500 continue; 501 /* we now assume we have the proper reply */ 502 break; 503 } 504 inlen = (socklen_t)recvlen; 505 506 /* 507 * now decode and validate the response 508 */ 509 510 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 511 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 512 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 513 if (ok) { 514 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 515 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 516 cu->cu_error.re_status = RPC_SUCCESS; 517 else 518 _seterr_reply(&reply_msg, &(cu->cu_error)); 519 520 if (cu->cu_error.re_status == RPC_SUCCESS) { 521 if (! AUTH_VALIDATE(cl->cl_auth, 522 &reply_msg.acpted_rply.ar_verf)) { 523 cu->cu_error.re_status = RPC_AUTHERROR; 524 cu->cu_error.re_why = AUTH_INVALIDRESP; 525 } 526 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 527 xdrs->x_op = XDR_FREE; 528 (void) xdr_opaque_auth(xdrs, 529 &(reply_msg.acpted_rply.ar_verf)); 530 } 531 } /* end successful completion */ 532 /* 533 * If unsuccesful AND error is an authentication error 534 * then refresh credentials and try again, else break 535 */ 536 else if (cu->cu_error.re_status == RPC_AUTHERROR) 537 /* maybe our credentials need to be refreshed ... */ 538 if (nrefreshes > 0 && 539 AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 540 nrefreshes--; 541 goto call_again; 542 } 543 /* end of unsuccessful completion */ 544 } /* end of valid reply message */ 545 else { 546 cu->cu_error.re_status = RPC_CANTDECODERES; 547 548 } 549 release_fd_lock(cu->cu_fd, mask); 550 return (cu->cu_error.re_status); 551} 552 553static void 554clnt_dg_geterr(cl, errp) 555 CLIENT *cl; 556 struct rpc_err *errp; 557{ 558 struct cu_data *cu = (struct cu_data *)cl->cl_private; 559 560 *errp = cu->cu_error; 561} 562 563static bool_t 564clnt_dg_freeres(cl, xdr_res, res_ptr) 565 CLIENT *cl; 566 xdrproc_t xdr_res; 567 caddr_t res_ptr; 568{ 569 struct cu_data *cu = (struct cu_data *)cl->cl_private; 570 XDR *xdrs = &(cu->cu_outxdrs); 571 bool_t dummy; 572 sigset_t mask; 573 sigset_t newmask; 574 575 sigfillset(&newmask); 576 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 577 mutex_lock(&clnt_fd_lock); 578 while (dg_fd_locks[cu->cu_fd]) 579 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 580 xdrs->x_op = XDR_FREE; 581 dummy = (*xdr_res)(xdrs, res_ptr); 582 mutex_unlock(&clnt_fd_lock); 583 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 584 cond_signal(&dg_cv[cu->cu_fd]); 585 return (dummy); 586} 587 588/*ARGSUSED*/ 589static void 590clnt_dg_abort(h) 591 CLIENT *h; 592{ 593} 594 595static bool_t 596clnt_dg_control(cl, request, info) 597 CLIENT *cl; 598 u_int request; 599 char *info; 600{ 601 struct cu_data *cu = (struct cu_data *)cl->cl_private; 602 struct netbuf *addr; 603 sigset_t mask; 604 sigset_t newmask; 605 int rpc_lock_value; 606 607 sigfillset(&newmask); 608 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 609 mutex_lock(&clnt_fd_lock); 610 while (dg_fd_locks[cu->cu_fd]) 611 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 612 if (__isthreaded) 613 rpc_lock_value = 1; 614 else 615 rpc_lock_value = 0; 616 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 617 mutex_unlock(&clnt_fd_lock); 618 switch (request) { 619 case CLSET_FD_CLOSE: 620 cu->cu_closeit = TRUE; 621 release_fd_lock(cu->cu_fd, mask); 622 return (TRUE); 623 case CLSET_FD_NCLOSE: 624 cu->cu_closeit = FALSE; 625 release_fd_lock(cu->cu_fd, mask); 626 return (TRUE); 627 } 628 629 /* for other requests which use info */ 630 if (info == NULL) { 631 release_fd_lock(cu->cu_fd, mask); 632 return (FALSE); 633 } 634 switch (request) { 635 case CLSET_TIMEOUT: 636 if (time_not_ok((struct timeval *)(void *)info)) { 637 release_fd_lock(cu->cu_fd, mask); 638 return (FALSE); 639 } 640 cu->cu_total = *(struct timeval *)(void *)info; 641 break; 642 case CLGET_TIMEOUT: 643 *(struct timeval *)(void *)info = cu->cu_total; 644 break; 645 case CLGET_SERVER_ADDR: /* Give him the fd address */ 646 /* Now obsolete. Only for backward compatibility */ 647 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 648 break; 649 case CLSET_RETRY_TIMEOUT: 650 if (time_not_ok((struct timeval *)(void *)info)) { 651 release_fd_lock(cu->cu_fd, mask); 652 return (FALSE); 653 } 654 cu->cu_wait = *(struct timeval *)(void *)info; 655 break; 656 case CLGET_RETRY_TIMEOUT: 657 *(struct timeval *)(void *)info = cu->cu_wait; 658 break; 659 case CLGET_FD: 660 *(int *)(void *)info = cu->cu_fd; 661 break; 662 case CLGET_SVC_ADDR: 663 addr = (struct netbuf *)(void *)info; 664 addr->buf = &cu->cu_raddr; 665 addr->len = cu->cu_rlen; 666 addr->maxlen = sizeof cu->cu_raddr; 667 break; 668 case CLSET_SVC_ADDR: /* set to new address */ 669 addr = (struct netbuf *)(void *)info; 670 if (addr->len < sizeof cu->cu_raddr) 671 return (FALSE); 672 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 673 cu->cu_rlen = addr->len; 674 break; 675 case CLGET_XID: 676 /* 677 * use the knowledge that xid is the 678 * first element in the call structure *. 679 * This will get the xid of the PREVIOUS call 680 */ 681 *(u_int32_t *)(void *)info = 682 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 683 break; 684 685 case CLSET_XID: 686 /* This will set the xid of the NEXT call */ 687 *(u_int32_t *)(void *)cu->cu_outbuf = 688 htonl(*(u_int32_t *)(void *)info - 1); 689 /* decrement by 1 as clnt_dg_call() increments once */ 690 break; 691 692 case CLGET_VERS: 693 /* 694 * This RELIES on the information that, in the call body, 695 * the version number field is the fifth field from the 696 * begining of the RPC header. MUST be changed if the 697 * call_struct is changed 698 */ 699 *(u_int32_t *)(void *)info = 700 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 701 4 * BYTES_PER_XDR_UNIT)); 702 break; 703 704 case CLSET_VERS: 705 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 706 = htonl(*(u_int32_t *)(void *)info); 707 break; 708 709 case CLGET_PROG: 710 /* 711 * This RELIES on the information that, in the call body, 712 * the program number field is the fourth field from the 713 * begining of the RPC header. MUST be changed if the 714 * call_struct is changed 715 */ 716 *(u_int32_t *)(void *)info = 717 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 718 3 * BYTES_PER_XDR_UNIT)); 719 break; 720 721 case CLSET_PROG: 722 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 723 = htonl(*(u_int32_t *)(void *)info); 724 break;
| 513 *((u_int32_t *)(void *)(cu->cu_outbuf))) 514 continue; 515 /* we now assume we have the proper reply */ 516 break; 517 } 518 inlen = (socklen_t)recvlen; 519 520 /* 521 * now decode and validate the response 522 */ 523 524 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 525 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 526 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 527 if (ok) { 528 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 529 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 530 cu->cu_error.re_status = RPC_SUCCESS; 531 else 532 _seterr_reply(&reply_msg, &(cu->cu_error)); 533 534 if (cu->cu_error.re_status == RPC_SUCCESS) { 535 if (! AUTH_VALIDATE(cl->cl_auth, 536 &reply_msg.acpted_rply.ar_verf)) { 537 cu->cu_error.re_status = RPC_AUTHERROR; 538 cu->cu_error.re_why = AUTH_INVALIDRESP; 539 } 540 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 541 xdrs->x_op = XDR_FREE; 542 (void) xdr_opaque_auth(xdrs, 543 &(reply_msg.acpted_rply.ar_verf)); 544 } 545 } /* end successful completion */ 546 /* 547 * If unsuccesful AND error is an authentication error 548 * then refresh credentials and try again, else break 549 */ 550 else if (cu->cu_error.re_status == RPC_AUTHERROR) 551 /* maybe our credentials need to be refreshed ... */ 552 if (nrefreshes > 0 && 553 AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 554 nrefreshes--; 555 goto call_again; 556 } 557 /* end of unsuccessful completion */ 558 } /* end of valid reply message */ 559 else { 560 cu->cu_error.re_status = RPC_CANTDECODERES; 561 562 } 563 release_fd_lock(cu->cu_fd, mask); 564 return (cu->cu_error.re_status); 565} 566 567static void 568clnt_dg_geterr(cl, errp) 569 CLIENT *cl; 570 struct rpc_err *errp; 571{ 572 struct cu_data *cu = (struct cu_data *)cl->cl_private; 573 574 *errp = cu->cu_error; 575} 576 577static bool_t 578clnt_dg_freeres(cl, xdr_res, res_ptr) 579 CLIENT *cl; 580 xdrproc_t xdr_res; 581 caddr_t res_ptr; 582{ 583 struct cu_data *cu = (struct cu_data *)cl->cl_private; 584 XDR *xdrs = &(cu->cu_outxdrs); 585 bool_t dummy; 586 sigset_t mask; 587 sigset_t newmask; 588 589 sigfillset(&newmask); 590 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 591 mutex_lock(&clnt_fd_lock); 592 while (dg_fd_locks[cu->cu_fd]) 593 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 594 xdrs->x_op = XDR_FREE; 595 dummy = (*xdr_res)(xdrs, res_ptr); 596 mutex_unlock(&clnt_fd_lock); 597 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 598 cond_signal(&dg_cv[cu->cu_fd]); 599 return (dummy); 600} 601 602/*ARGSUSED*/ 603static void 604clnt_dg_abort(h) 605 CLIENT *h; 606{ 607} 608 609static bool_t 610clnt_dg_control(cl, request, info) 611 CLIENT *cl; 612 u_int request; 613 char *info; 614{ 615 struct cu_data *cu = (struct cu_data *)cl->cl_private; 616 struct netbuf *addr; 617 sigset_t mask; 618 sigset_t newmask; 619 int rpc_lock_value; 620 621 sigfillset(&newmask); 622 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 623 mutex_lock(&clnt_fd_lock); 624 while (dg_fd_locks[cu->cu_fd]) 625 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 626 if (__isthreaded) 627 rpc_lock_value = 1; 628 else 629 rpc_lock_value = 0; 630 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 631 mutex_unlock(&clnt_fd_lock); 632 switch (request) { 633 case CLSET_FD_CLOSE: 634 cu->cu_closeit = TRUE; 635 release_fd_lock(cu->cu_fd, mask); 636 return (TRUE); 637 case CLSET_FD_NCLOSE: 638 cu->cu_closeit = FALSE; 639 release_fd_lock(cu->cu_fd, mask); 640 return (TRUE); 641 } 642 643 /* for other requests which use info */ 644 if (info == NULL) { 645 release_fd_lock(cu->cu_fd, mask); 646 return (FALSE); 647 } 648 switch (request) { 649 case CLSET_TIMEOUT: 650 if (time_not_ok((struct timeval *)(void *)info)) { 651 release_fd_lock(cu->cu_fd, mask); 652 return (FALSE); 653 } 654 cu->cu_total = *(struct timeval *)(void *)info; 655 break; 656 case CLGET_TIMEOUT: 657 *(struct timeval *)(void *)info = cu->cu_total; 658 break; 659 case CLGET_SERVER_ADDR: /* Give him the fd address */ 660 /* Now obsolete. Only for backward compatibility */ 661 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 662 break; 663 case CLSET_RETRY_TIMEOUT: 664 if (time_not_ok((struct timeval *)(void *)info)) { 665 release_fd_lock(cu->cu_fd, mask); 666 return (FALSE); 667 } 668 cu->cu_wait = *(struct timeval *)(void *)info; 669 break; 670 case CLGET_RETRY_TIMEOUT: 671 *(struct timeval *)(void *)info = cu->cu_wait; 672 break; 673 case CLGET_FD: 674 *(int *)(void *)info = cu->cu_fd; 675 break; 676 case CLGET_SVC_ADDR: 677 addr = (struct netbuf *)(void *)info; 678 addr->buf = &cu->cu_raddr; 679 addr->len = cu->cu_rlen; 680 addr->maxlen = sizeof cu->cu_raddr; 681 break; 682 case CLSET_SVC_ADDR: /* set to new address */ 683 addr = (struct netbuf *)(void *)info; 684 if (addr->len < sizeof cu->cu_raddr) 685 return (FALSE); 686 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 687 cu->cu_rlen = addr->len; 688 break; 689 case CLGET_XID: 690 /* 691 * use the knowledge that xid is the 692 * first element in the call structure *. 693 * This will get the xid of the PREVIOUS call 694 */ 695 *(u_int32_t *)(void *)info = 696 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 697 break; 698 699 case CLSET_XID: 700 /* This will set the xid of the NEXT call */ 701 *(u_int32_t *)(void *)cu->cu_outbuf = 702 htonl(*(u_int32_t *)(void *)info - 1); 703 /* decrement by 1 as clnt_dg_call() increments once */ 704 break; 705 706 case CLGET_VERS: 707 /* 708 * This RELIES on the information that, in the call body, 709 * the version number field is the fifth field from the 710 * begining of the RPC header. MUST be changed if the 711 * call_struct is changed 712 */ 713 *(u_int32_t *)(void *)info = 714 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 715 4 * BYTES_PER_XDR_UNIT)); 716 break; 717 718 case CLSET_VERS: 719 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 720 = htonl(*(u_int32_t *)(void *)info); 721 break; 722 723 case CLGET_PROG: 724 /* 725 * This RELIES on the information that, in the call body, 726 * the program number field is the fourth field from the 727 * begining of the RPC header. MUST be changed if the 728 * call_struct is changed 729 */ 730 *(u_int32_t *)(void *)info = 731 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 732 3 * BYTES_PER_XDR_UNIT)); 733 break; 734 735 case CLSET_PROG: 736 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 737 = htonl(*(u_int32_t *)(void *)info); 738 break;
|
725
| 739 case CLSET_ASYNC: 740 cu->cu_async = *(int *)(void *)info; 741 break;
|
726 default: 727 release_fd_lock(cu->cu_fd, mask); 728 return (FALSE); 729 } 730 release_fd_lock(cu->cu_fd, mask); 731 return (TRUE); 732} 733 734static void 735clnt_dg_destroy(cl) 736 CLIENT *cl; 737{ 738 struct cu_data *cu = (struct cu_data *)cl->cl_private; 739 int cu_fd = cu->cu_fd; 740 sigset_t mask; 741 sigset_t newmask; 742 743 sigfillset(&newmask); 744 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 745 mutex_lock(&clnt_fd_lock); 746 while (dg_fd_locks[cu_fd]) 747 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 748 if (cu->cu_closeit) 749 (void)_close(cu_fd); 750 XDR_DESTROY(&(cu->cu_outxdrs)); 751 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 752 if (cl->cl_netid && cl->cl_netid[0]) 753 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 754 if (cl->cl_tp && cl->cl_tp[0]) 755 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 756 mem_free(cl, sizeof (CLIENT)); 757 mutex_unlock(&clnt_fd_lock); 758 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 759 cond_signal(&dg_cv[cu_fd]); 760} 761 762static struct clnt_ops * 763clnt_dg_ops() 764{ 765 static struct clnt_ops ops; 766 extern mutex_t ops_lock; 767 sigset_t mask; 768 sigset_t newmask; 769 770/* VARIABLES PROTECTED BY ops_lock: ops */ 771 772 sigfillset(&newmask); 773 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 774 mutex_lock(&ops_lock); 775 if (ops.cl_call == NULL) { 776 ops.cl_call = clnt_dg_call; 777 ops.cl_abort = clnt_dg_abort; 778 ops.cl_geterr = clnt_dg_geterr; 779 ops.cl_freeres = clnt_dg_freeres; 780 ops.cl_destroy = clnt_dg_destroy; 781 ops.cl_control = clnt_dg_control; 782 } 783 mutex_unlock(&ops_lock); 784 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 785 return (&ops); 786} 787 788/* 789 * Make sure that the time is not garbage. -1 value is allowed. 790 */ 791static bool_t 792time_not_ok(t) 793 struct timeval *t; 794{ 795 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 796 t->tv_usec < -1 || t->tv_usec > 1000000); 797} 798 799 800/* 801 * Convert from timevals (used by select) to milliseconds (used by poll). 802 */ 803static int 804__rpc_timeval_to_msec(t) 805 struct timeval *t; 806{ 807 int t1, tmp; 808 809 /* 810 * We're really returning t->tv_sec * 1000 + (t->tv_usec / 1000) 811 * but try to do so efficiently. Note: 1000 = 1024 - 16 - 8. 812 */ 813 tmp = (int)t->tv_sec << 3; 814 t1 = -tmp; 815 t1 += t1 << 1; 816 t1 += tmp << 7; 817 if (t->tv_usec) 818 t1 += (int)(t->tv_usec / 1000); 819 820 return (t1); 821}
| 742 default: 743 release_fd_lock(cu->cu_fd, mask); 744 return (FALSE); 745 } 746 release_fd_lock(cu->cu_fd, mask); 747 return (TRUE); 748} 749 750static void 751clnt_dg_destroy(cl) 752 CLIENT *cl; 753{ 754 struct cu_data *cu = (struct cu_data *)cl->cl_private; 755 int cu_fd = cu->cu_fd; 756 sigset_t mask; 757 sigset_t newmask; 758 759 sigfillset(&newmask); 760 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 761 mutex_lock(&clnt_fd_lock); 762 while (dg_fd_locks[cu_fd]) 763 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 764 if (cu->cu_closeit) 765 (void)_close(cu_fd); 766 XDR_DESTROY(&(cu->cu_outxdrs)); 767 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 768 if (cl->cl_netid && cl->cl_netid[0]) 769 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 770 if (cl->cl_tp && cl->cl_tp[0]) 771 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 772 mem_free(cl, sizeof (CLIENT)); 773 mutex_unlock(&clnt_fd_lock); 774 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 775 cond_signal(&dg_cv[cu_fd]); 776} 777 778static struct clnt_ops * 779clnt_dg_ops() 780{ 781 static struct clnt_ops ops; 782 extern mutex_t ops_lock; 783 sigset_t mask; 784 sigset_t newmask; 785 786/* VARIABLES PROTECTED BY ops_lock: ops */ 787 788 sigfillset(&newmask); 789 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 790 mutex_lock(&ops_lock); 791 if (ops.cl_call == NULL) { 792 ops.cl_call = clnt_dg_call; 793 ops.cl_abort = clnt_dg_abort; 794 ops.cl_geterr = clnt_dg_geterr; 795 ops.cl_freeres = clnt_dg_freeres; 796 ops.cl_destroy = clnt_dg_destroy; 797 ops.cl_control = clnt_dg_control; 798 } 799 mutex_unlock(&ops_lock); 800 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 801 return (&ops); 802} 803 804/* 805 * Make sure that the time is not garbage. -1 value is allowed. 806 */ 807static bool_t 808time_not_ok(t) 809 struct timeval *t; 810{ 811 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 812 t->tv_usec < -1 || t->tv_usec > 1000000); 813} 814 815 816/* 817 * Convert from timevals (used by select) to milliseconds (used by poll). 818 */ 819static int 820__rpc_timeval_to_msec(t) 821 struct timeval *t; 822{ 823 int t1, tmp; 824 825 /* 826 * We're really returning t->tv_sec * 1000 + (t->tv_usec / 1000) 827 * but try to do so efficiently. Note: 1000 = 1024 - 16 - 8. 828 */ 829 tmp = (int)t->tv_sec << 3; 830 t1 = -tmp; 831 t1 += t1 << 1; 832 t1 += tmp << 7; 833 if (t->tv_usec) 834 t1 += (int)(t->tv_usec / 1000); 835 836 return (t1); 837}
|