Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/rpc/clnt_vc.c
39476 views
1
/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-3-Clause
5
*
6
* Copyright (c) 2009, Sun Microsystems, Inc.
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions are met:
11
* - Redistributions of source code must retain the above copyright notice,
12
* this list of conditions and the following disclaimer.
13
* - Redistributions in binary form must reproduce the above copyright notice,
14
* this list of conditions and the following disclaimer in the documentation
15
* and/or other materials provided with the distribution.
16
* - Neither the name of Sun Microsystems, Inc. nor the names of its
17
* contributors may be used to endorse or promote products derived
18
* from this software without specific prior written permission.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
* POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
/*
34
* clnt_tcp.c, Implements a TCP/IP based, client side RPC.
35
*
36
* Copyright (C) 1984, Sun Microsystems, Inc.
37
*
38
* TCP based RPC supports 'batched calls'.
39
* A sequence of calls may be batched-up in a send buffer. The rpc call
40
* return immediately to the client even though the call was not necessarily
41
* sent. The batching occurs if the results' xdr routine is NULL (0) AND
42
* the rpc timeout value is zero (see clnt.h, rpc).
43
*
44
* Clients should NOT casually batch calls that in fact return results; that is,
45
* the server side should be aware that a call is batched and not produce any
46
* return message. Batched calls that produce many result messages can
47
* deadlock (netlock) the client and the server....
48
*
49
* Now go hang yourself.
50
*/
51
52
#include "namespace.h"
53
#include "reentrant.h"
54
#include <sys/types.h>
55
#include <sys/poll.h>
56
#include <sys/syslog.h>
57
#include <sys/socket.h>
58
#include <sys/tree.h>
59
#include <sys/un.h>
60
#include <sys/uio.h>
61
62
#include <arpa/inet.h>
63
#include <assert.h>
64
#include <err.h>
65
#include <errno.h>
66
#include <netdb.h>
67
#include <pthread.h>
68
#include <stdio.h>
69
#include <stdbool.h>
70
#include <stdlib.h>
71
#include <string.h>
72
#include <unistd.h>
73
#include <signal.h>
74
75
#include <rpc/rpc.h>
76
#include <rpc/rpcsec_gss.h>
77
#include "un-namespace.h"
78
#include "rpc_com.h"
79
#include "mt_misc.h"
80
81
#define MCALL_MSG_SIZE 24
82
83
struct cmessage {
84
struct cmsghdr cmsg;
85
struct cmsgcred cmcred;
86
};
87
88
static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
89
xdrproc_t, void *, struct timeval);
90
static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
91
static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
92
static void clnt_vc_abort(CLIENT *);
93
static bool_t clnt_vc_control(CLIENT *, u_int, void *);
94
static void clnt_vc_destroy(CLIENT *);
95
static struct clnt_ops *clnt_vc_ops(void);
96
static bool_t time_not_ok(struct timeval *);
97
static int read_vc(void *, void *, int);
98
static int write_vc(void *, void *, int);
99
static int __msgwrite(int, void *, size_t);
100
static int __msgread(int, void *, size_t);
101
102
struct ct_data {
103
int ct_fd; /* connection's fd */
104
bool_t ct_closeit; /* close it on destroy */
105
struct timeval ct_wait; /* wait interval in milliseconds */
106
bool_t ct_waitset; /* wait set by clnt_control? */
107
struct netbuf ct_addr; /* remote addr */
108
struct rpc_err ct_error;
109
union {
110
char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
111
u_int32_t ct_mcalli;
112
} ct_u;
113
u_int ct_mpos; /* pos after marshal */
114
XDR ct_xdrs; /* XDR stream */
115
};
116
117
/*
118
* This machinery implements per-fd locks for MT-safety. It is not
119
* sufficient to do per-CLIENT handle locks for MT-safety because a
120
* user may create more than one CLIENT handle with the same fd behind
121
* it. Therefore, we allocate an associative array of flags and condition
122
* variables (vc_fd). The flags and the array are protected by the
123
* clnt_fd_lock mutex. vc_fd_lock[fd] == 1 => a call is active on some
124
* CLIENT handle created for that fd. The current implementation holds
125
* locks across the entire RPC and reply. Yes, this is silly, and as soon
126
* as this code is proven to work, this should be the first thing fixed.
127
* One step at a time.
128
*/
129
struct vc_fd {
130
RB_ENTRY(vc_fd) vc_link;
131
int fd;
132
mutex_t mtx;
133
};
134
static inline int
135
cmp_vc_fd(struct vc_fd *a, struct vc_fd *b)
136
{
137
if (a->fd > b->fd) {
138
return (1);
139
} else if (a->fd < b->fd) {
140
return (-1);
141
} else {
142
return (0);
143
}
144
}
145
RB_HEAD(vc_fd_list, vc_fd);
146
RB_PROTOTYPE(vc_fd_list, vc_fd, vc_link, cmp_vc_fd);
147
RB_GENERATE(vc_fd_list, vc_fd, vc_link, cmp_vc_fd);
148
struct vc_fd_list vc_fd_head = RB_INITIALIZER(&vc_fd_head);
149
150
/*
151
* Find the lock structure for the given file descriptor, or initialize it if
152
* it does not already exist. The clnt_fd_lock mutex must be held.
153
*/
154
static struct vc_fd *
155
vc_fd_find(int fd)
156
{
157
struct vc_fd key, *elem;
158
159
key.fd = fd;
160
elem = RB_FIND(vc_fd_list, &vc_fd_head, &key);
161
if (elem == NULL) {
162
elem = calloc(1, sizeof(*elem));
163
elem->fd = fd;
164
mutex_init(&elem->mtx, NULL);
165
RB_INSERT(vc_fd_list, &vc_fd_head, elem);
166
}
167
return (elem);
168
}
169
170
static void
171
release_fd_lock(struct vc_fd *elem, sigset_t mask)
172
{
173
mutex_unlock(&elem->mtx);
174
thr_sigsetmask(SIG_SETMASK, &mask, NULL);
175
}
176
177
static const char clnt_vc_errstr[] = "%s : %s";
178
static const char clnt_vc_str[] = "clnt_vc_create";
179
static const char __no_mem_str[] = "out of memory";
180
181
/*
182
* Create a client handle for a connection.
183
* Default options are set, which the user can change using clnt_control()'s.
184
* The rpc/vc package does buffering similar to stdio, so the client
185
* must pick send and receive buffer sizes, 0 => use the default.
186
* NB: fd is copied into a private area.
187
* NB: The rpch->cl_auth is set null authentication. Caller may wish to
188
* set this something more useful.
189
*
190
* fd should be an open socket
191
*
192
* fd - open file descriptor
193
* raddr - servers address
194
* prog - program number
195
* vers - version number
196
* sendsz - buffer send size
197
* recvsz - buffer recv size
198
*/
199
CLIENT *
200
clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog,
201
const rpcvers_t vers, u_int sendsz, u_int recvsz)
202
{
203
CLIENT *cl; /* client handle */
204
struct ct_data *ct = NULL; /* client handle */
205
struct timeval now;
206
struct rpc_msg call_msg;
207
static u_int32_t disrupt;
208
struct sockaddr_storage ss;
209
socklen_t slen;
210
struct __rpc_sockinfo si;
211
212
if (disrupt == 0)
213
disrupt = (u_int32_t)(long)raddr;
214
215
cl = (CLIENT *)mem_alloc(sizeof (*cl));
216
ct = (struct ct_data *)mem_alloc(sizeof (*ct));
217
if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
218
(void) syslog(LOG_ERR, clnt_vc_errstr,
219
clnt_vc_str, __no_mem_str);
220
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
221
rpc_createerr.cf_error.re_errno = errno;
222
goto err;
223
}
224
ct->ct_addr.buf = NULL;
225
226
/*
227
* XXX - fvdl connecting while holding a mutex?
228
*/
229
slen = sizeof ss;
230
if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
231
if (errno != ENOTCONN) {
232
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
233
rpc_createerr.cf_error.re_errno = errno;
234
mutex_unlock(&clnt_fd_lock);
235
goto err;
236
}
237
if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
238
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
239
rpc_createerr.cf_error.re_errno = errno;
240
mutex_unlock(&clnt_fd_lock);
241
goto err;
242
}
243
}
244
mutex_unlock(&clnt_fd_lock);
245
if (!__rpc_fd2sockinfo(fd, &si))
246
goto err;
247
248
ct->ct_closeit = FALSE;
249
250
/*
251
* Set up private data struct
252
*/
253
ct->ct_fd = fd;
254
ct->ct_wait.tv_usec = 0;
255
ct->ct_waitset = FALSE;
256
ct->ct_addr.buf = malloc(raddr->maxlen);
257
if (ct->ct_addr.buf == NULL)
258
goto err;
259
memcpy(ct->ct_addr.buf, raddr->buf, raddr->len);
260
ct->ct_addr.len = raddr->len;
261
ct->ct_addr.maxlen = raddr->maxlen;
262
263
/*
264
* Initialize call message
265
*/
266
(void)gettimeofday(&now, NULL);
267
call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
268
call_msg.rm_direction = CALL;
269
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
270
call_msg.rm_call.cb_prog = (u_int32_t)prog;
271
call_msg.rm_call.cb_vers = (u_int32_t)vers;
272
273
/*
274
* pre-serialize the static part of the call msg and stash it away
275
*/
276
xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
277
XDR_ENCODE);
278
if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
279
if (ct->ct_closeit) {
280
(void)_close(fd);
281
}
282
goto err;
283
}
284
ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
285
XDR_DESTROY(&(ct->ct_xdrs));
286
assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE);
287
288
/*
289
* Create a client handle which uses xdrrec for serialization
290
* and authnone for authentication.
291
*/
292
cl->cl_ops = clnt_vc_ops();
293
cl->cl_private = ct;
294
cl->cl_auth = authnone_create();
295
sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
296
recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
297
xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
298
cl->cl_private, read_vc, write_vc);
299
return (cl);
300
301
err:
302
if (ct) {
303
if (ct->ct_addr.len)
304
mem_free(ct->ct_addr.buf, ct->ct_addr.len);
305
mem_free(ct, sizeof (struct ct_data));
306
}
307
if (cl)
308
mem_free(cl, sizeof (CLIENT));
309
return ((CLIENT *)NULL);
310
}
311
312
static enum clnt_stat
313
clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
314
xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
315
{
316
struct ct_data *ct = (struct ct_data *) cl->cl_private;
317
XDR *xdrs = &(ct->ct_xdrs);
318
struct rpc_msg reply_msg;
319
struct vc_fd *elem;
320
u_int32_t x_id;
321
u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
322
bool_t shipnow;
323
int refreshes = 2;
324
sigset_t mask, newmask;
325
bool_t reply_stat;
326
327
assert(cl != NULL);
328
329
sigfillset(&newmask);
330
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
331
mutex_lock(&clnt_fd_lock);
332
elem = vc_fd_find(ct->ct_fd);
333
mutex_unlock(&clnt_fd_lock);
334
mutex_lock(&elem->mtx);
335
if (!ct->ct_waitset) {
336
/* If time is not within limits, we ignore it. */
337
if (time_not_ok(&timeout) == FALSE)
338
ct->ct_wait = timeout;
339
}
340
341
shipnow =
342
(xdr_results == NULL && timeout.tv_sec == 0
343
&& timeout.tv_usec == 0) ? FALSE : TRUE;
344
345
call_again:
346
xdrs->x_op = XDR_ENCODE;
347
ct->ct_error.re_status = RPC_SUCCESS;
348
x_id = ntohl(--(*msg_x_id));
349
350
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
351
if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
352
(! XDR_PUTINT32(xdrs, &proc)) ||
353
(! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
354
(! (*xdr_args)(xdrs, args_ptr))) {
355
if (ct->ct_error.re_status == RPC_SUCCESS)
356
ct->ct_error.re_status = RPC_CANTENCODEARGS;
357
(void)xdrrec_endofrecord(xdrs, TRUE);
358
release_fd_lock(elem, mask);
359
return (ct->ct_error.re_status);
360
}
361
} else {
362
*(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc);
363
if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc,
364
ct->ct_mpos + sizeof(uint32_t),
365
xdrs, xdr_args, args_ptr)) {
366
if (ct->ct_error.re_status == RPC_SUCCESS)
367
ct->ct_error.re_status = RPC_CANTENCODEARGS;
368
(void)xdrrec_endofrecord(xdrs, TRUE);
369
release_fd_lock(elem, mask);
370
return (ct->ct_error.re_status);
371
}
372
}
373
if (! xdrrec_endofrecord(xdrs, shipnow)) {
374
release_fd_lock(elem, mask);
375
return (ct->ct_error.re_status = RPC_CANTSEND);
376
}
377
if (! shipnow) {
378
release_fd_lock(elem, mask);
379
return (RPC_SUCCESS);
380
}
381
/*
382
* Hack to provide rpc-based message passing
383
*/
384
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
385
release_fd_lock(elem, mask);
386
return(ct->ct_error.re_status = RPC_TIMEDOUT);
387
}
388
389
390
/*
391
* Keep receiving until we get a valid transaction id
392
*/
393
xdrs->x_op = XDR_DECODE;
394
while (TRUE) {
395
reply_msg.acpted_rply.ar_verf = _null_auth;
396
reply_msg.acpted_rply.ar_results.where = NULL;
397
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
398
if (! xdrrec_skiprecord(xdrs)) {
399
release_fd_lock(elem, mask);
400
return (ct->ct_error.re_status);
401
}
402
/* now decode and validate the response header */
403
if (! xdr_replymsg(xdrs, &reply_msg)) {
404
if (ct->ct_error.re_status == RPC_SUCCESS)
405
continue;
406
release_fd_lock(elem, mask);
407
return (ct->ct_error.re_status);
408
}
409
if (reply_msg.rm_xid == x_id)
410
break;
411
}
412
413
/*
414
* process header
415
*/
416
_seterr_reply(&reply_msg, &(ct->ct_error));
417
if (ct->ct_error.re_status == RPC_SUCCESS) {
418
if (! AUTH_VALIDATE(cl->cl_auth,
419
&reply_msg.acpted_rply.ar_verf)) {
420
ct->ct_error.re_status = RPC_AUTHERROR;
421
ct->ct_error.re_why = AUTH_INVALIDRESP;
422
} else {
423
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
424
reply_stat = (*xdr_results)(xdrs, results_ptr);
425
} else {
426
reply_stat = __rpc_gss_unwrap(cl->cl_auth,
427
xdrs, xdr_results, results_ptr);
428
}
429
if (! reply_stat) {
430
if (ct->ct_error.re_status == RPC_SUCCESS)
431
ct->ct_error.re_status =
432
RPC_CANTDECODERES;
433
}
434
}
435
/* free verifier ... */
436
if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
437
xdrs->x_op = XDR_FREE;
438
(void)xdr_opaque_auth(xdrs,
439
&(reply_msg.acpted_rply.ar_verf));
440
}
441
} /* end successful completion */
442
else {
443
/* maybe our credentials need to be refreshed ... */
444
if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
445
goto call_again;
446
} /* end of unsuccessful completion */
447
release_fd_lock(elem, mask);
448
return (ct->ct_error.re_status);
449
}
450
451
static void
452
clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
453
{
454
struct ct_data *ct;
455
456
assert(cl != NULL);
457
assert(errp != NULL);
458
459
ct = (struct ct_data *) cl->cl_private;
460
*errp = ct->ct_error;
461
}
462
463
static bool_t
464
clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
465
{
466
struct ct_data *ct;
467
struct vc_fd *elem;
468
XDR *xdrs;
469
bool_t dummy;
470
sigset_t mask;
471
sigset_t newmask;
472
473
assert(cl != NULL);
474
475
ct = (struct ct_data *)cl->cl_private;
476
xdrs = &(ct->ct_xdrs);
477
478
sigfillset(&newmask);
479
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
480
mutex_lock(&clnt_fd_lock);
481
elem = vc_fd_find(ct->ct_fd);
482
mutex_lock(&elem->mtx);
483
xdrs->x_op = XDR_FREE;
484
dummy = (*xdr_res)(xdrs, res_ptr);
485
486
mutex_unlock(&clnt_fd_lock);
487
release_fd_lock(elem, mask);
488
return dummy;
489
}
490
491
/*ARGSUSED*/
492
static void
493
clnt_vc_abort(CLIENT *cl)
494
{
495
}
496
497
static __inline void
498
htonlp(void *dst, const void *src, uint32_t incr)
499
{
500
/* We are aligned, so we think */
501
*(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
502
}
503
504
static __inline void
505
ntohlp(void *dst, const void *src)
506
{
507
/* We are aligned, so we think */
508
*(uint32_t *)dst = htonl(*(const uint32_t *)src);
509
}
510
511
static bool_t
512
clnt_vc_control(CLIENT *cl, u_int request, void *info)
513
{
514
struct ct_data *ct;
515
struct vc_fd *elem;
516
void *infop = info;
517
sigset_t mask;
518
sigset_t newmask;
519
520
assert(cl != NULL);
521
522
ct = (struct ct_data *)cl->cl_private;
523
524
sigfillset(&newmask);
525
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
526
mutex_lock(&clnt_fd_lock);
527
elem = vc_fd_find(ct->ct_fd);
528
mutex_unlock(&clnt_fd_lock);
529
mutex_lock(&elem->mtx);
530
531
switch (request) {
532
case CLSET_FD_CLOSE:
533
ct->ct_closeit = TRUE;
534
release_fd_lock(elem, mask);
535
return (TRUE);
536
case CLSET_FD_NCLOSE:
537
ct->ct_closeit = FALSE;
538
release_fd_lock(elem, mask);
539
return (TRUE);
540
default:
541
break;
542
}
543
544
/* for other requests which use info */
545
if (info == NULL) {
546
release_fd_lock(elem, mask);
547
return (FALSE);
548
}
549
switch (request) {
550
case CLSET_TIMEOUT:
551
if (time_not_ok((struct timeval *)info)) {
552
release_fd_lock(elem, mask);
553
return (FALSE);
554
}
555
ct->ct_wait = *(struct timeval *)infop;
556
ct->ct_waitset = TRUE;
557
break;
558
case CLGET_TIMEOUT:
559
*(struct timeval *)infop = ct->ct_wait;
560
break;
561
case CLGET_SERVER_ADDR:
562
(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
563
break;
564
case CLGET_FD:
565
*(int *)info = ct->ct_fd;
566
break;
567
case CLGET_SVC_ADDR:
568
/* The caller should not free this memory area */
569
*(struct netbuf *)info = ct->ct_addr;
570
break;
571
case CLSET_SVC_ADDR: /* set to new address */
572
release_fd_lock(elem, mask);
573
return (FALSE);
574
case CLGET_XID:
575
/*
576
* use the knowledge that xid is the
577
* first element in the call structure
578
* This will get the xid of the PREVIOUS call
579
*/
580
ntohlp(info, &ct->ct_u.ct_mcalli);
581
break;
582
case CLSET_XID:
583
/* This will set the xid of the NEXT call */
584
/* increment by 1 as clnt_vc_call() decrements once */
585
htonlp(&ct->ct_u.ct_mcalli, info, 1);
586
break;
587
case CLGET_VERS:
588
/*
589
* This RELIES on the information that, in the call body,
590
* the version number field is the fifth field from the
591
* beginning of the RPC header. MUST be changed if the
592
* call_struct is changed
593
*/
594
ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
595
break;
596
597
case CLSET_VERS:
598
htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
599
break;
600
601
case CLGET_PROG:
602
/*
603
* This RELIES on the information that, in the call body,
604
* the program number field is the fourth field from the
605
* beginning of the RPC header. MUST be changed if the
606
* call_struct is changed
607
*/
608
ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
609
break;
610
611
case CLSET_PROG:
612
htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
613
break;
614
615
default:
616
release_fd_lock(elem, mask);
617
return (FALSE);
618
}
619
release_fd_lock(elem, mask);
620
return (TRUE);
621
}
622
623
624
static void
625
clnt_vc_destroy(CLIENT *cl)
626
{
627
struct ct_data *ct = (struct ct_data *) cl->cl_private;
628
struct vc_fd *elem;
629
int ct_fd = ct->ct_fd;
630
sigset_t mask;
631
sigset_t newmask;
632
633
assert(cl != NULL);
634
635
ct = (struct ct_data *) cl->cl_private;
636
637
sigfillset(&newmask);
638
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
639
mutex_lock(&clnt_fd_lock);
640
elem = vc_fd_find(ct_fd);
641
mutex_lock(&elem->mtx);
642
if (ct->ct_closeit && ct->ct_fd != -1) {
643
(void)_close(ct->ct_fd);
644
}
645
XDR_DESTROY(&(ct->ct_xdrs));
646
free(ct->ct_addr.buf);
647
mem_free(ct, sizeof(struct ct_data));
648
if (cl->cl_netid && cl->cl_netid[0])
649
mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
650
if (cl->cl_tp && cl->cl_tp[0])
651
mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
652
mem_free(cl, sizeof(CLIENT));
653
mutex_unlock(&clnt_fd_lock);
654
release_fd_lock(elem, mask);
655
}
656
657
/*
658
* Interface between xdr serializer and tcp connection.
659
* Behaves like the system calls, read & write, but keeps some error state
660
* around for the rpc level.
661
*/
662
static int
663
read_vc(void *ctp, void *buf, int len)
664
{
665
struct sockaddr sa;
666
socklen_t sal;
667
struct ct_data *ct = (struct ct_data *)ctp;
668
struct pollfd fd;
669
int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
670
(ct->ct_wait.tv_usec / 1000));
671
672
if (len == 0)
673
return (0);
674
fd.fd = ct->ct_fd;
675
fd.events = POLLIN;
676
for (;;) {
677
switch (_poll(&fd, 1, milliseconds)) {
678
case 0:
679
ct->ct_error.re_status = RPC_TIMEDOUT;
680
return (-1);
681
682
case -1:
683
if (errno == EINTR)
684
continue;
685
ct->ct_error.re_status = RPC_CANTRECV;
686
ct->ct_error.re_errno = errno;
687
return (-1);
688
}
689
break;
690
}
691
692
sal = sizeof(sa);
693
if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
694
(sa.sa_family == AF_LOCAL)) {
695
len = __msgread(ct->ct_fd, buf, (size_t)len);
696
} else {
697
len = _read(ct->ct_fd, buf, (size_t)len);
698
}
699
700
switch (len) {
701
case 0:
702
/* premature eof */
703
ct->ct_error.re_errno = ECONNRESET;
704
ct->ct_error.re_status = RPC_CANTRECV;
705
len = -1; /* it's really an error */
706
break;
707
708
case -1:
709
ct->ct_error.re_errno = errno;
710
ct->ct_error.re_status = RPC_CANTRECV;
711
break;
712
}
713
return (len);
714
}
715
716
static int
717
write_vc(void *ctp, void *buf, int len)
718
{
719
struct sockaddr sa;
720
socklen_t sal;
721
struct ct_data *ct = (struct ct_data *)ctp;
722
int i, cnt;
723
724
sal = sizeof(sa);
725
if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
726
(sa.sa_family == AF_LOCAL)) {
727
for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
728
if ((i = __msgwrite(ct->ct_fd, buf,
729
(size_t)cnt)) == -1) {
730
ct->ct_error.re_errno = errno;
731
ct->ct_error.re_status = RPC_CANTSEND;
732
return (-1);
733
}
734
}
735
} else {
736
for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
737
if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
738
ct->ct_error.re_errno = errno;
739
ct->ct_error.re_status = RPC_CANTSEND;
740
return (-1);
741
}
742
}
743
}
744
return (len);
745
}
746
747
static struct clnt_ops *
748
clnt_vc_ops(void)
749
{
750
static struct clnt_ops ops;
751
sigset_t mask, newmask;
752
753
/* VARIABLES PROTECTED BY ops_lock: ops */
754
755
sigfillset(&newmask);
756
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
757
mutex_lock(&ops_lock);
758
if (ops.cl_call == NULL) {
759
ops.cl_call = clnt_vc_call;
760
ops.cl_abort = clnt_vc_abort;
761
ops.cl_geterr = clnt_vc_geterr;
762
ops.cl_freeres = clnt_vc_freeres;
763
ops.cl_destroy = clnt_vc_destroy;
764
ops.cl_control = clnt_vc_control;
765
}
766
mutex_unlock(&ops_lock);
767
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
768
return (&ops);
769
}
770
771
/*
772
* Make sure that the time is not garbage. -1 value is disallowed.
773
* Note this is different from time_not_ok in clnt_dg.c
774
*/
775
static bool_t
776
time_not_ok(struct timeval *t)
777
{
778
return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
779
t->tv_usec <= -1 || t->tv_usec > 1000000);
780
}
781
782
static int
783
__msgread(int sock, void *buf, size_t cnt)
784
{
785
struct iovec iov[1];
786
struct msghdr msg;
787
union {
788
struct cmsghdr cmsg;
789
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
790
} cm;
791
792
bzero((char *)&cm, sizeof(cm));
793
iov[0].iov_base = buf;
794
iov[0].iov_len = cnt;
795
796
msg.msg_iov = iov;
797
msg.msg_iovlen = 1;
798
msg.msg_name = NULL;
799
msg.msg_namelen = 0;
800
msg.msg_control = (caddr_t)&cm;
801
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
802
msg.msg_flags = 0;
803
804
return(_recvmsg(sock, &msg, 0));
805
}
806
807
static int
808
__msgwrite(int sock, void *buf, size_t cnt)
809
{
810
struct iovec iov[1];
811
struct msghdr msg;
812
union {
813
struct cmsghdr cmsg;
814
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
815
} cm;
816
817
bzero((char *)&cm, sizeof(cm));
818
iov[0].iov_base = buf;
819
iov[0].iov_len = cnt;
820
821
cm.cmsg.cmsg_type = SCM_CREDS;
822
cm.cmsg.cmsg_level = SOL_SOCKET;
823
cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
824
825
msg.msg_iov = iov;
826
msg.msg_iovlen = 1;
827
msg.msg_name = NULL;
828
msg.msg_namelen = 0;
829
msg.msg_control = (caddr_t)&cm;
830
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
831
msg.msg_flags = 0;
832
833
return(_sendmsg(sock, &msg, 0));
834
}
835
836