PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

lib/libc/rpc/clnt_vc.c

http://www.minix3.org/
C | 783 lines | 571 code | 78 blank | 134 comment | 97 complexity | b1359a57da779185e1d9f8b85d254302 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: clnt_vc.c,v 1.17 2010/12/08 02:06:38 joerg Exp $ */
  2. /*
  3. * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  4. * unrestricted use provided that this legend is included on all tape
  5. * media and as a part of the software program in whole or part. Users
  6. * may copy or modify Sun RPC without charge, but are not authorized
  7. * to license or distribute it to anyone else except as part of a product or
  8. * program developed by the user.
  9. *
  10. * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  11. * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12. * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  13. *
  14. * Sun RPC is provided with no support and without any obligation on the
  15. * part of Sun Microsystems, Inc. to assist in its use, correction,
  16. * modification or enhancement.
  17. *
  18. * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  19. * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  20. * OR ANY PART THEREOF.
  21. *
  22. * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  23. * or profits or other special, indirect and consequential damages, even if
  24. * Sun has been advised of the possibility of such damages.
  25. *
  26. * Sun Microsystems, Inc.
  27. * 2550 Garcia Avenue
  28. * Mountain View, California 94043
  29. */
  30. #include <sys/cdefs.h>
  31. #if defined(LIBC_SCCS) && !defined(lint)
  32. #if 0
  33. static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
  34. static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
  35. static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
  36. #else
  37. __RCSID("$NetBSD: clnt_vc.c,v 1.17 2010/12/08 02:06:38 joerg Exp $");
  38. #endif
  39. #endif
  40. /*
  41. * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
  42. *
  43. * Copyright (C) 1984, Sun Microsystems, Inc.
  44. *
  45. * TCP based RPC supports 'batched calls'.
  46. * A sequence of calls may be batched-up in a send buffer. The rpc call
  47. * return immediately to the client even though the call was not necessarily
  48. * sent. The batching occurs if the results' xdr routine is NULL (0) AND
  49. * the rpc timeout value is zero (see clnt.h, rpc).
  50. *
  51. * Clients should NOT casually batch calls that in fact return results; that is,
  52. * the server side should be aware that a call is batched and not produce any
  53. * return message. Batched calls that produce many result messages can
  54. * deadlock (netlock) the client and the server....
  55. *
  56. * Now go hang yourself.
  57. */
  58. #include "namespace.h"
  59. #include "reentrant.h"
  60. #include <sys/types.h>
  61. #include <sys/poll.h>
  62. #include <sys/socket.h>
  63. #include <assert.h>
  64. #include <err.h>
  65. #include <errno.h>
  66. #include <netdb.h>
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <unistd.h>
  71. #include <signal.h>
  72. #include <rpc/rpc.h>
  73. #include "rpc_internal.h"
  74. #ifdef __weak_alias
  75. __weak_alias(clnt_vc_create,_clnt_vc_create)
  76. #endif
  77. #define MCALL_MSG_SIZE 24
  78. static enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t,
  79. const char *, xdrproc_t, caddr_t, struct timeval));
  80. static void clnt_vc_geterr __P((CLIENT *, struct rpc_err *));
  81. static bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t));
  82. static void clnt_vc_abort __P((CLIENT *));
  83. static bool_t clnt_vc_control __P((CLIENT *, u_int, char *));
  84. static void clnt_vc_destroy __P((CLIENT *));
  85. static struct clnt_ops *clnt_vc_ops __P((void));
  86. static bool_t time_not_ok __P((struct timeval *));
  87. static int read_vc __P((caddr_t, caddr_t, int));
  88. static int write_vc __P((caddr_t, caddr_t, int));
  89. struct ct_data {
  90. int ct_fd;
  91. bool_t ct_closeit;
  92. struct timeval ct_wait;
  93. bool_t ct_waitset; /* wait set by clnt_control? */
  94. struct netbuf ct_addr;
  95. struct rpc_err ct_error;
  96. union {
  97. char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
  98. u_int32_t ct_mcalli;
  99. } ct_u;
  100. u_int ct_mpos; /* pos after marshal */
  101. XDR ct_xdrs;
  102. };
  103. /*
  104. * This machinery implements per-fd locks for MT-safety. It is not
  105. * sufficient to do per-CLIENT handle locks for MT-safety because a
  106. * user may create more than one CLIENT handle with the same fd behind
  107. * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
  108. * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
  109. * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some
  110. * CLIENT handle created for that fd.
  111. * The current implementation holds locks across the entire RPC and reply.
  112. * Yes, this is silly, and as soon as this code is proven to work, this
  113. * should be the first thing fixed. One step at a time.
  114. */
  115. #ifdef _REENTRANT
  116. static int *vc_fd_locks;
  117. #define __rpc_lock_value __isthreaded;
  118. extern mutex_t clnt_fd_lock;
  119. static cond_t *vc_cv;
  120. #define release_fd_lock(fd, mask) { \
  121. mutex_lock(&clnt_fd_lock); \
  122. vc_fd_locks[fd] = 0; \
  123. mutex_unlock(&clnt_fd_lock); \
  124. thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
  125. cond_signal(&vc_cv[fd]); \
  126. }
  127. #else
  128. #define release_fd_lock(fd,mask)
  129. #define __rpc_lock_value 0
  130. #endif
  131. /*
  132. * Create a client handle for a connection.
  133. * Default options are set, which the user can change using clnt_control()'s.
  134. * The rpc/vc package does buffering similar to stdio, so the client
  135. * must pick send and receive buffer sizes, 0 => use the default.
  136. * NB: fd is copied into a private area.
  137. * NB: The rpch->cl_auth is set null authentication. Caller may wish to
  138. * set this something more useful.
  139. *
  140. * fd should be an open socket
  141. */
  142. CLIENT *
  143. clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz)
  144. int fd;
  145. const struct netbuf *raddr;
  146. rpcprog_t prog;
  147. rpcvers_t vers;
  148. u_int sendsz;
  149. u_int recvsz;
  150. {
  151. CLIENT *h;
  152. struct ct_data *ct = NULL;
  153. struct rpc_msg call_msg;
  154. #ifdef _REENTRANT
  155. sigset_t mask;
  156. #endif
  157. sigset_t newmask;
  158. struct sockaddr_storage ss;
  159. socklen_t slen;
  160. struct __rpc_sockinfo si;
  161. _DIAGASSERT(raddr != NULL);
  162. h = mem_alloc(sizeof(*h));
  163. if (h == NULL) {
  164. warnx("clnt_vc_create: out of memory");
  165. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  166. rpc_createerr.cf_error.re_errno = errno;
  167. goto fooy;
  168. }
  169. ct = mem_alloc(sizeof(*ct));
  170. if (ct == NULL) {
  171. warnx("clnt_vc_create: out of memory");
  172. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  173. rpc_createerr.cf_error.re_errno = errno;
  174. goto fooy;
  175. }
  176. sigfillset(&newmask);
  177. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  178. #ifdef _REENTRANT
  179. mutex_lock(&clnt_fd_lock);
  180. if (vc_fd_locks == NULL) {
  181. size_t cv_allocsz, fd_allocsz;
  182. int dtbsize = __rpc_dtbsize();
  183. fd_allocsz = dtbsize * sizeof (int);
  184. vc_fd_locks = mem_alloc(fd_allocsz);
  185. if (vc_fd_locks == NULL) {
  186. mutex_unlock(&clnt_fd_lock);
  187. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  188. goto fooy;
  189. } else
  190. memset(vc_fd_locks, '\0', fd_allocsz);
  191. _DIAGASSERT(vc_cv == NULL);
  192. cv_allocsz = dtbsize * sizeof (cond_t);
  193. vc_cv = mem_alloc(cv_allocsz);
  194. if (vc_cv == NULL) {
  195. mem_free(vc_fd_locks, fd_allocsz);
  196. vc_fd_locks = NULL;
  197. mutex_unlock(&clnt_fd_lock);
  198. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  199. goto fooy;
  200. } else {
  201. int i;
  202. for (i = 0; i < dtbsize; i++)
  203. cond_init(&vc_cv[i], 0, (void *) 0);
  204. }
  205. } else
  206. _DIAGASSERT(vc_cv != NULL);
  207. #endif
  208. /*
  209. * XXX - fvdl connecting while holding a mutex?
  210. */
  211. slen = sizeof ss;
  212. if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
  213. if (errno != ENOTCONN) {
  214. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  215. rpc_createerr.cf_error.re_errno = errno;
  216. mutex_unlock(&clnt_fd_lock);
  217. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  218. goto fooy;
  219. }
  220. if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
  221. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  222. rpc_createerr.cf_error.re_errno = errno;
  223. mutex_unlock(&clnt_fd_lock);
  224. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  225. goto fooy;
  226. }
  227. }
  228. mutex_unlock(&clnt_fd_lock);
  229. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  230. if (!__rpc_fd2sockinfo(fd, &si))
  231. goto fooy;
  232. ct->ct_closeit = FALSE;
  233. /*
  234. * Set up private data struct
  235. */
  236. ct->ct_fd = fd;
  237. ct->ct_wait.tv_usec = 0;
  238. ct->ct_waitset = FALSE;
  239. ct->ct_addr.buf = malloc((size_t)raddr->maxlen);
  240. if (ct->ct_addr.buf == NULL)
  241. goto fooy;
  242. memcpy(ct->ct_addr.buf, &raddr->buf, (size_t)raddr->len);
  243. ct->ct_addr.len = raddr->maxlen;
  244. ct->ct_addr.maxlen = raddr->maxlen;
  245. /*
  246. * Initialize call message
  247. */
  248. call_msg.rm_xid = __RPC_GETXID();
  249. call_msg.rm_direction = CALL;
  250. call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  251. call_msg.rm_call.cb_prog = (u_int32_t)prog;
  252. call_msg.rm_call.cb_vers = (u_int32_t)vers;
  253. /*
  254. * pre-serialize the static part of the call msg and stash it away
  255. */
  256. xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
  257. XDR_ENCODE);
  258. if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
  259. if (ct->ct_closeit) {
  260. (void)close(fd);
  261. }
  262. goto fooy;
  263. }
  264. ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
  265. XDR_DESTROY(&(ct->ct_xdrs));
  266. /*
  267. * Create a client handle which uses xdrrec for serialization
  268. * and authnone for authentication.
  269. */
  270. h->cl_ops = clnt_vc_ops();
  271. h->cl_private = ct;
  272. h->cl_auth = authnone_create();
  273. sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
  274. recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
  275. xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
  276. h->cl_private, read_vc, write_vc);
  277. return (h);
  278. fooy:
  279. /*
  280. * Something goofed, free stuff and barf
  281. */
  282. if (ct)
  283. mem_free(ct, sizeof(struct ct_data));
  284. if (h)
  285. mem_free(h, sizeof(CLIENT));
  286. return (NULL);
  287. }
  288. static enum clnt_stat
  289. clnt_vc_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
  290. CLIENT *h;
  291. rpcproc_t proc;
  292. xdrproc_t xdr_args;
  293. const char *args_ptr;
  294. xdrproc_t xdr_results;
  295. caddr_t results_ptr;
  296. struct timeval timeout;
  297. {
  298. struct ct_data *ct;
  299. XDR *xdrs;
  300. struct rpc_msg reply_msg;
  301. u_int32_t x_id;
  302. u_int32_t *msg_x_id;
  303. bool_t shipnow;
  304. int refreshes = 2;
  305. #ifdef _REENTRANT
  306. sigset_t mask, newmask;
  307. #endif
  308. _DIAGASSERT(h != NULL);
  309. ct = (struct ct_data *) h->cl_private;
  310. #ifdef _REENTRANT
  311. sigfillset(&newmask);
  312. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  313. mutex_lock(&clnt_fd_lock);
  314. while (vc_fd_locks[ct->ct_fd])
  315. cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
  316. vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
  317. mutex_unlock(&clnt_fd_lock);
  318. #endif
  319. xdrs = &(ct->ct_xdrs);
  320. msg_x_id = &ct->ct_u.ct_mcalli;
  321. if (!ct->ct_waitset) {
  322. if (time_not_ok(&timeout) == FALSE)
  323. ct->ct_wait = timeout;
  324. }
  325. shipnow =
  326. (xdr_results == NULL && timeout.tv_sec == 0
  327. && timeout.tv_usec == 0) ? FALSE : TRUE;
  328. call_again:
  329. xdrs->x_op = XDR_ENCODE;
  330. ct->ct_error.re_status = RPC_SUCCESS;
  331. x_id = ntohl(--(*msg_x_id));
  332. if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
  333. (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
  334. (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
  335. (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) {
  336. if (ct->ct_error.re_status == RPC_SUCCESS)
  337. ct->ct_error.re_status = RPC_CANTENCODEARGS;
  338. (void)xdrrec_endofrecord(xdrs, TRUE);
  339. release_fd_lock(ct->ct_fd, mask);
  340. return (ct->ct_error.re_status);
  341. }
  342. if (! xdrrec_endofrecord(xdrs, shipnow)) {
  343. release_fd_lock(ct->ct_fd, mask);
  344. return (ct->ct_error.re_status = RPC_CANTSEND);
  345. }
  346. if (! shipnow) {
  347. release_fd_lock(ct->ct_fd, mask);
  348. return (RPC_SUCCESS);
  349. }
  350. /*
  351. * Hack to provide rpc-based message passing
  352. */
  353. if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  354. release_fd_lock(ct->ct_fd, mask);
  355. return(ct->ct_error.re_status = RPC_TIMEDOUT);
  356. }
  357. /*
  358. * Keep receiving until we get a valid transaction id
  359. */
  360. xdrs->x_op = XDR_DECODE;
  361. for (;;) {
  362. reply_msg.acpted_rply.ar_verf = _null_auth;
  363. reply_msg.acpted_rply.ar_results.where = NULL;
  364. reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
  365. if (! xdrrec_skiprecord(xdrs)) {
  366. release_fd_lock(ct->ct_fd, mask);
  367. return (ct->ct_error.re_status);
  368. }
  369. /* now decode and validate the response header */
  370. if (! xdr_replymsg(xdrs, &reply_msg)) {
  371. if (ct->ct_error.re_status == RPC_SUCCESS)
  372. continue;
  373. release_fd_lock(ct->ct_fd, mask);
  374. return (ct->ct_error.re_status);
  375. }
  376. if (reply_msg.rm_xid == x_id)
  377. break;
  378. }
  379. /*
  380. * process header
  381. */
  382. _seterr_reply(&reply_msg, &(ct->ct_error));
  383. if (ct->ct_error.re_status == RPC_SUCCESS) {
  384. if (! AUTH_VALIDATE(h->cl_auth,
  385. &reply_msg.acpted_rply.ar_verf)) {
  386. ct->ct_error.re_status = RPC_AUTHERROR;
  387. ct->ct_error.re_why = AUTH_INVALIDRESP;
  388. } else if (! (*xdr_results)(xdrs, results_ptr)) {
  389. if (ct->ct_error.re_status == RPC_SUCCESS)
  390. ct->ct_error.re_status = RPC_CANTDECODERES;
  391. }
  392. /* free verifier ... */
  393. if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  394. xdrs->x_op = XDR_FREE;
  395. (void)xdr_opaque_auth(xdrs,
  396. &(reply_msg.acpted_rply.ar_verf));
  397. }
  398. } /* end successful completion */
  399. else {
  400. /* maybe our credentials need to be refreshed ... */
  401. if (refreshes-- && AUTH_REFRESH(h->cl_auth))
  402. goto call_again;
  403. } /* end of unsuccessful completion */
  404. release_fd_lock(ct->ct_fd, mask);
  405. return (ct->ct_error.re_status);
  406. }
  407. static void
  408. clnt_vc_geterr(h, errp)
  409. CLIENT *h;
  410. struct rpc_err *errp;
  411. {
  412. struct ct_data *ct;
  413. _DIAGASSERT(h != NULL);
  414. _DIAGASSERT(errp != NULL);
  415. ct = (struct ct_data *) h->cl_private;
  416. *errp = ct->ct_error;
  417. }
  418. static bool_t
  419. clnt_vc_freeres(cl, xdr_res, res_ptr)
  420. CLIENT *cl;
  421. xdrproc_t xdr_res;
  422. caddr_t res_ptr;
  423. {
  424. struct ct_data *ct;
  425. XDR *xdrs;
  426. bool_t dummy;
  427. #ifdef _REENTRANT
  428. sigset_t mask;
  429. #endif
  430. sigset_t newmask;
  431. _DIAGASSERT(cl != NULL);
  432. ct = (struct ct_data *)cl->cl_private;
  433. xdrs = &(ct->ct_xdrs);
  434. sigfillset(&newmask);
  435. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  436. mutex_lock(&clnt_fd_lock);
  437. #ifdef _REENTRANT
  438. while (vc_fd_locks[ct->ct_fd])
  439. cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
  440. #endif
  441. xdrs->x_op = XDR_FREE;
  442. dummy = (*xdr_res)(xdrs, res_ptr);
  443. mutex_unlock(&clnt_fd_lock);
  444. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  445. cond_signal(&vc_cv[ct->ct_fd]);
  446. return dummy;
  447. }
  448. /*ARGSUSED*/
  449. static void
  450. clnt_vc_abort(cl)
  451. CLIENT *cl;
  452. {
  453. }
  454. static bool_t
  455. clnt_vc_control(cl, request, info)
  456. CLIENT *cl;
  457. u_int request;
  458. char *info;
  459. {
  460. struct ct_data *ct;
  461. void *infop = info;
  462. #ifdef _REENTRANT
  463. sigset_t mask;
  464. #endif
  465. sigset_t newmask;
  466. _DIAGASSERT(cl != NULL);
  467. ct = (struct ct_data *)cl->cl_private;
  468. sigfillset(&newmask);
  469. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  470. mutex_lock(&clnt_fd_lock);
  471. #ifdef _REENTRANT
  472. while (vc_fd_locks[ct->ct_fd])
  473. cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
  474. vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
  475. #endif
  476. mutex_unlock(&clnt_fd_lock);
  477. switch (request) {
  478. case CLSET_FD_CLOSE:
  479. ct->ct_closeit = TRUE;
  480. release_fd_lock(ct->ct_fd, mask);
  481. return (TRUE);
  482. case CLSET_FD_NCLOSE:
  483. ct->ct_closeit = FALSE;
  484. release_fd_lock(ct->ct_fd, mask);
  485. return (TRUE);
  486. default:
  487. break;
  488. }
  489. /* for other requests which use info */
  490. if (info == NULL) {
  491. release_fd_lock(ct->ct_fd, mask);
  492. return (FALSE);
  493. }
  494. switch (request) {
  495. case CLSET_TIMEOUT:
  496. if (time_not_ok((struct timeval *)(void *)info)) {
  497. release_fd_lock(ct->ct_fd, mask);
  498. return (FALSE);
  499. }
  500. ct->ct_wait = *(struct timeval *)infop;
  501. ct->ct_waitset = TRUE;
  502. break;
  503. case CLGET_TIMEOUT:
  504. *(struct timeval *)infop = ct->ct_wait;
  505. break;
  506. case CLGET_SERVER_ADDR:
  507. (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
  508. break;
  509. case CLGET_FD:
  510. *(int *)(void *)info = ct->ct_fd;
  511. break;
  512. case CLGET_SVC_ADDR:
  513. /* The caller should not free this memory area */
  514. *(struct netbuf *)(void *)info = ct->ct_addr;
  515. break;
  516. case CLSET_SVC_ADDR: /* set to new address */
  517. release_fd_lock(ct->ct_fd, mask);
  518. return (FALSE);
  519. case CLGET_XID:
  520. /*
  521. * use the knowledge that xid is the
  522. * first element in the call structure
  523. * This will get the xid of the PREVIOUS call
  524. */
  525. *(u_int32_t *)(void *)info =
  526. ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
  527. break;
  528. case CLSET_XID:
  529. /* This will set the xid of the NEXT call */
  530. *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
  531. htonl(*((u_int32_t *)(void *)info) + 1);
  532. /* increment by 1 as clnt_vc_call() decrements once */
  533. break;
  534. case CLGET_VERS:
  535. /*
  536. * This RELIES on the information that, in the call body,
  537. * the version number field is the fifth field from the
  538. * begining of the RPC header. MUST be changed if the
  539. * call_struct is changed
  540. */
  541. *(u_int32_t *)(void *)info =
  542. ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
  543. 4 * BYTES_PER_XDR_UNIT));
  544. break;
  545. case CLSET_VERS:
  546. *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
  547. 4 * BYTES_PER_XDR_UNIT) =
  548. htonl(*(u_int32_t *)(void *)info);
  549. break;
  550. case CLGET_PROG:
  551. /*
  552. * This RELIES on the information that, in the call body,
  553. * the program number field is the fourth field from the
  554. * begining of the RPC header. MUST be changed if the
  555. * call_struct is changed
  556. */
  557. *(u_int32_t *)(void *)info =
  558. ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
  559. 3 * BYTES_PER_XDR_UNIT));
  560. break;
  561. case CLSET_PROG:
  562. *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
  563. 3 * BYTES_PER_XDR_UNIT) =
  564. htonl(*(u_int32_t *)(void *)info);
  565. break;
  566. default:
  567. release_fd_lock(ct->ct_fd, mask);
  568. return (FALSE);
  569. }
  570. release_fd_lock(ct->ct_fd, mask);
  571. return (TRUE);
  572. }
  573. static void
  574. clnt_vc_destroy(cl)
  575. CLIENT *cl;
  576. {
  577. struct ct_data *ct;
  578. #ifdef _REENTRANT
  579. int ct_fd;
  580. sigset_t mask;
  581. #endif
  582. sigset_t newmask;
  583. _DIAGASSERT(cl != NULL);
  584. ct = (struct ct_data *) cl->cl_private;
  585. ct_fd = ct->ct_fd;
  586. sigfillset(&newmask);
  587. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  588. mutex_lock(&clnt_fd_lock);
  589. #ifdef _REENTRANT
  590. while (vc_fd_locks[ct_fd])
  591. cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
  592. #endif
  593. if (ct->ct_closeit && ct->ct_fd != -1) {
  594. (void)close(ct->ct_fd);
  595. }
  596. XDR_DESTROY(&(ct->ct_xdrs));
  597. if (ct->ct_addr.buf)
  598. free(ct->ct_addr.buf);
  599. mem_free(ct, sizeof(struct ct_data));
  600. mem_free(cl, sizeof(CLIENT));
  601. mutex_unlock(&clnt_fd_lock);
  602. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  603. cond_signal(&vc_cv[ct_fd]);
  604. }
  605. /*
  606. * Interface between xdr serializer and tcp connection.
  607. * Behaves like the system calls, read & write, but keeps some error state
  608. * around for the rpc level.
  609. */
  610. static int
  611. read_vc(ctp, buf, len)
  612. caddr_t ctp;
  613. caddr_t buf;
  614. int len;
  615. {
  616. struct ct_data *ct = (struct ct_data *)(void *)ctp;
  617. struct pollfd fd;
  618. struct timespec ts;
  619. if (len == 0)
  620. return (0);
  621. TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &ts);
  622. fd.fd = ct->ct_fd;
  623. fd.events = POLLIN;
  624. for (;;) {
  625. switch (pollts(&fd, 1, &ts, NULL)) {
  626. case 0:
  627. ct->ct_error.re_status = RPC_TIMEDOUT;
  628. return (-1);
  629. case -1:
  630. if (errno == EINTR)
  631. continue;
  632. ct->ct_error.re_status = RPC_CANTRECV;
  633. ct->ct_error.re_errno = errno;
  634. return (-1);
  635. }
  636. break;
  637. }
  638. switch (len = read(ct->ct_fd, buf, (size_t)len)) {
  639. case 0:
  640. /* premature eof */
  641. ct->ct_error.re_errno = ECONNRESET;
  642. ct->ct_error.re_status = RPC_CANTRECV;
  643. len = -1; /* it's really an error */
  644. break;
  645. case -1:
  646. ct->ct_error.re_errno = errno;
  647. ct->ct_error.re_status = RPC_CANTRECV;
  648. break;
  649. }
  650. return (len);
  651. }
  652. static int
  653. write_vc(ctp, buf, len)
  654. caddr_t ctp;
  655. caddr_t buf;
  656. int len;
  657. {
  658. struct ct_data *ct = (struct ct_data *)(void *)ctp;
  659. int i, cnt;
  660. for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  661. if ((i = write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
  662. ct->ct_error.re_errno = errno;
  663. ct->ct_error.re_status = RPC_CANTSEND;
  664. return (-1);
  665. }
  666. }
  667. return (len);
  668. }
  669. static struct clnt_ops *
  670. clnt_vc_ops()
  671. {
  672. static struct clnt_ops ops;
  673. #ifdef _REENTRANT
  674. extern mutex_t ops_lock;
  675. sigset_t mask;
  676. #endif
  677. sigset_t newmask;
  678. /* VARIABLES PROTECTED BY ops_lock: ops */
  679. sigfillset(&newmask);
  680. thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
  681. mutex_lock(&ops_lock);
  682. if (ops.cl_call == NULL) {
  683. ops.cl_call = clnt_vc_call;
  684. ops.cl_abort = clnt_vc_abort;
  685. ops.cl_geterr = clnt_vc_geterr;
  686. ops.cl_freeres = clnt_vc_freeres;
  687. ops.cl_destroy = clnt_vc_destroy;
  688. ops.cl_control = clnt_vc_control;
  689. }
  690. mutex_unlock(&ops_lock);
  691. thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
  692. return (&ops);
  693. }
  694. /*
  695. * Make sure that the time is not garbage. -1 value is disallowed.
  696. * Note this is different from time_not_ok in clnt_dg.c
  697. */
  698. static bool_t
  699. time_not_ok(t)
  700. struct timeval *t;
  701. {
  702. _DIAGASSERT(t != NULL);
  703. return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
  704. t->tv_usec <= -1 || t->tv_usec > 1000000);
  705. }