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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T
29 * All Rights Reserved
30 */
31
32 /*
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
35 * All Rights Reserved
36 *
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
39 * contributors.
40 */
41
42 /*
43 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
44 *
45 * TCP based RPC supports 'batched calls'.
46 * A sequence of calls may be batched-up in a send buffer. The rpc call
47 * return immediately to the client even though the call was not necessarily
48 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
49 * the rpc timeout value is zero (see clnt.h, rpc).
50 *
51 * Clients should NOT casually batch calls that in fact return results; that is,
52 * the server side should be aware that a call is batched and not produce any
53 * return message. Batched calls that produce many result messages can
54 * deadlock (netlock) the client and the server....
55 *
56 * Now go hang yourself.
57 */
58
59 #include <rpc/rpc.h>
60 #include <sys/socket.h>
61 #include <sys/time.h>
62 #include <netdb.h>
63 #include <errno.h>
64 #include <rpc/pmap_clnt.h>
65 #include <syslog.h>
66 #include <malloc.h>
67 #include <stdio.h>
68
69 #define MCALL_MSG_SIZE 24
70
71 extern int errno;
72
73 static int readtcp(void *, caddr_t, int);
74 static int writetcp(void *, caddr_t, int);
75 extern int _socket(int, int, int);
76 extern pid_t getpid(void);
77 extern int bindresvport(int, struct sockaddr_in *);
78 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
79 static struct clnt_ops *clnttcp_ops(void);
80
81 struct ct_data {
82 int ct_sock;
83 bool_t ct_closeit;
84 struct timeval ct_wait;
85 bool_t ct_waitset; /* wait set by clnt_control? */
86 struct sockaddr_in ct_addr;
87 struct rpc_err ct_error;
88 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
89 uint_t ct_mpos; /* pos after marshal */
90 XDR ct_xdrs;
91 };
92
93 /*
94 * Create a client handle for a tcp/ip connection.
95 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
96 * connected to raddr. If *sockp non-negative then
97 * raddr is ignored. The rpc/tcp package does buffering
98 * similar to stdio, so the client must pick send and receive buffer sizes
99 * 0 => use the default.
100 * If raddr->sin_port is 0, then a binder on the remote machine is
101 * consulted for the right port number.
102 * NB: *sockp is copied into a private area.
103 * NB: It is the clients responsibility to close *sockp.
104 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
105 * set this something more useful.
106 */
107 CLIENT *
clnttcp_create(struct sockaddr_in * raddr,rpcprog_t prog,rpcvers_t vers,int * sockp,uint_t sendsz,uint_t recvsz)108 clnttcp_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
109 int *sockp, uint_t sendsz, uint_t recvsz)
110 {
111 CLIENT *h;
112 struct ct_data *ct;
113 struct timeval now;
114 struct rpc_msg call_msg;
115
116 h = (CLIENT *)mem_alloc(sizeof (*h));
117 if (h == NULL) {
118 (void) syslog(LOG_ERR, "clnttcp_create: out of memory");
119 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
120 rpc_createerr.cf_error.re_errno = errno;
121 goto fooy;
122 }
123 ct = (struct ct_data *)mem_alloc(sizeof (*ct));
124 if (ct == NULL) {
125 (void) syslog(LOG_ERR, "clnttcp_create: out of memory");
126 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
127 rpc_createerr.cf_error.re_errno = errno;
128 goto fooy;
129 }
130
131 /*
132 * If no port number given ask the pmap for one
133 */
134 if (raddr->sin_port == 0) {
135 ushort_t port;
136 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP))
137 == 0) {
138 mem_free((caddr_t)ct, sizeof (struct ct_data));
139 mem_free((caddr_t)h, sizeof (CLIENT));
140 return ((CLIENT *)NULL);
141 }
142 raddr->sin_port = htons(port);
143 }
144
145 /*
146 * If no socket given, open one
147 */
148 if (*sockp < 0) {
149 *sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
150 (void) bindresvport(*sockp, (struct sockaddr_in *)0);
151 if ((*sockp < 0)||
152 (connect(*sockp, (struct sockaddr *)raddr,
153 sizeof (*raddr)) < 0)) {
154 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
155 rpc_createerr.cf_error.re_errno = errno;
156 (void) close(*sockp);
157 goto fooy;
158 }
159 ct->ct_closeit = TRUE;
160 } else {
161 ct->ct_closeit = FALSE;
162 }
163
164 /*
165 * Set up private data struct
166 */
167 ct->ct_sock = *sockp;
168 ct->ct_wait.tv_usec = 0;
169 ct->ct_waitset = FALSE;
170 ct->ct_addr = *raddr;
171
172 /*
173 * Initialize call message
174 */
175 (void) gettimeofday(&now, (struct timezone *)0);
176 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
177 call_msg.rm_direction = CALL;
178 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
179 call_msg.rm_call.cb_prog = prog;
180 call_msg.rm_call.cb_vers = vers;
181
182 /*
183 * pre-serialize the staic part of the call msg and stash it away
184 */
185 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
186 XDR_ENCODE);
187 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
188 if (ct->ct_closeit) {
189 (void) close(*sockp);
190 }
191 goto fooy;
192 }
193 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
194 XDR_DESTROY(&(ct->ct_xdrs));
195
196 /*
197 * Create a client handle which uses xdrrec for serialization
198 * and authnone for authentication.
199 */
200 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
201 (caddr_t)ct, readtcp, writetcp);
202 h->cl_ops = clnttcp_ops();
203 h->cl_private = (caddr_t)ct;
204 h->cl_auth = authnone_create();
205 return (h);
206
207 fooy:
208 /*
209 * Something goofed, free stuff and barf
210 */
211 mem_free((caddr_t)ct, sizeof (struct ct_data));
212 mem_free((caddr_t)h, sizeof (CLIENT));
213 return (NULL);
214 }
215
216 static enum clnt_stat
clnttcp_call(CLIENT * h,rpcproc_t proc,xdrproc_t xdr_args,caddr_t args_ptr,xdrproc_t xdr_results,caddr_t results_ptr,struct timeval timeout)217 clnttcp_call(CLIENT *h, rpcproc_t proc, xdrproc_t xdr_args, caddr_t args_ptr,
218 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout)
219 {
220 struct ct_data *ct;
221 XDR *xdrs;
222 struct rpc_msg reply_msg;
223 uint32_t x_id;
224 uint32_t *msg_x_id;
225 bool_t shipnow;
226 int refreshes;
227
228 ct = (struct ct_data *)h->cl_private;
229 xdrs = &(ct->ct_xdrs);
230 msg_x_id = (uint32_t *)(ct->ct_mcall); /* yuk */
231 refreshes = 2;
232
233 if (!ct->ct_waitset) {
234 ct->ct_wait = timeout;
235 }
236
237 shipnow =
238 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 &&
239 timeout.tv_usec == 0) ? FALSE : TRUE;
240
241 call_again:
242 xdrs->x_op = XDR_ENCODE;
243 ct->ct_error.re_status = RPC_SUCCESS;
244 x_id = ntohl(--(*msg_x_id));
245 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
246 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
247 (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
248 (! (*xdr_args)(xdrs, args_ptr))) {
249 if (ct->ct_error.re_status == RPC_SUCCESS)
250 ct->ct_error.re_status = RPC_CANTENCODEARGS;
251 (void) xdrrec_endofrecord(xdrs, TRUE);
252 return (ct->ct_error.re_status);
253 }
254 if (! xdrrec_endofrecord(xdrs, shipnow))
255 return (ct->ct_error.re_status = RPC_CANTSEND);
256 if (! shipnow)
257 return (RPC_SUCCESS);
258 /*
259 * Hack to provide rpc-based message passing
260 */
261 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
262 return (ct->ct_error.re_status = RPC_TIMEDOUT);
263 }
264
265
266 /*
267 * Keep receiving until we get a valid transaction id
268 */
269 xdrs->x_op = XDR_DECODE;
270 while (TRUE) {
271 reply_msg.acpted_rply.ar_verf = _null_auth;
272 reply_msg.acpted_rply.ar_results.where = NULL;
273 reply_msg.acpted_rply.ar_results.proc = xdr_void;
274 if (! xdrrec_skiprecord(xdrs))
275 return (ct->ct_error.re_status);
276 /* now decode and validate the response header */
277 if (! xdr_replymsg(xdrs, &reply_msg)) {
278 if (ct->ct_error.re_status == RPC_SUCCESS)
279 continue;
280 return (ct->ct_error.re_status);
281 }
282 if (reply_msg.rm_xid == x_id)
283 break;
284 }
285
286 /*
287 * process header
288 */
289 __seterr_reply(&reply_msg, &(ct->ct_error));
290 if (ct->ct_error.re_status == RPC_SUCCESS) {
291 if (! AUTH_VALIDATE(h->cl_auth,
292 &reply_msg.acpted_rply.ar_verf)) {
293 ct->ct_error.re_status = RPC_AUTHERROR;
294 ct->ct_error.re_why = AUTH_INVALIDRESP;
295 } else if (! (*xdr_results)(xdrs, results_ptr)) {
296 if (ct->ct_error.re_status == RPC_SUCCESS)
297 ct->ct_error.re_status = RPC_CANTDECODERES;
298 }
299 /* free verifier ... */
300 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
301 xdrs->x_op = XDR_FREE;
302 (void) xdr_opaque_auth(xdrs,
303 &(reply_msg.acpted_rply.ar_verf));
304 }
305 } /* end successful completion */
306 else {
307 /* maybe our credentials need to be refreshed ... */
308 if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
309 goto call_again;
310 } /* end of unsuccessful completion */
311 return (ct->ct_error.re_status);
312 }
313
314 static void
clnttcp_geterr(CLIENT * h,struct rpc_err * errp)315 clnttcp_geterr(CLIENT *h, struct rpc_err *errp)
316 {
317 struct ct_data *ct;
318
319 ct = (struct ct_data *)h->cl_private;
320 *errp = ct->ct_error;
321 }
322
323 static bool_t
clnttcp_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)324 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
325 {
326 struct ct_data *ct;
327 XDR *xdrs;
328
329 ct = (struct ct_data *)cl->cl_private;
330 xdrs = &(ct->ct_xdrs);
331 xdrs->x_op = XDR_FREE;
332 return ((*xdr_res)(xdrs, res_ptr));
333 }
334
335 static void
clnttcp_abort(void)336 clnttcp_abort(void)
337 {
338 }
339
340 static bool_t
clnttcp_control(CLIENT * cl,int request,char * info)341 clnttcp_control(CLIENT *cl, int request, char *info)
342 {
343 struct ct_data *ct;
344
345 ct = (struct ct_data *)cl->cl_private;
346 switch (request) {
347 case CLSET_TIMEOUT:
348 ct->ct_wait = *(struct timeval *)info;
349 ct->ct_waitset = TRUE;
350 break;
351 case CLGET_TIMEOUT:
352 *(struct timeval *)info = ct->ct_wait;
353 break;
354 case CLGET_SERVER_ADDR:
355 *(struct sockaddr_in *)info = ct->ct_addr;
356 break;
357 case CLGET_FD:
358 *(int *)info = ct->ct_sock;
359 break;
360 case CLSET_FD_CLOSE:
361 ct->ct_closeit = TRUE;
362 break;
363 case CLSET_FD_NCLOSE:
364 ct->ct_closeit = FALSE;
365 break;
366 default:
367 return (FALSE);
368 }
369 return (TRUE);
370 }
371
372
373 static void
clnttcp_destroy(CLIENT * h)374 clnttcp_destroy(CLIENT *h)
375 {
376 struct ct_data *ct;
377
378 ct = (struct ct_data *)h->cl_private;
379 if (ct->ct_closeit) {
380 (void) close(ct->ct_sock);
381 }
382 XDR_DESTROY(&(ct->ct_xdrs));
383 mem_free((caddr_t)ct, sizeof (struct ct_data));
384 mem_free((caddr_t)h, sizeof (CLIENT));
385 }
386
387 /*
388 * Interface between xdr serializer and tcp connection.
389 * Behaves like the system calls, read & write, but keeps some error state
390 * around for the rpc level.
391 */
392 static int
readtcp(void * data,caddr_t buf,int len)393 readtcp(void *data, caddr_t buf, int len)
394 {
395 fd_set mask;
396 fd_set readfds;
397 struct ct_data *ct;
398
399 if (len == 0)
400 return (0);
401
402 ct = data;
403 FD_ZERO(&mask);
404 FD_SET(ct->ct_sock, &mask);
405 while (TRUE) {
406 readfds = mask;
407 switch (select(__rpc_dtbsize(),
408 &readfds, NULL, NULL, &(ct->ct_wait))) {
409 case 0:
410 ct->ct_error.re_status = RPC_TIMEDOUT;
411 return (-1);
412
413 case -1:
414 if (errno == EINTR)
415 continue;
416 ct->ct_error.re_status = RPC_CANTRECV;
417 ct->ct_error.re_errno = errno;
418 return (-1);
419 }
420 break;
421 }
422 switch (len = read(ct->ct_sock, buf, len)) {
423
424 case 0:
425 /* premature eof */
426 ct->ct_error.re_errno = ECONNRESET;
427 ct->ct_error.re_status = RPC_CANTRECV;
428 len = -1; /* it's really an error */
429 break;
430
431 case -1:
432 ct->ct_error.re_errno = errno;
433 ct->ct_error.re_status = RPC_CANTRECV;
434 break;
435 }
436 return (len);
437 }
438
439 static int
writetcp(void * data,caddr_t buf,int len)440 writetcp(void *data, caddr_t buf, int len)
441 {
442 struct ct_data *ct;
443 int i, cnt;
444
445 ct = data;
446 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
447 if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
448 ct->ct_error.re_errno = errno;
449 ct->ct_error.re_status = RPC_CANTSEND;
450 return (-1);
451 }
452 }
453 return (len);
454 }
455
456 static struct clnt_ops *
clnttcp_ops(void)457 clnttcp_ops(void)
458 {
459 static struct clnt_ops ops;
460
461 if (ops.cl_call == NULL) {
462 ops.cl_call = clnttcp_call;
463 ops.cl_abort = clnttcp_abort;
464 ops.cl_geterr = clnttcp_geterr;
465 ops.cl_freeres = clnttcp_freeres;
466 ops.cl_destroy = clnttcp_destroy;
467 ops.cl_control = clnttcp_control;
468 }
469 return (&ops);
470 }
471