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