xref: /titanic_51/usr/src/lib/libnsl/rpc/clnt_vc.c (revision 14ea4bb737263733ad80a36b4f73f681c30a6b45)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * Portions of this source code were derived from Berkeley
30  * 4.3 BSD under license from the Regents of the University of
31  * California.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 /*
37  * clnt_vc.c
38  *
39  * Implements a connectionful client side RPC.
40  *
41  * Connectionful RPC supports 'batched calls'.
42  * A sequence of calls may be batched-up in a send buffer. The rpc call
43  * return immediately to the client even though the call was not necessarily
44  * sent. The batching occurs if the results' xdr routine is NULL (0) AND
45  * the rpc timeout value is zero (see clnt.h, rpc).
46  *
47  * Clients should NOT casually batch calls that in fact return results; that
48  * is the server side should be aware that a call is batched and not produce
49  * any return message. Batched calls that produce many result messages can
50  * deadlock (netlock) the client and the server....
51  */
52 
53 
54 #include "mt.h"
55 #include "rpc_mt.h"
56 #include <assert.h>
57 #include <rpc/rpc.h>
58 #include <errno.h>
59 #include <sys/byteorder.h>
60 #include <sys/mkdev.h>
61 #include <sys/poll.h>
62 #include <syslog.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <netinet/tcp.h>
66 
67 #define	MCALL_MSG_SIZE 24
68 #define	SECS_TO_MS 1000
69 #define	USECS_TO_MS 1/1000
70 #ifndef MIN
71 #define	MIN(a, b)	(((a) < (b)) ? (a) : (b))
72 #endif
73 
74 extern int __rpc_timeval_to_msec(struct timeval *);
75 extern int __rpc_compress_pollfd(int, pollfd_t *, pollfd_t *);
76 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
77 extern bool_t __rpc_gss_wrap(AUTH *, char *, uint_t, XDR *, bool_t (*)(),
78 								caddr_t);
79 extern bool_t __rpc_gss_unwrap(AUTH *, XDR *, bool_t (*)(), caddr_t);
80 extern CLIENT *_clnt_vc_create_timed(int, struct netbuf *, rpcprog_t,
81 		rpcvers_t, uint_t, uint_t, const struct timeval *);
82 
83 static struct clnt_ops	*clnt_vc_ops(void);
84 static int		read_vc(void *, caddr_t, int);
85 static int		write_vc(void *, caddr_t, int);
86 static int		t_rcvall(int, char *, int);
87 static bool_t		time_not_ok(struct timeval *);
88 
89 struct ct_data;
90 static bool_t		set_up_connection(int, struct netbuf *,
91 				struct ct_data *, const struct timeval *);
92 static bool_t		set_io_mode(struct ct_data *, int);
93 
94 /*
95  * Lock table handle used by various MT sync. routines
96  */
97 static mutex_t	vctbl_lock = DEFAULTMUTEX;
98 static void	*vctbl = NULL;
99 
100 static const char clnt_vc_errstr[] = "%s : %s";
101 static const char clnt_vc_str[] = "clnt_vc_create";
102 static const char clnt_read_vc_str[] = "read_vc";
103 static const char __no_mem_str[] = "out of memory";
104 static const char no_fcntl_getfl_str[] = "could not get status flags and modes";
105 static const char no_nonblock_str[] = "could not set transport blocking mode";
106 
107 /*
108  * Private data structure
109  */
110 struct ct_data {
111 	int		ct_fd;		/* connection's fd */
112 	bool_t		ct_closeit;	/* close it on destroy */
113 	int		ct_tsdu;	/* size of tsdu */
114 	int		ct_wait;	/* wait interval in milliseconds */
115 	bool_t		ct_waitset;	/* wait set by clnt_control? */
116 	struct netbuf	ct_addr;	/* remote addr */
117 	struct rpc_err	ct_error;
118 	char		ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
119 	uint_t		ct_mpos;	/* pos after marshal */
120 	XDR		ct_xdrs;	/* XDR stream */
121 
122 	/* NON STANDARD INFO - 00-08-31 */
123 	bool_t		ct_is_oneway; /* True if the current call is oneway. */
124 	bool_t		ct_is_blocking;
125 	ushort_t	ct_io_mode;
126 	ushort_t	ct_blocking_mode;
127 	uint_t		ct_bufferSize; /* Total size of the buffer. */
128 	uint_t		ct_bufferPendingSize; /* Size of unsent data. */
129 	char 		*ct_buffer; /* Pointer to the buffer. */
130 	char 		*ct_bufferWritePtr; /* Ptr to the first free byte. */
131 	char 		*ct_bufferReadPtr; /* Ptr to the first byte of data. */
132 };
133 
134 struct nb_reg_node {
135 	struct nb_reg_node *next;
136 	struct ct_data *ct;
137 };
138 
139 static struct nb_reg_node *nb_first = (struct nb_reg_node *)&nb_first;
140 static struct nb_reg_node *nb_free  = (struct nb_reg_node *)&nb_free;
141 
142 static bool_t exit_handler_set = FALSE;
143 
144 static mutex_t nb_list_mutex = DEFAULTMUTEX;
145 
146 
147 /* Define some macros to manage the linked list. */
148 #define	LIST_ISEMPTY(l) (l == (struct nb_reg_node *)&l)
149 #define	LIST_CLR(l) (l = (struct nb_reg_node *)&l)
150 #define	LIST_ADD(l, node) (node->next = l->next, l = node)
151 #define	LIST_EXTRACT(l, node) (node = l, l = l->next)
152 #define	LIST_FOR_EACH(l, node) \
153 	for (node = l; node != (struct nb_reg_node *)&l; node = node->next)
154 
155 
156 /* Default size of the IO buffer used in non blocking mode */
157 #define	DEFAULT_PENDING_ZONE_MAX_SIZE (16*1024)
158 
159 static int nb_send(struct ct_data *, void *, unsigned int);
160 static int do_flush(struct ct_data *, uint_t);
161 static bool_t set_flush_mode(struct ct_data *, int);
162 static bool_t set_blocking_connection(struct ct_data *, bool_t);
163 
164 static int register_nb(struct ct_data *);
165 static int unregister_nb(struct ct_data *);
166 
167 
168 /*
169  * Change the mode of the underlying fd.
170  */
171 static bool_t
172 set_blocking_connection(struct ct_data *ct, bool_t blocking)
173 {
174 	int flag;
175 
176 	/*
177 	 * If the underlying fd is already in the required mode,
178 	 * avoid the syscall.
179 	 */
180 	if (ct->ct_is_blocking == blocking)
181 		return (TRUE);
182 
183 	if ((flag = fcntl(ct->ct_fd, F_GETFL, 0)) < 0) {
184 		(void) syslog(LOG_ERR, "set_blocking_connection : %s",
185 		    no_fcntl_getfl_str);
186 		return (FALSE);
187 	}
188 
189 	flag = blocking? flag&~O_NONBLOCK : flag|O_NONBLOCK;
190 	if (fcntl(ct->ct_fd, F_SETFL, flag) != 0) {
191 		(void) syslog(LOG_ERR, "set_blocking_connection : %s",
192 		    no_nonblock_str);
193 		return (FALSE);
194 	}
195 	ct->ct_is_blocking = blocking;
196 	return (TRUE);
197 }
198 
199 /*
200  * Create a client handle for a connection.
201  * Default options are set, which the user can change using clnt_control()'s.
202  * The rpc/vc package does buffering similar to stdio, so the client
203  * must pick send and receive buffer sizes, 0 => use the default.
204  * NB: fd is copied into a private area.
205  * NB: The rpch->cl_auth is set null authentication. Caller may wish to
206  * set this something more useful.
207  *
208  * fd should be open and bound.
209  */
210 CLIENT *
211 clnt_vc_create(const int fd, struct netbuf *svcaddr, const rpcprog_t prog,
212 	const rpcvers_t vers, const uint_t sendsz, const uint_t recvsz)
213 {
214 	return (_clnt_vc_create_timed(fd, svcaddr, prog, vers, sendsz,
215 			recvsz, NULL));
216 }
217 
218 /*
219  * This has the same definition as clnt_vc_create(), except it
220  * takes an additional parameter - a pointer to a timeval structure.
221  *
222  * Not a public interface. This is for clnt_create_timed,
223  * clnt_create_vers_timed, clnt_tp_create_timed to pass down the timeout
224  * value to control a tcp connection attempt.
225  * (for bug 4049792: clnt_create_timed does not time out)
226  *
227  * If tp is NULL, use default timeout to set up the connection.
228  */
229 CLIENT *
230 _clnt_vc_create_timed(int fd, struct netbuf *svcaddr, rpcprog_t prog,
231 	rpcvers_t vers, uint_t sendsz, uint_t recvsz, const struct timeval *tp)
232 {
233 	CLIENT *cl;			/* client handle */
234 	struct ct_data *ct;		/* private data */
235 	struct timeval now;
236 	struct rpc_msg call_msg;
237 	struct t_info tinfo;
238 	int flag;
239 
240 	cl = malloc(sizeof (*cl));
241 	ct = malloc(sizeof (*ct));
242 	if ((cl == NULL) || (ct == NULL)) {
243 		(void) syslog(LOG_ERR, clnt_vc_errstr,
244 				clnt_vc_str, __no_mem_str);
245 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
246 		rpc_createerr.cf_error.re_errno = errno;
247 		rpc_createerr.cf_error.re_terrno = 0;
248 		goto err;
249 	}
250 	ct->ct_addr.buf = NULL;
251 
252 	/*
253 	 * The only use of vctbl_lock is for serializing the creation of
254 	 * vctbl. Once created the lock needs to be released so we don't
255 	 * hold it across the set_up_connection() call and end up with a
256 	 * bunch of threads stuck waiting for the mutex.
257 	 */
258 	sig_mutex_lock(&vctbl_lock);
259 
260 	if ((vctbl == NULL) && ((vctbl = rpc_fd_init()) == NULL)) {
261 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
262 		rpc_createerr.cf_error.re_errno = errno;
263 		rpc_createerr.cf_error.re_terrno = 0;
264 		sig_mutex_unlock(&vctbl_lock);
265 		goto err;
266 	}
267 
268 	sig_mutex_unlock(&vctbl_lock);
269 
270 	ct->ct_io_mode = RPC_CL_BLOCKING;
271 	ct->ct_blocking_mode = RPC_CL_BLOCKING_FLUSH;
272 
273 	ct->ct_buffer = NULL;	/* We allocate the buffer when needed. */
274 	ct->ct_bufferSize = DEFAULT_PENDING_ZONE_MAX_SIZE;
275 	ct->ct_bufferPendingSize = 0;
276 	ct->ct_bufferWritePtr = NULL;
277 	ct->ct_bufferReadPtr = NULL;
278 
279 	/* Check the current state of the fd. */
280 	if ((flag = fcntl(fd, F_GETFL, 0)) < 0) {
281 		(void) syslog(LOG_ERR, "_clnt_vc_create_timed : %s",
282 		    no_fcntl_getfl_str);
283 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
284 		rpc_createerr.cf_error.re_terrno = errno;
285 		rpc_createerr.cf_error.re_errno = 0;
286 		goto err;
287 	}
288 	ct->ct_is_blocking = flag & O_NONBLOCK ? FALSE : TRUE;
289 
290 	if (set_up_connection(fd, svcaddr, ct, tp) == FALSE) {
291 		goto err;
292 	}
293 
294 	/*
295 	 * Set up other members of private data struct
296 	 */
297 	ct->ct_fd = fd;
298 	/*
299 	 * The actual value will be set by clnt_call or clnt_control
300 	 */
301 	ct->ct_wait = 30000;
302 	ct->ct_waitset = FALSE;
303 	/*
304 	 * By default, closeit is always FALSE. It is users responsibility
305 	 * to do a t_close on it, else the user may use clnt_control
306 	 * to let clnt_destroy do it for him/her.
307 	 */
308 	ct->ct_closeit = FALSE;
309 
310 	/*
311 	 * Initialize call message
312 	 */
313 	(void) gettimeofday(&now, (struct timezone *)0);
314 	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
315 	call_msg.rm_call.cb_prog = prog;
316 	call_msg.rm_call.cb_vers = vers;
317 
318 	/*
319 	 * pre-serialize the static part of the call msg and stash it away
320 	 */
321 	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
322 	if (!xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
323 		goto err;
324 	}
325 	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
326 	XDR_DESTROY(&(ct->ct_xdrs));
327 
328 	if (t_getinfo(fd, &tinfo) == -1) {
329 		rpc_createerr.cf_stat = RPC_TLIERROR;
330 		rpc_createerr.cf_error.re_terrno = t_errno;
331 		rpc_createerr.cf_error.re_errno = 0;
332 		goto err;
333 	}
334 	/*
335 	 * Find the receive and the send size
336 	 */
337 	sendsz = __rpc_get_t_size((int)sendsz, tinfo.tsdu);
338 	recvsz = __rpc_get_t_size((int)recvsz, tinfo.tsdu);
339 	if ((sendsz == 0) || (recvsz == 0)) {
340 		rpc_createerr.cf_stat = RPC_TLIERROR;
341 		rpc_createerr.cf_error.re_terrno = 0;
342 		rpc_createerr.cf_error.re_errno = 0;
343 		goto err;
344 	}
345 	ct->ct_tsdu = tinfo.tsdu;
346 	/*
347 	 * Create a client handle which uses xdrrec for serialization
348 	 * and authnone for authentication.
349 	 */
350 	ct->ct_xdrs.x_ops = NULL;
351 	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct,
352 			read_vc, write_vc);
353 	if (ct->ct_xdrs.x_ops == NULL) {
354 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
355 		rpc_createerr.cf_error.re_terrno = 0;
356 		rpc_createerr.cf_error.re_errno = ENOMEM;
357 		goto err;
358 	}
359 	cl->cl_ops = clnt_vc_ops();
360 	cl->cl_private = (caddr_t)ct;
361 	cl->cl_auth = authnone_create();
362 	cl->cl_tp = NULL;
363 	cl->cl_netid = NULL;
364 	return (cl);
365 
366 err:
367 	if (cl) {
368 		if (ct) {
369 			if (ct->ct_addr.len)
370 				free(ct->ct_addr.buf);
371 			free(ct);
372 		}
373 		free(cl);
374 	}
375 	return (NULL);
376 }
377 
378 #define	TCPOPT_BUFSIZE 128
379 
380 /*
381  * Set tcp connection timeout value.
382  * Retun 0 for success, -1 for failure.
383  */
384 static int
385 _set_tcp_conntime(int fd, int optval)
386 {
387 	struct t_optmgmt req, res;
388 	struct opthdr *opt;
389 	int *ip;
390 	char buf[TCPOPT_BUFSIZE];
391 
392 	/* LINTED pointer cast */
393 	opt = (struct opthdr *)buf;
394 	opt->level =  IPPROTO_TCP;
395 	opt->name = TCP_CONN_ABORT_THRESHOLD;
396 	opt->len = sizeof (int);
397 
398 	req.flags = T_NEGOTIATE;
399 	req.opt.len = sizeof (struct opthdr) + opt->len;
400 	req.opt.buf = (char *)opt;
401 	/* LINTED pointer cast */
402 	ip = (int *)((char *)buf + sizeof (struct opthdr));
403 	*ip = optval;
404 
405 	res.flags = 0;
406 	res.opt.buf = (char *)buf;
407 	res.opt.maxlen = sizeof (buf);
408 	if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
409 		return (-1);
410 	}
411 	return (0);
412 }
413 
414 /*
415  * Get current tcp connection timeout value.
416  * Retun 0 for success, -1 for failure.
417  */
418 static int
419 _get_tcp_conntime(int fd)
420 {
421 	struct t_optmgmt req, res;
422 	struct opthdr *opt;
423 	int *ip, retval;
424 	char buf[TCPOPT_BUFSIZE];
425 
426 	/* LINTED pointer cast */
427 	opt = (struct opthdr *)buf;
428 	opt->level =  IPPROTO_TCP;
429 	opt->name = TCP_CONN_ABORT_THRESHOLD;
430 	opt->len = sizeof (int);
431 
432 	req.flags = T_CURRENT;
433 	req.opt.len = sizeof (struct opthdr) + opt->len;
434 	req.opt.buf = (char *)opt;
435 	/* LINTED pointer cast */
436 	ip = (int *)((char *)buf + sizeof (struct opthdr));
437 	*ip = 0;
438 
439 	res.flags = 0;
440 	res.opt.buf = (char *)buf;
441 	res.opt.maxlen = sizeof (buf);
442 	if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
443 		return (-1);
444 	}
445 
446 	/* LINTED pointer cast */
447 	ip = (int *)((char *)buf + sizeof (struct opthdr));
448 	retval = *ip;
449 	return (retval);
450 }
451 
452 static bool_t
453 set_up_connection(int fd, struct netbuf *svcaddr, struct ct_data *ct,
454 						const struct timeval *tp)
455 {
456 	int state;
457 	struct t_call sndcallstr, *rcvcall;
458 	int nconnect;
459 	bool_t connected, do_rcv_connect;
460 	int curr_time = 0;
461 
462 	ct->ct_addr.len = 0;
463 	state = t_getstate(fd);
464 	if (state == -1) {
465 		rpc_createerr.cf_stat = RPC_TLIERROR;
466 		rpc_createerr.cf_error.re_errno = 0;
467 		rpc_createerr.cf_error.re_terrno = t_errno;
468 		return (FALSE);
469 	}
470 
471 #ifdef DEBUG
472 	fprintf(stderr, "set_up_connection: state = %d\n", state);
473 #endif
474 	switch (state) {
475 	case T_IDLE:
476 		if (svcaddr == NULL) {
477 			rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
478 			return (FALSE);
479 		}
480 		/*
481 		 * Connect only if state is IDLE and svcaddr known
482 		 */
483 /* LINTED pointer alignment */
484 		rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_OPT|T_ADDR);
485 		if (rcvcall == NULL) {
486 			rpc_createerr.cf_stat = RPC_TLIERROR;
487 			rpc_createerr.cf_error.re_terrno = t_errno;
488 			rpc_createerr.cf_error.re_errno = errno;
489 			return (FALSE);
490 		}
491 		rcvcall->udata.maxlen = 0;
492 		sndcallstr.addr = *svcaddr;
493 		sndcallstr.opt.len = 0;
494 		sndcallstr.udata.len = 0;
495 		/*
496 		 * Even NULL could have sufficed for rcvcall, because
497 		 * the address returned is same for all cases except
498 		 * for the gateway case, and hence required.
499 		 */
500 		connected = FALSE;
501 		do_rcv_connect = FALSE;
502 
503 		/*
504 		 * If there is a timeout value specified, we will try to
505 		 * reset the tcp connection timeout. If the transport does
506 		 * not support the TCP_CONN_ABORT_THRESHOLD option or fails
507 		 * for other reason, default timeout will be used.
508 		 */
509 		if (tp != NULL) {
510 		    int ms;
511 
512 		    /* TCP_CONN_ABORT_THRESHOLD takes int value in millisecs */
513 		    ms = tp->tv_sec * SECS_TO_MS + tp->tv_usec * USECS_TO_MS;
514 		    if (((curr_time = _get_tcp_conntime(fd)) != -1) &&
515 			(_set_tcp_conntime(fd, ms) == 0)) {
516 			/* EMPTY */
517 #ifdef DEBUG
518 			fprintf(stderr, "set_up_connection: set tcp ");
519 			fprintf(stderr, "connection timeout to %d ms\n", ms);
520 #endif
521 		    }
522 		}
523 
524 		for (nconnect = 0; nconnect < 3; nconnect++) {
525 			if (t_connect(fd, &sndcallstr, rcvcall) != -1) {
526 				connected = TRUE;
527 				break;
528 			}
529 			if (!(t_errno == TSYSERR && errno == EINTR)) {
530 				break;
531 			}
532 			if ((state = t_getstate(fd)) == T_OUTCON) {
533 				do_rcv_connect = TRUE;
534 				break;
535 			}
536 			if (state != T_IDLE) {
537 				break;
538 			}
539 		}
540 		if (do_rcv_connect) {
541 			do {
542 				if (t_rcvconnect(fd, rcvcall) != -1) {
543 					connected = TRUE;
544 					break;
545 				}
546 			} while (t_errno == TSYSERR && errno == EINTR);
547 		}
548 
549 		/*
550 		 * Set the connection timeout back to its old value.
551 		 */
552 		if (curr_time) {
553 			(void) _set_tcp_conntime(fd, curr_time);
554 		}
555 
556 		if (!connected) {
557 			rpc_createerr.cf_stat = RPC_TLIERROR;
558 			rpc_createerr.cf_error.re_terrno = t_errno;
559 			rpc_createerr.cf_error.re_errno = errno;
560 			(void) t_free((char *)rcvcall, T_CALL);
561 #ifdef DEBUG
562 			fprintf(stderr, "clnt_vc: t_connect error %d\n",
563 				rpc_createerr.cf_error.re_terrno);
564 #endif
565 			return (FALSE);
566 		}
567 
568 		/* Free old area if allocated */
569 		if (ct->ct_addr.buf)
570 			free(ct->ct_addr.buf);
571 		ct->ct_addr = rcvcall->addr;	/* To get the new address */
572 		/* So that address buf does not get freed */
573 		rcvcall->addr.buf = NULL;
574 		(void) t_free((char *)rcvcall, T_CALL);
575 		break;
576 	case T_DATAXFER:
577 	case T_OUTCON:
578 		if (svcaddr == NULL) {
579 			/*
580 			 * svcaddr could also be NULL in cases where the
581 			 * client is already bound and connected.
582 			 */
583 			ct->ct_addr.len = 0;
584 		} else {
585 			ct->ct_addr.buf = malloc(svcaddr->len);
586 			if (ct->ct_addr.buf == NULL) {
587 				(void) syslog(LOG_ERR, clnt_vc_errstr,
588 					clnt_vc_str, __no_mem_str);
589 				rpc_createerr.cf_stat = RPC_SYSTEMERROR;
590 				rpc_createerr.cf_error.re_errno = errno;
591 				rpc_createerr.cf_error.re_terrno = 0;
592 				return (FALSE);
593 			}
594 			(void) memcpy(ct->ct_addr.buf, svcaddr->buf,
595 					(size_t)svcaddr->len);
596 			ct->ct_addr.len = ct->ct_addr.maxlen = svcaddr->len;
597 		}
598 		break;
599 	default:
600 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
601 		return (FALSE);
602 	}
603 	return (TRUE);
604 }
605 
606 static enum clnt_stat
607 clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, caddr_t args_ptr,
608 	xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout)
609 {
610 /* LINTED pointer alignment */
611 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
612 	XDR *xdrs = &(ct->ct_xdrs);
613 	struct rpc_msg reply_msg;
614 	uint32_t x_id;
615 /* LINTED pointer alignment */
616 	uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);	/* yuk */
617 	bool_t shipnow;
618 	int refreshes = 2;
619 
620 	if (rpc_fd_lock(vctbl, ct->ct_fd)) {
621 		rpc_callerr.re_status = RPC_FAILED;
622 		rpc_callerr.re_errno = errno;
623 		rpc_fd_unlock(vctbl, ct->ct_fd);
624 		return (RPC_FAILED);
625 	}
626 
627 	ct->ct_is_oneway = FALSE;
628 	if (ct->ct_io_mode == RPC_CL_NONBLOCKING) {
629 		if (do_flush(ct, RPC_CL_BLOCKING_FLUSH) != 0) {
630 			rpc_fd_unlock(vctbl, ct->ct_fd);
631 			return (RPC_FAILED);  /* XXX */
632 		}
633 	}
634 
635 	if (!ct->ct_waitset) {
636 		/* If time is not within limits, we ignore it. */
637 		if (time_not_ok(&timeout) == FALSE)
638 			ct->ct_wait = __rpc_timeval_to_msec(&timeout);
639 	} else {
640 		timeout.tv_sec = (ct->ct_wait / 1000);
641 		timeout.tv_usec = (ct->ct_wait % 1000) * 1000;
642 	}
643 
644 	shipnow = ((xdr_results == (xdrproc_t)0) && (timeout.tv_sec == 0) &&
645 	    (timeout.tv_usec == 0)) ? FALSE : TRUE;
646 call_again:
647 	xdrs->x_op = XDR_ENCODE;
648 	rpc_callerr.re_status = RPC_SUCCESS;
649 	/*
650 	 * Due to little endian byte order, it is necessary to convert to host
651 	 * format before decrementing xid.
652 	 */
653 	x_id = ntohl(*msg_x_id) - 1;
654 	*msg_x_id = htonl(x_id);
655 
656 	if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
657 		if ((!XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
658 		    (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
659 		    (!AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
660 		    (!xdr_args(xdrs, args_ptr))) {
661 			if (rpc_callerr.re_status == RPC_SUCCESS)
662 				rpc_callerr.re_status = RPC_CANTENCODEARGS;
663 			(void) xdrrec_endofrecord(xdrs, TRUE);
664 			rpc_fd_unlock(vctbl, ct->ct_fd);
665 			return (rpc_callerr.re_status);
666 		}
667 	} else {
668 /* LINTED pointer alignment */
669 		uint32_t *u = (uint32_t *)&ct->ct_mcall[ct->ct_mpos];
670 		IXDR_PUT_U_INT32(u, proc);
671 		if (!__rpc_gss_wrap(cl->cl_auth, ct->ct_mcall,
672 		    ((char *)u) - ct->ct_mcall, xdrs, xdr_args, args_ptr)) {
673 			if (rpc_callerr.re_status == RPC_SUCCESS)
674 				rpc_callerr.re_status = RPC_CANTENCODEARGS;
675 			(void) xdrrec_endofrecord(xdrs, TRUE);
676 			rpc_fd_unlock(vctbl, ct->ct_fd);
677 			return (rpc_callerr.re_status);
678 		}
679 	}
680 	if (!xdrrec_endofrecord(xdrs, shipnow)) {
681 		rpc_fd_unlock(vctbl, ct->ct_fd);
682 		return (rpc_callerr.re_status = RPC_CANTSEND);
683 	}
684 	if (!shipnow) {
685 		rpc_fd_unlock(vctbl, ct->ct_fd);
686 		return (RPC_SUCCESS);
687 	}
688 	/*
689 	 * Hack to provide rpc-based message passing
690 	 */
691 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
692 		rpc_fd_unlock(vctbl, ct->ct_fd);
693 		return (rpc_callerr.re_status = RPC_TIMEDOUT);
694 	}
695 
696 
697 	/*
698 	 * Keep receiving until we get a valid transaction id
699 	 */
700 	xdrs->x_op = XDR_DECODE;
701 	for (;;) {
702 		reply_msg.acpted_rply.ar_verf = _null_auth;
703 		reply_msg.acpted_rply.ar_results.where = NULL;
704 		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
705 		if (!xdrrec_skiprecord(xdrs)) {
706 			rpc_fd_unlock(vctbl, ct->ct_fd);
707 			return (rpc_callerr.re_status);
708 		}
709 		/* now decode and validate the response header */
710 		if (!xdr_replymsg(xdrs, &reply_msg)) {
711 			if (rpc_callerr.re_status == RPC_SUCCESS)
712 				continue;
713 			rpc_fd_unlock(vctbl, ct->ct_fd);
714 			return (rpc_callerr.re_status);
715 		}
716 		if (reply_msg.rm_xid == x_id)
717 			break;
718 	}
719 
720 	/*
721 	 * process header
722 	 */
723 	if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
724 	    (reply_msg.acpted_rply.ar_stat == SUCCESS))
725 		rpc_callerr.re_status = RPC_SUCCESS;
726 	else
727 		__seterr_reply(&reply_msg, &(rpc_callerr));
728 
729 	if (rpc_callerr.re_status == RPC_SUCCESS) {
730 		if (!AUTH_VALIDATE(cl->cl_auth,
731 				&reply_msg.acpted_rply.ar_verf)) {
732 			rpc_callerr.re_status = RPC_AUTHERROR;
733 			rpc_callerr.re_why = AUTH_INVALIDRESP;
734 		} else if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
735 			if (!(*xdr_results)(xdrs, results_ptr)) {
736 				if (rpc_callerr.re_status == RPC_SUCCESS)
737 				    rpc_callerr.re_status = RPC_CANTDECODERES;
738 			}
739 		} else if (!__rpc_gss_unwrap(cl->cl_auth, xdrs, xdr_results,
740 							results_ptr)) {
741 			if (rpc_callerr.re_status == RPC_SUCCESS)
742 				rpc_callerr.re_status = RPC_CANTDECODERES;
743 		}
744 	}	/* end successful completion */
745 	/*
746 	 * If unsuccesful AND error is an authentication error
747 	 * then refresh credentials and try again, else break
748 	 */
749 	else if (rpc_callerr.re_status == RPC_AUTHERROR) {
750 		/* maybe our credentials need to be refreshed ... */
751 		if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
752 			goto call_again;
753 		else
754 			/*
755 			 * We are setting rpc_callerr here given that libnsl
756 			 * is not reentrant thereby reinitializing the TSD.
757 			 * If not set here then success could be returned even
758 			 * though refresh failed.
759 			 */
760 			rpc_callerr.re_status = RPC_AUTHERROR;
761 	} /* end of unsuccessful completion */
762 	/* free verifier ... */
763 	if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED &&
764 			reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
765 		xdrs->x_op = XDR_FREE;
766 		(void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
767 	}
768 	rpc_fd_unlock(vctbl, ct->ct_fd);
769 	return (rpc_callerr.re_status);
770 }
771 
772 static enum clnt_stat
773 clnt_vc_send(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, caddr_t args_ptr)
774 {
775 /* LINTED pointer alignment */
776 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
777 	XDR *xdrs = &(ct->ct_xdrs);
778 	uint32_t x_id;
779 /* LINTED pointer alignment */
780 	uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);	/* yuk */
781 
782 	if (rpc_fd_lock(vctbl, ct->ct_fd)) {
783 		rpc_callerr.re_status = RPC_FAILED;
784 		rpc_callerr.re_errno = errno;
785 		rpc_fd_unlock(vctbl, ct->ct_fd);
786 		return (RPC_FAILED);
787 	}
788 
789 	ct->ct_is_oneway = TRUE;
790 
791 	xdrs->x_op = XDR_ENCODE;
792 	rpc_callerr.re_status = RPC_SUCCESS;
793 	/*
794 	 * Due to little endian byte order, it is necessary to convert to host
795 	 * format before decrementing xid.
796 	 */
797 	x_id = ntohl(*msg_x_id) - 1;
798 	*msg_x_id = htonl(x_id);
799 
800 	if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
801 		if ((!XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
802 		    (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
803 		    (!AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
804 		    (!xdr_args(xdrs, args_ptr))) {
805 			if (rpc_callerr.re_status == RPC_SUCCESS)
806 				rpc_callerr.re_status = RPC_CANTENCODEARGS;
807 			(void) xdrrec_endofrecord(xdrs, TRUE);
808 			rpc_fd_unlock(vctbl, ct->ct_fd);
809 			return (rpc_callerr.re_status);
810 		}
811 	} else {
812 /* LINTED pointer alignment */
813 		uint32_t *u = (uint32_t *)&ct->ct_mcall[ct->ct_mpos];
814 		IXDR_PUT_U_INT32(u, proc);
815 		if (!__rpc_gss_wrap(cl->cl_auth, ct->ct_mcall,
816 		    ((char *)u) - ct->ct_mcall, xdrs, xdr_args, args_ptr)) {
817 			if (rpc_callerr.re_status == RPC_SUCCESS)
818 				rpc_callerr.re_status = RPC_CANTENCODEARGS;
819 			(void) xdrrec_endofrecord(xdrs, TRUE);
820 			rpc_fd_unlock(vctbl, ct->ct_fd);
821 			return (rpc_callerr.re_status);
822 		}
823 	}
824 
825 	/*
826 	 * Do not need to check errors, as the following code does
827 	 * not depend on the successful completion of the call.
828 	 * An error, if any occurs, is reported through
829 	 * rpc_callerr.re_status.
830 	 */
831 	(void) xdrrec_endofrecord(xdrs, TRUE);
832 
833 	rpc_fd_unlock(vctbl, ct->ct_fd);
834 	return (rpc_callerr.re_status);
835 }
836 
837 /* ARGSUSED */
838 static void
839 clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
840 {
841 	*errp = rpc_callerr;
842 }
843 
844 static bool_t
845 clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
846 {
847 /* LINTED pointer alignment */
848 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
849 	XDR *xdrs = &(ct->ct_xdrs);
850 	bool_t stat;
851 
852 	(void) rpc_fd_lock(vctbl, ct->ct_fd);
853 	xdrs->x_op = XDR_FREE;
854 	stat = (*xdr_res)(xdrs, res_ptr);
855 	rpc_fd_unlock(vctbl, ct->ct_fd);
856 	return (stat);
857 }
858 
859 static void
860 clnt_vc_abort(void)
861 {
862 }
863 
864 /*ARGSUSED*/
865 static bool_t
866 clnt_vc_control(CLIENT *cl, int request, char *info)
867 {
868 	bool_t ret;
869 /* LINTED pointer alignment */
870 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
871 
872 	if (rpc_fd_lock(vctbl, ct->ct_fd)) {
873 		rpc_fd_unlock(vctbl, ct->ct_fd);
874 		return (RPC_FAILED);
875 	}
876 
877 	switch (request) {
878 	case CLSET_FD_CLOSE:
879 		ct->ct_closeit = TRUE;
880 		rpc_fd_unlock(vctbl, ct->ct_fd);
881 		return (TRUE);
882 	case CLSET_FD_NCLOSE:
883 		ct->ct_closeit = FALSE;
884 		rpc_fd_unlock(vctbl, ct->ct_fd);
885 		return (TRUE);
886 	case CLFLUSH:
887 		if (ct->ct_io_mode == RPC_CL_NONBLOCKING) {
888 			int res;
889 			res = do_flush(ct, (info == NULL ||
890 			    /* LINTED pointer cast */
891 			    *(int *)info == RPC_CL_DEFAULT_FLUSH)?
892 			    /* LINTED pointer cast */
893 			    ct->ct_blocking_mode: *(int *)info);
894 			ret = (0 == res);
895 		}
896 		rpc_fd_unlock(vctbl, ct->ct_fd);
897 		return (ret);
898 	}
899 
900 	/* for other requests which use info */
901 	if (info == NULL) {
902 		rpc_fd_unlock(vctbl, ct->ct_fd);
903 		return (FALSE);
904 	}
905 	switch (request) {
906 	case CLSET_TIMEOUT:
907 /* LINTED pointer alignment */
908 		if (time_not_ok((struct timeval *)info)) {
909 			rpc_fd_unlock(vctbl, ct->ct_fd);
910 			return (FALSE);
911 		}
912 /* LINTED pointer alignment */
913 		ct->ct_wait = __rpc_timeval_to_msec((struct timeval *)info);
914 		ct->ct_waitset = TRUE;
915 		break;
916 	case CLGET_TIMEOUT:
917 /* LINTED pointer alignment */
918 		((struct timeval *)info)->tv_sec = ct->ct_wait / 1000;
919 /* LINTED pointer alignment */
920 		((struct timeval *)info)->tv_usec =
921 			(ct->ct_wait % 1000) * 1000;
922 		break;
923 	case CLGET_SERVER_ADDR:	/* For compatibility only */
924 		(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
925 		break;
926 	case CLGET_FD:
927 /* LINTED pointer alignment */
928 		*(int *)info = ct->ct_fd;
929 		break;
930 	case CLGET_SVC_ADDR:
931 		/* The caller should not free this memory area */
932 /* LINTED pointer alignment */
933 		*(struct netbuf *)info = ct->ct_addr;
934 		break;
935 	case CLSET_SVC_ADDR:		/* set to new address */
936 #ifdef undef
937 		/*
938 		 * XXX: once the t_snddis(), followed by t_connect() starts to
939 		 * work, this ifdef should be removed.  CLIENT handle reuse
940 		 * would then be possible for COTS as well.
941 		 */
942 		if (t_snddis(ct->ct_fd, NULL) == -1) {
943 			rpc_createerr.cf_stat = RPC_TLIERROR;
944 			rpc_createerr.cf_error.re_terrno = t_errno;
945 			rpc_createerr.cf_error.re_errno = errno;
946 			rpc_fd_unlock(vctbl, ct->ct_fd);
947 			return (FALSE);
948 		}
949 		ret = set_up_connection(ct->ct_fd, (struct netbuf *)info,
950 			ct, NULL));
951 		rpc_fd_unlock(vctbl, ct->ct_fd);
952 		return (ret);
953 #else
954 		rpc_fd_unlock(vctbl, ct->ct_fd);
955 		return (FALSE);
956 #endif
957 	case CLGET_XID:
958 		/*
959 		 * use the knowledge that xid is the
960 		 * first element in the call structure
961 		 * This will get the xid of the PREVIOUS call
962 		 */
963 /* LINTED pointer alignment */
964 		*(uint32_t *)info = ntohl(*(uint32_t *)ct->ct_mcall);
965 		break;
966 	case CLSET_XID:
967 		/* This will set the xid of the NEXT call */
968 /* LINTED pointer alignment */
969 		*(uint32_t *)ct->ct_mcall =  htonl(*(uint32_t *)info + 1);
970 		/* increment by 1 as clnt_vc_call() decrements once */
971 		break;
972 	case CLGET_VERS:
973 		/*
974 		 * This RELIES on the information that, in the call body,
975 		 * the version number field is the fifth field from the
976 		 * begining of the RPC header. MUST be changed if the
977 		 * call_struct is changed
978 		 */
979 /* LINTED pointer alignment */
980 		*(uint32_t *)info = ntohl(*(uint32_t *)(ct->ct_mcall +
981 						4 * BYTES_PER_XDR_UNIT));
982 		break;
983 
984 	case CLSET_VERS:
985 /* LINTED pointer alignment */
986 		*(uint32_t *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT) =
987 /* LINTED pointer alignment */
988 			htonl(*(uint32_t *)info);
989 		break;
990 
991 	case CLGET_PROG:
992 		/*
993 		 * This RELIES on the information that, in the call body,
994 		 * the program number field is the fourth field from the
995 		 * begining of the RPC header. MUST be changed if the
996 		 * call_struct is changed
997 		 */
998 /* LINTED pointer alignment */
999 		*(uint32_t *)info = ntohl(*(uint32_t *)(ct->ct_mcall +
1000 						3 * BYTES_PER_XDR_UNIT));
1001 		break;
1002 
1003 	case CLSET_PROG:
1004 /* LINTED pointer alignment */
1005 		*(uint32_t *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT) =
1006 /* LINTED pointer alignment */
1007 			htonl(*(uint32_t *)info);
1008 		break;
1009 
1010 	case CLSET_IO_MODE:
1011 		/* LINTED pointer cast */
1012 		if (!set_io_mode(ct, *(int *)info)) {
1013 		    rpc_fd_unlock(vctbl, ct->ct_fd);
1014 		    return (FALSE);
1015 		}
1016 		break;
1017 	case CLSET_FLUSH_MODE:
1018 		/* Set a specific FLUSH_MODE */
1019 		/* LINTED pointer cast */
1020 		if (!set_flush_mode(ct, *(int *)info)) {
1021 		    rpc_fd_unlock(vctbl, ct->ct_fd);
1022 		    return (FALSE);
1023 		}
1024 		break;
1025 	case CLGET_FLUSH_MODE:
1026 		/* LINTED pointer cast */
1027 		*(rpcflushmode_t *)info = ct->ct_blocking_mode;
1028 		break;
1029 
1030 	case CLGET_IO_MODE:
1031 		/* LINTED pointer cast */
1032 		*(rpciomode_t *)info = ct->ct_io_mode;
1033 		break;
1034 
1035 	case CLGET_CURRENT_REC_SIZE:
1036 		/*
1037 		 * Returns the current amount of memory allocated
1038 		 * to pending requests
1039 		 */
1040 		/* LINTED pointer cast */
1041 		*(int *)info = ct->ct_bufferPendingSize;
1042 		break;
1043 
1044 	case CLSET_CONNMAXREC_SIZE:
1045 		/* Cannot resize the buffer if it is used. */
1046 		if (ct->ct_bufferPendingSize != 0) {
1047 			rpc_fd_unlock(vctbl, ct->ct_fd);
1048 			return (FALSE);
1049 		}
1050 		/*
1051 		 * If the new size is equal to the current size,
1052 		 * there is nothing to do.
1053 		 */
1054 		/* LINTED pointer cast */
1055 		if (ct->ct_bufferSize == *(uint_t *)info)
1056 			break;
1057 
1058 		/* LINTED pointer cast */
1059 		ct->ct_bufferSize = *(uint_t *)info;
1060 		if (ct->ct_buffer) {
1061 			free(ct->ct_buffer);
1062 			ct->ct_buffer = NULL;
1063 			ct->ct_bufferReadPtr = ct->ct_bufferWritePtr = NULL;
1064 		}
1065 		break;
1066 
1067 	case CLGET_CONNMAXREC_SIZE:
1068 		/*
1069 		 * Returns the size of buffer allocated
1070 		 * to pending requests
1071 		 */
1072 		/* LINTED pointer cast */
1073 		*(uint_t *)info = ct->ct_bufferSize;
1074 		break;
1075 
1076 	default:
1077 		rpc_fd_unlock(vctbl, ct->ct_fd);
1078 		return (FALSE);
1079 	}
1080 	rpc_fd_unlock(vctbl, ct->ct_fd);
1081 	return (TRUE);
1082 }
1083 
1084 static void
1085 clnt_vc_destroy(CLIENT *cl)
1086 {
1087 /* LINTED pointer alignment */
1088 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
1089 	int ct_fd = ct->ct_fd;
1090 
1091 	(void) rpc_fd_lock(vctbl, ct_fd);
1092 
1093 	if (ct->ct_io_mode == RPC_CL_NONBLOCKING) {
1094 		(void) do_flush(ct, RPC_CL_BLOCKING_FLUSH);
1095 		(void) unregister_nb(ct);
1096 	}
1097 
1098 	if (ct->ct_closeit)
1099 		(void) t_close(ct_fd);
1100 	XDR_DESTROY(&(ct->ct_xdrs));
1101 	if (ct->ct_addr.buf)
1102 		free(ct->ct_addr.buf);
1103 	free(ct);
1104 	if (cl->cl_netid && cl->cl_netid[0])
1105 		free(cl->cl_netid);
1106 	if (cl->cl_tp && cl->cl_tp[0])
1107 		free(cl->cl_tp);
1108 	free(cl);
1109 	rpc_fd_unlock(vctbl, ct_fd);
1110 }
1111 
1112 /*
1113  * Interface between xdr serializer and vc connection.
1114  * Behaves like the system calls, read & write, but keeps some error state
1115  * around for the rpc level.
1116  */
1117 static int
1118 read_vc(void *ct_tmp, caddr_t buf, int len)
1119 {
1120 	static pthread_key_t pfdp_key;
1121 	struct pollfd *pfdp;
1122 	int npfd;		/* total number of pfdp allocated */
1123 	struct ct_data *ct = ct_tmp;
1124 	struct timeval starttime;
1125 	struct timeval curtime;
1126 	int poll_time;
1127 	int delta;
1128 
1129 	if (len == 0)
1130 		return (0);
1131 
1132 	/*
1133 	 * Allocate just one the first time.  thr_get_storage() may
1134 	 * return a larger buffer, left over from the last time we were
1135 	 * here, but that's OK.  realloc() will deal with it properly.
1136 	 */
1137 	npfd = 1;
1138 	pfdp = thr_get_storage(&pfdp_key, sizeof (struct pollfd), free);
1139 	if (pfdp == NULL) {
1140 		(void) syslog(LOG_ERR, clnt_vc_errstr,
1141 			clnt_read_vc_str, __no_mem_str);
1142 		rpc_callerr.re_status = RPC_SYSTEMERROR;
1143 		rpc_callerr.re_errno = errno;
1144 		rpc_callerr.re_terrno = 0;
1145 		return (-1);
1146 	}
1147 
1148 	/*
1149 	 *	N.B.:  slot 0 in the pollfd array is reserved for the file
1150 	 *	descriptor we're really interested in (as opposed to the
1151 	 *	callback descriptors).
1152 	 */
1153 	pfdp[0].fd = ct->ct_fd;
1154 	pfdp[0].events = MASKVAL;
1155 	pfdp[0].revents = 0;
1156 	poll_time = ct->ct_wait;
1157 	if (gettimeofday(&starttime, NULL) == -1) {
1158 		syslog(LOG_ERR, "Unable to get time of day: %m");
1159 		return (-1);
1160 	}
1161 
1162 	for (;;) {
1163 		extern void (*_svc_getreqset_proc)();
1164 		extern pollfd_t *svc_pollfd;
1165 		extern int svc_max_pollfd;
1166 		int fds;
1167 
1168 		/* VARIABLES PROTECTED BY svc_fd_lock: svc_pollfd */
1169 
1170 		if (_svc_getreqset_proc) {
1171 			sig_rw_rdlock(&svc_fd_lock);
1172 
1173 			/* reallocate pfdp to svc_max_pollfd +1 */
1174 			if (npfd != (svc_max_pollfd + 1)) {
1175 				struct pollfd *tmp_pfdp = realloc(pfdp,
1176 						sizeof (struct pollfd) *
1177 						(svc_max_pollfd + 1));
1178 				if (tmp_pfdp == NULL) {
1179 					sig_rw_unlock(&svc_fd_lock);
1180 					(void) syslog(LOG_ERR, clnt_vc_errstr,
1181 						clnt_read_vc_str, __no_mem_str);
1182 					rpc_callerr.re_status = RPC_SYSTEMERROR;
1183 					rpc_callerr.re_errno = errno;
1184 					rpc_callerr.re_terrno = 0;
1185 					return (-1);
1186 				}
1187 
1188 				pfdp = tmp_pfdp;
1189 				npfd = svc_max_pollfd + 1;
1190 				(void) pthread_setspecific(pfdp_key, pfdp);
1191 			}
1192 			if (npfd > 1)
1193 				(void) memcpy(&pfdp[1], svc_pollfd,
1194 				    sizeof (struct pollfd) * (npfd - 1));
1195 
1196 			sig_rw_unlock(&svc_fd_lock);
1197 		} else {
1198 			npfd = 1;	/* don't forget about pfdp[0] */
1199 		}
1200 
1201 		switch (fds = poll(pfdp, npfd, poll_time)) {
1202 		case 0:
1203 			rpc_callerr.re_status = RPC_TIMEDOUT;
1204 			return (-1);
1205 
1206 		case -1:
1207 			if (errno != EINTR)
1208 				continue;
1209 			else {
1210 				/*
1211 				 * interrupted by another signal,
1212 				 * update time_waited
1213 				 */
1214 
1215 				if (gettimeofday(&curtime, NULL) == -1) {
1216 					syslog(LOG_ERR,
1217 					    "Unable to get time of day:  %m");
1218 					errno = 0;
1219 					continue;
1220 				};
1221 				delta = (curtime.tv_sec -
1222 						starttime.tv_sec) * 1000 +
1223 					(curtime.tv_usec -
1224 						starttime.tv_usec) / 1000;
1225 				poll_time -= delta;
1226 				if (poll_time < 0) {
1227 					rpc_callerr.re_status =
1228 						RPC_TIMEDOUT;
1229 					errno = 0;
1230 					return (-1);
1231 				} else {
1232 					errno = 0; /* reset it */
1233 					continue;
1234 				}
1235 			}
1236 		}
1237 
1238 		if (pfdp[0].revents == 0) {
1239 			/* must be for server side of the house */
1240 			(*_svc_getreqset_proc)(&pfdp[1], fds);
1241 			continue;	/* do poll again */
1242 		}
1243 
1244 		if (pfdp[0].revents & POLLNVAL) {
1245 			rpc_callerr.re_status = RPC_CANTRECV;
1246 			/*
1247 			 *	Note:  we're faking errno here because we
1248 			 *	previously would have expected select() to
1249 			 *	return -1 with errno EBADF.  Poll(BA_OS)
1250 			 *	returns 0 and sets the POLLNVAL revents flag
1251 			 *	instead.
1252 			 */
1253 			rpc_callerr.re_errno = errno = EBADF;
1254 			return (-1);
1255 		}
1256 
1257 		if (pfdp[0].revents & (POLLERR | POLLHUP)) {
1258 			rpc_callerr.re_status = RPC_CANTRECV;
1259 			rpc_callerr.re_errno = errno = EPIPE;
1260 			return (-1);
1261 		}
1262 		break;
1263 	}
1264 
1265 	switch (len = t_rcvall(ct->ct_fd, buf, len)) {
1266 	case 0:
1267 		/* premature eof */
1268 		rpc_callerr.re_errno = ENOLINK;
1269 		rpc_callerr.re_terrno = 0;
1270 		rpc_callerr.re_status = RPC_CANTRECV;
1271 		len = -1;	/* it's really an error */
1272 		break;
1273 
1274 	case -1:
1275 		rpc_callerr.re_terrno = t_errno;
1276 		rpc_callerr.re_errno = 0;
1277 		rpc_callerr.re_status = RPC_CANTRECV;
1278 		break;
1279 	}
1280 	return (len);
1281 }
1282 
1283 static int
1284 write_vc(void *ct_tmp, caddr_t buf, int len)
1285 {
1286 	int i, cnt;
1287 	struct ct_data *ct = ct_tmp;
1288 	int flag;
1289 	int maxsz;
1290 
1291 	maxsz = ct->ct_tsdu;
1292 
1293 	/* Handle the non-blocking mode */
1294 	if (ct->ct_is_oneway && ct->ct_io_mode == RPC_CL_NONBLOCKING) {
1295 		/*
1296 		 * Test a special case here. If the length of the current
1297 		 * write is greater than the transport data unit, and the
1298 		 * mode is non blocking, we return RPC_CANTSEND.
1299 		 * XXX  this is not very clean.
1300 		 */
1301 		if (maxsz > 0 && len > maxsz) {
1302 			rpc_callerr.re_terrno = errno;
1303 			rpc_callerr.re_errno = 0;
1304 			rpc_callerr.re_status = RPC_CANTSEND;
1305 			return (-1);
1306 		}
1307 
1308 		len = nb_send(ct, buf, (unsigned)len);
1309 		if (len == -1) {
1310 			rpc_callerr.re_terrno = errno;
1311 			rpc_callerr.re_errno = 0;
1312 			rpc_callerr.re_status = RPC_CANTSEND;
1313 		} else if (len == -2) {
1314 			rpc_callerr.re_terrno = 0;
1315 			rpc_callerr.re_errno = 0;
1316 			rpc_callerr.re_status = RPC_CANTSTORE;
1317 		}
1318 		return (len);
1319 	}
1320 
1321 	if ((maxsz == 0) || (maxsz == -1)) {
1322 		/*
1323 		 * T_snd may return -1 for error on connection (connection
1324 		 * needs to be repaired/closed, and -2 for flow-control
1325 		 * handling error (no operation to do, just wait and call
1326 		 * T_Flush()).
1327 		 */
1328 		if ((len = t_snd(ct->ct_fd, buf, (unsigned)len, 0)) == -1) {
1329 			rpc_callerr.re_terrno = t_errno;
1330 			rpc_callerr.re_errno = 0;
1331 			rpc_callerr.re_status = RPC_CANTSEND;
1332 		}
1333 		return (len);
1334 	}
1335 
1336 	/*
1337 	 * This for those transports which have a max size for data.
1338 	 */
1339 	for (cnt = len, i = 0; cnt > 0; cnt -= i, buf += i) {
1340 		flag = cnt > maxsz ? T_MORE : 0;
1341 		if ((i = t_snd(ct->ct_fd, buf, (unsigned)MIN(cnt, maxsz),
1342 				flag)) == -1) {
1343 			rpc_callerr.re_terrno = t_errno;
1344 			rpc_callerr.re_errno = 0;
1345 			rpc_callerr.re_status = RPC_CANTSEND;
1346 			return (-1);
1347 		}
1348 	}
1349 	return (len);
1350 }
1351 
1352 /*
1353  * Receive the required bytes of data, even if it is fragmented.
1354  */
1355 static int
1356 t_rcvall(int fd, char *buf, int len)
1357 {
1358 	int moreflag;
1359 	int final = 0;
1360 	int res;
1361 
1362 	do {
1363 		moreflag = 0;
1364 		res = t_rcv(fd, buf, (unsigned)len, &moreflag);
1365 		if (res == -1) {
1366 			if (t_errno == TLOOK)
1367 				switch (t_look(fd)) {
1368 				case T_DISCONNECT:
1369 					(void) t_rcvdis(fd, NULL);
1370 					(void) t_snddis(fd, NULL);
1371 					return (-1);
1372 				case T_ORDREL:
1373 				/* Received orderly release indication */
1374 					(void) t_rcvrel(fd);
1375 				/* Send orderly release indicator */
1376 					(void) t_sndrel(fd);
1377 					return (-1);
1378 				default:
1379 					return (-1);
1380 				}
1381 		} else if (res == 0) {
1382 			return (0);
1383 		}
1384 		final += res;
1385 		buf += res;
1386 		len -= res;
1387 	} while ((len > 0) && (moreflag & T_MORE));
1388 	return (final);
1389 }
1390 
1391 static struct clnt_ops *
1392 clnt_vc_ops(void)
1393 {
1394 	static struct clnt_ops ops;
1395 	extern mutex_t	ops_lock;
1396 
1397 	/* VARIABLES PROTECTED BY ops_lock: ops */
1398 
1399 	sig_mutex_lock(&ops_lock);
1400 	if (ops.cl_call == NULL) {
1401 		ops.cl_call = clnt_vc_call;
1402 		ops.cl_send = clnt_vc_send;
1403 		ops.cl_abort = clnt_vc_abort;
1404 		ops.cl_geterr = clnt_vc_geterr;
1405 		ops.cl_freeres = clnt_vc_freeres;
1406 		ops.cl_destroy = clnt_vc_destroy;
1407 		ops.cl_control = clnt_vc_control;
1408 	}
1409 	sig_mutex_unlock(&ops_lock);
1410 	return (&ops);
1411 }
1412 
1413 /*
1414  * Make sure that the time is not garbage.   -1 value is disallowed.
1415  * Note this is different from time_not_ok in clnt_dg.c
1416  */
1417 static bool_t
1418 time_not_ok(struct timeval *t)
1419 {
1420 	return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
1421 		t->tv_usec <= -1 || t->tv_usec > 1000000);
1422 }
1423 
1424 
1425 /* Compute the # of bytes that remains until the end of the buffer */
1426 #define	REMAIN_BYTES(p) (ct->ct_bufferSize-(ct->ct_##p - ct->ct_buffer))
1427 
1428 static int
1429 addInBuffer(struct ct_data *ct, char *dataToAdd, unsigned int nBytes)
1430 {
1431 	if (NULL == ct->ct_buffer) {
1432 		/* Buffer not allocated yet. */
1433 		char *buffer;
1434 
1435 		buffer = malloc(ct->ct_bufferSize);
1436 		if (NULL == buffer) {
1437 			errno = ENOMEM;
1438 			return (-1);
1439 		}
1440 		(void) memcpy(buffer, dataToAdd, nBytes);
1441 
1442 		ct->ct_buffer = buffer;
1443 		ct->ct_bufferReadPtr = buffer;
1444 		ct->ct_bufferWritePtr = buffer + nBytes;
1445 		ct->ct_bufferPendingSize = nBytes;
1446 	} else {
1447 		/*
1448 		 * For an already allocated buffer, two mem copies
1449 		 * might be needed, depending on the current
1450 		 * writing position.
1451 		 */
1452 
1453 		/* Compute the length of the first copy. */
1454 		int len = MIN(nBytes, REMAIN_BYTES(bufferWritePtr));
1455 
1456 		ct->ct_bufferPendingSize += nBytes;
1457 
1458 		(void) memcpy(ct->ct_bufferWritePtr, dataToAdd, len);
1459 		ct->ct_bufferWritePtr += len;
1460 		nBytes -= len;
1461 		if (0 == nBytes) {
1462 			/* One memcopy needed. */
1463 
1464 			/*
1465 			 * If the write pointer is at the end of the buffer,
1466 			 * wrap it now.
1467 			 */
1468 			if (ct->ct_bufferWritePtr ==
1469 			    (ct->ct_buffer + ct->ct_bufferSize)) {
1470 				ct->ct_bufferWritePtr = ct->ct_buffer;
1471 			}
1472 		} else {
1473 			/* Two memcopy needed. */
1474 			dataToAdd += len;
1475 
1476 			/*
1477 			 * Copy the remaining data to the beginning of the
1478 			 * buffer
1479 			 */
1480 			(void) memcpy(ct->ct_buffer, dataToAdd, nBytes);
1481 			ct->ct_bufferWritePtr = ct->ct_buffer + nBytes;
1482 		}
1483 	}
1484 	return (0);
1485 }
1486 
1487 static void
1488 consumeFromBuffer(struct ct_data *ct, unsigned int nBytes)
1489 {
1490 	ct->ct_bufferPendingSize -= nBytes;
1491 	if (ct->ct_bufferPendingSize == 0) {
1492 		/*
1493 		 * If the buffer contains no data, we set the two pointers at
1494 		 * the beginning of the buffer (to miminize buffer wraps).
1495 		 */
1496 		ct->ct_bufferReadPtr = ct->ct_bufferWritePtr = ct->ct_buffer;
1497 	} else {
1498 		ct->ct_bufferReadPtr += nBytes;
1499 		if (ct->ct_bufferReadPtr >
1500 		    ct->ct_buffer + ct->ct_bufferSize) {
1501 			ct->ct_bufferReadPtr -= ct->ct_bufferSize;
1502 		}
1503 	}
1504 }
1505 
1506 static int
1507 iovFromBuffer(struct ct_data *ct, struct iovec *iov)
1508 {
1509 	int l;
1510 
1511 	if (ct->ct_bufferPendingSize == 0)
1512 		return (0);
1513 
1514 	l = REMAIN_BYTES(bufferReadPtr);
1515 	if (l < ct->ct_bufferPendingSize) {
1516 		/* Buffer in two fragments. */
1517 		iov[0].iov_base = ct->ct_bufferReadPtr;
1518 		iov[0].iov_len  = l;
1519 
1520 		iov[1].iov_base = ct->ct_buffer;
1521 		iov[1].iov_len  = ct->ct_bufferPendingSize - l;
1522 		return (2);
1523 	} else {
1524 		/* Buffer in one fragment. */
1525 		iov[0].iov_base = ct->ct_bufferReadPtr;
1526 		iov[0].iov_len  = ct->ct_bufferPendingSize;
1527 		return (1);
1528 	}
1529 }
1530 
1531 static bool_t
1532 set_flush_mode(struct ct_data *ct, int mode)
1533 {
1534 	switch (mode) {
1535 	case RPC_CL_BLOCKING_FLUSH:
1536 		/* flush as most as possible without blocking */
1537 	case RPC_CL_BESTEFFORT_FLUSH:
1538 		/* flush the buffer completely (possibly blocking) */
1539 	case RPC_CL_DEFAULT_FLUSH:
1540 		/* flush according to the currently defined policy */
1541 		ct->ct_blocking_mode = mode;
1542 		return (TRUE);
1543 	default:
1544 		return (FALSE);
1545 	}
1546 }
1547 
1548 static bool_t
1549 set_io_mode(struct ct_data *ct, int ioMode)
1550 {
1551 	switch (ioMode) {
1552 	case RPC_CL_BLOCKING:
1553 		if (ct->ct_io_mode == RPC_CL_NONBLOCKING) {
1554 			if (NULL != ct->ct_buffer) {
1555 				/*
1556 				 * If a buffer was allocated for this
1557 				 * connection, flush it now, and free it.
1558 				 */
1559 				(void) do_flush(ct, RPC_CL_BLOCKING_FLUSH);
1560 				free(ct->ct_buffer);
1561 				ct->ct_buffer = NULL;
1562 			}
1563 			(void) unregister_nb(ct);
1564 			ct->ct_io_mode = ioMode;
1565 		}
1566 		break;
1567 	case RPC_CL_NONBLOCKING:
1568 		if (ct->ct_io_mode == RPC_CL_BLOCKING) {
1569 			if (-1 == register_nb(ct)) {
1570 				return (FALSE);
1571 			}
1572 			ct->ct_io_mode = ioMode;
1573 		}
1574 		break;
1575 	default:
1576 		return (FALSE);
1577 	}
1578 	return (TRUE);
1579 }
1580 
1581 static int
1582 do_flush(struct ct_data *ct, uint_t flush_mode)
1583 {
1584 	int result;
1585 	if (ct->ct_bufferPendingSize == 0) {
1586 		return (0);
1587 	}
1588 
1589 	switch (flush_mode) {
1590 	case RPC_CL_BLOCKING_FLUSH:
1591 		if (!set_blocking_connection(ct, TRUE)) {
1592 			return (-1);
1593 		}
1594 		while (ct->ct_bufferPendingSize > 0) {
1595 			if (REMAIN_BYTES(bufferReadPtr) <
1596 			    ct->ct_bufferPendingSize) {
1597 				struct iovec iov[2];
1598 				(void) iovFromBuffer(ct, iov);
1599 				result = writev(ct->ct_fd, iov, 2);
1600 			} else {
1601 				result = t_snd(ct->ct_fd, ct->ct_bufferReadPtr,
1602 				    ct->ct_bufferPendingSize, 0);
1603 			}
1604 			if (result < 0) {
1605 				return (-1);
1606 			}
1607 			consumeFromBuffer(ct, result);
1608 		}
1609 
1610 		break;
1611 
1612 	case RPC_CL_BESTEFFORT_FLUSH:
1613 		(void) set_blocking_connection(ct, FALSE);
1614 		if (REMAIN_BYTES(bufferReadPtr) < ct->ct_bufferPendingSize) {
1615 			struct iovec iov[2];
1616 			(void) iovFromBuffer(ct, iov);
1617 			result = writev(ct->ct_fd, iov, 2);
1618 		} else {
1619 			result = t_snd(ct->ct_fd, ct->ct_bufferReadPtr,
1620 			    ct->ct_bufferPendingSize, 0);
1621 		}
1622 		if (result < 0) {
1623 			if (errno != EWOULDBLOCK) {
1624 				perror("flush");
1625 				return (-1);
1626 			}
1627 			return (0);
1628 		}
1629 		if (result > 0)
1630 			consumeFromBuffer(ct, result);
1631 		break;
1632 	}
1633 	return (0);
1634 }
1635 
1636 /*
1637  * Non blocking send.
1638  */
1639 
1640 static int
1641 nb_send(struct ct_data *ct, void *buff, unsigned int nBytes)
1642 {
1643 	int result;
1644 
1645 	if (!(ntohl(*(uint32_t *)buff) & 2^31)) {
1646 		return (-1);
1647 	}
1648 
1649 	/*
1650 	 * Check to see if the current message can be stored fully in the
1651 	 * buffer. We have to check this now because it may be impossible
1652 	 * to send any data, so the message must be stored in the buffer.
1653 	 */
1654 	if (nBytes > (ct->ct_bufferSize - ct->ct_bufferPendingSize)) {
1655 		/* Try to flush  (to free some space). */
1656 		(void) do_flush(ct, RPC_CL_BESTEFFORT_FLUSH);
1657 
1658 		/* Can we store the message now ? */
1659 		if (nBytes > (ct->ct_bufferSize - ct->ct_bufferPendingSize))
1660 			return (-2);
1661 	}
1662 
1663 	(void) set_blocking_connection(ct, FALSE);
1664 
1665 	/*
1666 	 * If there is no data pending, we can simply try
1667 	 * to send our data.
1668 	 */
1669 	if (ct->ct_bufferPendingSize == 0) {
1670 		result = t_snd(ct->ct_fd, buff, nBytes, 0);
1671 		if (result == -1) {
1672 			if (errno == EWOULDBLOCK) {
1673 				result = 0;
1674 			} else {
1675 				perror("send");
1676 				return (-1);
1677 			}
1678 		}
1679 		/*
1680 		 * If we have not sent all data, we must store them
1681 		 * in the buffer.
1682 		 */
1683 		if (result != nBytes) {
1684 			if (addInBuffer(ct, (char *)buff + result,
1685 			    nBytes - result) == -1) {
1686 				return (-1);
1687 			}
1688 		}
1689 	} else {
1690 		/*
1691 		 * Some data pending in the buffer.  We try to send
1692 		 * both buffer data and current message in one shot.
1693 		 */
1694 		struct iovec iov[3];
1695 		int i = iovFromBuffer(ct, &iov[0]);
1696 
1697 		iov[i].iov_base = buff;
1698 		iov[i].iov_len  = nBytes;
1699 
1700 		result = writev(ct->ct_fd, iov, i+1);
1701 		if (result == -1) {
1702 			if (errno == EWOULDBLOCK) {
1703 				/* No bytes sent */
1704 				result = 0;
1705 			} else {
1706 				return (-1);
1707 			}
1708 		}
1709 
1710 		/*
1711 		 * Add the bytes from the message
1712 		 * that we have not sent.
1713 		 */
1714 		if (result <= ct->ct_bufferPendingSize) {
1715 			/* No bytes from the message sent */
1716 			consumeFromBuffer(ct, result);
1717 			if (addInBuffer(ct, buff, nBytes) == -1) {
1718 				return (-1);
1719 			}
1720 		} else {
1721 			/*
1722 			 * Some bytes of the message are sent.
1723 			 * Compute the length of the message that has
1724 			 * been sent.
1725 			 */
1726 			int len = result - ct->ct_bufferPendingSize;
1727 
1728 			/* So, empty the buffer. */
1729 			ct->ct_bufferReadPtr = ct->ct_buffer;
1730 			ct->ct_bufferWritePtr = ct->ct_buffer;
1731 			ct->ct_bufferPendingSize = 0;
1732 
1733 			/* And add the remaining part of the message. */
1734 			if (len != nBytes) {
1735 				if (addInBuffer(ct, (char *)buff + len,
1736 					nBytes-len) == -1) {
1737 					return (-1);
1738 				}
1739 			}
1740 		}
1741 	}
1742 	return (nBytes);
1743 }
1744 
1745 static void
1746 flush_registered_clients(void)
1747 {
1748 	struct nb_reg_node *node;
1749 
1750 	if (LIST_ISEMPTY(nb_first)) {
1751 		return;
1752 	}
1753 
1754 	LIST_FOR_EACH(nb_first, node) {
1755 		(void) do_flush(node->ct, RPC_CL_BLOCKING_FLUSH);
1756 	}
1757 }
1758 
1759 static int
1760 allocate_chunk(void)
1761 {
1762 #define	CHUNK_SIZE 16
1763 	struct nb_reg_node *chk =
1764 	    malloc(sizeof (struct nb_reg_node) * CHUNK_SIZE);
1765 	struct nb_reg_node *n;
1766 	int i;
1767 
1768 	if (NULL == chk) {
1769 		return (-1);
1770 	}
1771 
1772 	n = chk;
1773 	for (i = 0; i < CHUNK_SIZE-1; ++i) {
1774 		n[i].next = &(n[i+1]);
1775 	}
1776 	n[CHUNK_SIZE-1].next = (struct nb_reg_node *)&nb_free;
1777 	nb_free = chk;
1778 	return (0);
1779 }
1780 
1781 static int
1782 register_nb(struct ct_data *ct)
1783 {
1784 	struct nb_reg_node *node;
1785 
1786 	(void) mutex_lock(&nb_list_mutex);
1787 
1788 	if (LIST_ISEMPTY(nb_free) && (allocate_chunk() == -1)) {
1789 		(void) mutex_unlock(&nb_list_mutex);
1790 		errno = ENOMEM;
1791 		return (-1);
1792 	}
1793 
1794 	if (!exit_handler_set) {
1795 		(void) atexit(flush_registered_clients);
1796 		exit_handler_set = TRUE;
1797 	}
1798 	/* Get the first free node */
1799 	LIST_EXTRACT(nb_free, node);
1800 
1801 	node->ct = ct;
1802 
1803 	LIST_ADD(nb_first, node);
1804 	(void) mutex_unlock(&nb_list_mutex);
1805 
1806 	return (0);
1807 }
1808 
1809 static int
1810 unregister_nb(struct ct_data *ct)
1811 {
1812 	struct nb_reg_node *node;
1813 
1814 	(void) mutex_lock(&nb_list_mutex);
1815 	assert(!LIST_ISEMPTY(nb_first));
1816 
1817 	node = nb_first;
1818 	LIST_FOR_EACH(nb_first, node) {
1819 		if (node->next->ct == ct) {
1820 			/* Get the node to unregister. */
1821 			struct nb_reg_node *n = node->next;
1822 			node->next = n->next;
1823 
1824 			n->ct = NULL;
1825 			LIST_ADD(nb_free, n);
1826 			break;
1827 		}
1828 	}
1829 	(void) mutex_unlock(&nb_list_mutex);
1830 	return (0);
1831 }
1832