1/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 2 3/* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or --- 24 unchanged lines hidden (view full) --- 33 */ 34 35/* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 36 37#if !defined(lint) && defined(SCCSIDS) 38static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 39#endif 40#include <sys/cdefs.h> |
41__FBSDID("$FreeBSD: head/lib/libc/rpc/clnt_dg.c 105189 2002-10-15 22:28:59Z iedowse $"); |
42 43/* 44 * Implements a connectionless client side RPC. 45 */ 46 47#include "namespace.h" 48#include "reentrant.h" |
49#include <sys/types.h> |
50#include <sys/event.h> |
51#include <sys/time.h> 52#include <sys/socket.h> 53#include <sys/ioctl.h> 54#include <arpa/inet.h> 55#include <rpc/rpc.h> 56#include <errno.h> 57#include <stdlib.h> 58#include <string.h> --- 11 unchanged lines hidden (view full) --- 70static bool_t time_not_ok(struct timeval *); 71static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 72 xdrproc_t, void *, struct timeval); 73static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 74static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 75static void clnt_dg_abort(CLIENT *); 76static bool_t clnt_dg_control(CLIENT *, u_int, void *); 77static void clnt_dg_destroy(CLIENT *); |
78 79 80 81 82/* 83 * This machinery implements per-fd locks for MT-safety. It is not 84 * sufficient to do per-CLIENT handle locks for MT-safety because a 85 * user may create more than one CLIENT handle with the same fd behind --- 8 unchanged lines hidden (view full) --- 94 */ 95static int *dg_fd_locks; 96extern mutex_t clnt_fd_lock; 97static cond_t *dg_cv; 98#define release_fd_lock(fd, mask) { \ 99 mutex_lock(&clnt_fd_lock); \ 100 dg_fd_locks[fd] = 0; \ 101 mutex_unlock(&clnt_fd_lock); \ |
102 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ |
103 cond_signal(&dg_cv[fd]); \ 104} 105 106static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 107 108/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 109 110/* --- 7 unchanged lines hidden (view full) --- 118 struct timeval cu_wait; /* retransmit interval */ 119 struct timeval cu_total; /* total time for the call */ 120 struct rpc_err cu_error; 121 XDR cu_outxdrs; 122 u_int cu_xdrpos; 123 u_int cu_sendsz; /* send size */ 124 char *cu_outbuf; 125 u_int cu_recvsz; /* recv size */ |
126 int cu_async; 127 int cu_connect; /* Use connect(). */ 128 int cu_connected; /* Have done connect(). */ |
129 struct kevent cu_kin; 130 int cu_kq; |
131 char cu_inbuf[1]; 132}; 133 134/* 135 * Connection less client creation returns with client handle parameters. 136 * Default options are set, which the user can change using clnt_control(). 137 * fd should be open and bound. 138 * NB: The rpch->cl_auth is initialized to null authentication. --- 129 unchanged lines hidden (view full) --- 268 */ 269 cu->cu_closeit = FALSE; 270 cu->cu_fd = fd; 271 cl->cl_ops = clnt_dg_ops(); 272 cl->cl_private = (caddr_t)(void *)cu; 273 cl->cl_auth = authnone_create(); 274 cl->cl_tp = NULL; 275 cl->cl_netid = NULL; |
276 cu->cu_kq = -1; 277 EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); |
278 return (cl); 279err1: 280 warnx(mem_err_clnt_dg); 281 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 282 rpc_createerr.cf_error.re_errno = errno; 283err2: 284 if (cl) { 285 mem_free(cl, sizeof (CLIENT)); --- 10 unchanged lines hidden (view full) --- 296 xdrproc_t xargs; /* xdr routine for args */ 297 void *argsp; /* pointer to args */ 298 xdrproc_t xresults; /* xdr routine for results */ 299 void *resultsp; /* pointer to results */ 300 struct timeval utimeout; /* seconds to wait before giving up */ 301{ 302 struct cu_data *cu = (struct cu_data *)cl->cl_private; 303 XDR *xdrs; |
304 size_t outlen = 0; |
305 struct rpc_msg reply_msg; 306 XDR reply_xdrs; |
307 bool_t ok; 308 int nrefreshes = 2; /* number of times to refresh cred */ 309 struct timeval timeout; 310 struct timeval retransmit_time; |
311 struct timeval next_sendtime, starttime, time_waited, tv; 312 struct timespec ts; 313 struct kevent kv; |
314 struct sockaddr *sa; 315 sigset_t mask; 316 sigset_t newmask; 317 socklen_t inlen, salen; 318 ssize_t recvlen = 0; |
319 int kin_len, n, rpc_lock_value; |
320 u_int32_t xid; 321 322 outlen = 0; 323 sigfillset(&newmask); 324 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 325 mutex_lock(&clnt_fd_lock); 326 while (dg_fd_locks[cu->cu_fd]) 327 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); --- 7 unchanged lines hidden (view full) --- 335 timeout = utimeout; /* use supplied timeout */ 336 } else { 337 timeout = cu->cu_total; /* use default timeout */ 338 } 339 340 if (cu->cu_connect && !cu->cu_connected) { 341 if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, 342 cu->cu_rlen) < 0) { |
343 cu->cu_error.re_errno = errno; |
344 cu->cu_error.re_status = RPC_CANTSEND; 345 goto out; |
346 } 347 cu->cu_connected = 1; 348 } 349 if (cu->cu_connected) { 350 sa = NULL; 351 salen = 0; 352 } else { 353 sa = (struct sockaddr *)&cu->cu_raddr; 354 salen = cu->cu_rlen; 355 } 356 time_waited.tv_sec = 0; 357 time_waited.tv_usec = 0; |
358 retransmit_time = next_sendtime = cu->cu_wait; 359 gettimeofday(&starttime, NULL); |
360 |
361 /* Clean up in case the last call ended in a longjmp(3) call. */ 362 if (cu->cu_kq >= 0) 363 _close(cu->cu_kq); 364 if ((cu->cu_kq = kqueue()) < 0) { 365 cu->cu_error.re_errno = errno; 366 cu->cu_error.re_status = RPC_CANTSEND; 367 goto out; 368 } 369 kin_len = 1; 370 |
371call_again: 372 xdrs = &(cu->cu_outxdrs); 373 if (cu->cu_async == TRUE && xargs == NULL) 374 goto get_reply; 375 xdrs->x_op = XDR_ENCODE; 376 XDR_SETPOS(xdrs, cu->cu_xdrpos); 377 /* 378 * the transaction is the first thing in the out buffer 379 * XXX Yes, and it's in network byte order, so we should to 380 * be careful when we increment it, shouldn't we. 381 */ 382 xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); 383 xid++; 384 *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); 385 386 if ((! XDR_PUTINT32(xdrs, &proc)) || 387 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 388 (! (*xargs)(xdrs, argsp))) { |
389 cu->cu_error.re_status = RPC_CANTENCODEARGS; 390 goto out; |
391 } 392 outlen = (size_t)XDR_GETPOS(xdrs); 393 394send_again: 395 if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { 396 cu->cu_error.re_errno = errno; |
397 cu->cu_error.re_status = RPC_CANTSEND; 398 goto out; |
399 } 400 401 /* 402 * Hack to provide rpc-based message passing 403 */ 404 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { |
405 cu->cu_error.re_status = RPC_TIMEDOUT; 406 goto out; |
407 } 408 409get_reply: 410 411 /* 412 * sub-optimal code appears here because we have 413 * some clock time to spare while the packets are in flight. 414 * (We assume that this is actually only executed once.) 415 */ 416 reply_msg.acpted_rply.ar_verf = _null_auth; 417 reply_msg.acpted_rply.ar_results.where = resultsp; 418 reply_msg.acpted_rply.ar_results.proc = xresults; 419 |
420 for (;;) { |
421 /* Decide how long to wait. */ 422 if (timercmp(&next_sendtime, &timeout, <)) 423 timersub(&next_sendtime, &time_waited, &tv); 424 else 425 timersub(&timeout, &time_waited, &tv); 426 if (tv.tv_sec < 0 || tv.tv_usec < 0) 427 tv.tv_sec = tv.tv_usec = 0; 428 TIMEVAL_TO_TIMESPEC(&tv, &ts); |
429 |
430 n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts); 431 /* We don't need to register the event again. */ 432 kin_len = 0; |
433 |
434 if (n == 1) { 435 if (kv.flags & EV_ERROR) { 436 cu->cu_error.re_errno = kv.data; 437 cu->cu_error.re_status = RPC_CANTRECV; 438 goto out; 439 } 440 /* We have some data now */ 441 do { 442 recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, 443 cu->cu_recvsz, 0, NULL, NULL); 444 } while (recvlen < 0 && errno == EINTR); 445 if (recvlen < 0 && errno != EWOULDBLOCK) { |
446 cu->cu_error.re_errno = errno; |
447 cu->cu_error.re_status = RPC_CANTRECV; 448 goto out; |
449 } |
450 if (recvlen >= sizeof(u_int32_t) && 451 (cu->cu_async == TRUE || 452 *((u_int32_t *)(void *)(cu->cu_inbuf)) == 453 *((u_int32_t *)(void *)(cu->cu_outbuf)))) { 454 /* We now assume we have the proper reply. */ 455 break; |
456 } |
457 } 458 if (n == -1 && errno != EINTR) { 459 cu->cu_error.re_errno = errno; |
460 cu->cu_error.re_status = RPC_CANTRECV; |
461 goto out; |
462 } |
463 gettimeofday(&tv, NULL); 464 timersub(&tv, &starttime, &time_waited); |
465 |
466 /* Check for timeout. */ 467 if (timercmp(&time_waited, &timeout, >)) { 468 cu->cu_error.re_status = RPC_TIMEDOUT; 469 goto out; |
470 } |
471 472 /* Retransmit if necessary. */ 473 if (timercmp(&time_waited, &next_sendtime, >)) { 474 /* update retransmit_time */ 475 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 476 timeradd(&retransmit_time, &retransmit_time, 477 &retransmit_time); 478 timeradd(&next_sendtime, &retransmit_time, 479 &next_sendtime); 480 goto send_again; 481 } |
482 } 483 inlen = (socklen_t)recvlen; 484 485 /* 486 * now decode and validate the response 487 */ 488 489 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); --- 30 unchanged lines hidden (view full) --- 520 goto call_again; 521 } 522 /* end of unsuccessful completion */ 523 } /* end of valid reply message */ 524 else { 525 cu->cu_error.re_status = RPC_CANTDECODERES; 526 527 } |
528out: 529 if (cu->cu_kq >= 0) 530 _close(cu->cu_kq); 531 cu->cu_kq = -1; |
532 release_fd_lock(cu->cu_fd, mask); 533 return (cu->cu_error.re_status); 534} 535 536static void 537clnt_dg_geterr(cl, errp) 538 CLIENT *cl; 539 struct rpc_err *errp; --- 192 unchanged lines hidden (view full) --- 732 733 sigfillset(&newmask); 734 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 735 mutex_lock(&clnt_fd_lock); 736 while (dg_fd_locks[cu_fd]) 737 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 738 if (cu->cu_closeit) 739 (void)_close(cu_fd); |
740 if (cu->cu_kq >= 0) 741 _close(cu->cu_kq); |
742 XDR_DESTROY(&(cu->cu_outxdrs)); 743 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 744 if (cl->cl_netid && cl->cl_netid[0]) 745 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 746 if (cl->cl_tp && cl->cl_tp[0]) 747 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 748 mem_free(cl, sizeof (CLIENT)); 749 mutex_unlock(&clnt_fd_lock); --- 33 unchanged lines hidden (view full) --- 783static bool_t 784time_not_ok(t) 785 struct timeval *t; 786{ 787 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 788 t->tv_usec < -1 || t->tv_usec > 1000000); 789} 790 |