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