Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / rpc.subproj / clnt_tcp.c
1 /*
2 * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
26 * unrestricted use provided that this legend is included on all tape
27 * media and as a part of the software program in whole or part. Users
28 * may copy or modify Sun RPC without charge, but are not authorized
29 * to license or distribute it to anyone else except as part of a product or
30 * program developed by the user.
31 *
32 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
33 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
35 *
36 * Sun RPC is provided with no support and without any obligation on the
37 * part of Sun Microsystems, Inc. to assist in its use, correction,
38 * modification or enhancement.
39 *
40 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
41 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
42 * OR ANY PART THEREOF.
43 *
44 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
45 * or profits or other special, indirect and consequential damages, even if
46 * Sun has been advised of the possibility of such damages.
47 *
48 * Sun Microsystems, Inc.
49 * 2550 Garcia Avenue
50 * Mountain View, California 94043
51 */
52
53 #if defined(LIBC_SCCS) && !defined(lint)
54 /*static char *sccsid = "from: @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/
55 /*static char *sccsid = "from: @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/
56 static char *rcsid = "$Id: clnt_tcp.c,v 1.4 2002/03/15 22:07:48 majka Exp $";
57 #endif
58
59 /*
60 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
61 *
62 * Copyright (C) 1984, Sun Microsystems, Inc.
63 *
64 * TCP based RPC supports 'batched calls'.
65 * A sequence of calls may be batched-up in a send buffer. The rpc call
66 * returns immediately to the client even though the call was not necessarily
67 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
68 * the rpc timeout value is zero (see clnt.h, rpc).
69 *
70 * Clients should NOT casually batch calls that in fact return results; that is,
71 * the server side should be aware that a call is batched and not produce any
72 * return message. Batched calls that produce many result messages can
73 * deadlock (netlock) the client and the server....
74 *
75 * Now go hang yourself.
76 */
77
78 #include "libinfo_common.h"
79
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <rpc/rpc.h>
85 #include <sys/socket.h>
86 #include <sys/fcntl.h>
87 #include <netdb.h>
88 #include <errno.h>
89 #include <rpc/pmap_clnt.h>
90
91 #define MCALL_MSG_SIZE 24
92
93 extern int errno;
94
95 extern int bindresvport();
96 extern bool_t xdr_opaque_auth();
97
98 extern u_short pmap_getport_timeout(struct sockaddr_in *address, uint32_t program, uint32_t version, uint32_t protocol, struct timeval *timeout, struct timeval *totaltimeout);
99
100 static int readtcp();
101 static int writetcp();
102
103 static enum clnt_stat clnttcp_call();
104 static void clnttcp_abort();
105 static void clnttcp_geterr();
106 static bool_t clnttcp_freeres();
107 static bool_t clnttcp_control();
108 static void clnttcp_destroy();
109
110 static struct clnt_ops tcp_ops = {
111 clnttcp_call,
112 clnttcp_abort,
113 clnttcp_geterr,
114 clnttcp_freeres,
115 clnttcp_destroy,
116 clnttcp_control
117 };
118
119 struct ct_data {
120 int ct_sock;
121 bool_t ct_closeit;
122 struct timeval ct_timeout;
123 bool_t ct_timeout_set; /* timeout set by clnt_control? */
124 struct sockaddr_in ct_addr;
125 struct rpc_err ct_error;
126 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
127 u_int ct_mpos; /* pos after marshal */
128 XDR ct_xdrs;
129 };
130
131 /*
132 * Create a client handle for a tcp/ip connection.
133 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
134 * connected to raddr. If *sockp non-negative then
135 * raddr is ignored. The rpc/tcp package does buffering
136 * similar to stdio, so the client must pick send and receive buffer sizes,];
137 * 0 => use the default.
138 * If raddr->sin_port is 0, then a binder on the remote machine is
139 * consulted for the right port number.
140 * NB: *sockp is copied into a private area.
141 * NB: It is the clients responsibility to close *sockp.
142 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
143 * something more useful.
144 */
145 CLIENT *
146 clnttcp_create_timeout(struct sockaddr_in *raddr, uint32_t prog, uint32_t vers, int *sockp, uint32_t sendsz, uint32_t recvsz, struct timeval *retry_timeout, struct timeval *total_timeout)
147 {
148 CLIENT *h;
149 register struct ct_data *ct = NULL;
150 struct timeval now;
151 struct rpc_msg call_msg;
152 int rfd;
153 u_short port;
154
155 h = (CLIENT *)mem_alloc(sizeof(*h));
156 if (h == NULL)
157 {
158 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
159 rpc_createerr.cf_error.re_errno = errno;
160 goto fooy;
161 }
162
163 ct = (struct ct_data *)mem_alloc(sizeof(*ct));
164 if (ct == NULL)
165 {
166 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
167 rpc_createerr.cf_error.re_errno = errno;
168 goto fooy;
169 }
170
171 /*
172 * If no port number given ask the pmap for one
173 */
174 if (raddr->sin_port == 0)
175 {
176 port = pmap_getport_timeout(raddr, prog, vers, IPPROTO_TCP, retry_timeout, total_timeout);
177 if (port == 0)
178 {
179 mem_free((caddr_t)ct, sizeof(struct ct_data));
180 mem_free((caddr_t)h, sizeof(CLIENT));
181 return NULL;
182 }
183
184 raddr->sin_port = htons(port);
185 }
186
187 /*
188 * If no socket given, open one
189 */
190 if (*sockp < 0)
191 {
192 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
193 bindresvport(*sockp, (struct sockaddr_in *)0);
194 if ((*sockp < 0) || (connect(*sockp, (struct sockaddr *)raddr, sizeof(*raddr)) < 0))
195 {
196 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
197 rpc_createerr.cf_error.re_errno = errno;
198 close(*sockp);
199 goto fooy;
200 }
201
202 ct->ct_closeit = TRUE;
203 }
204 else
205 {
206 ct->ct_closeit = FALSE;
207 }
208
209 /*
210 * Set up private data struct
211 */
212 ct->ct_sock = *sockp;
213 ct->ct_timeout.tv_sec = 60;
214 ct->ct_timeout.tv_usec = 0;
215 ct->ct_timeout_set = FALSE;
216 if (total_timeout != NULL)
217 {
218 ct->ct_timeout = *total_timeout;
219 ct->ct_timeout_set = TRUE;
220 }
221 ct->ct_addr = *raddr;
222
223 /*
224 * Initialize call message
225 */
226 rfd = open("/dev/random", O_RDONLY, 0);
227 if ((rfd < 0) || (read(rfd, &call_msg.rm_xid, sizeof(call_msg.rm_xid)) != sizeof(call_msg.rm_xid)))
228 {
229 gettimeofday(&now, (struct timezone *)0);
230 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
231 }
232
233 if (rfd > 0) close(rfd);
234
235 call_msg.rm_direction = CALL;
236 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
237 call_msg.rm_call.cb_prog = prog;
238 call_msg.rm_call.cb_vers = vers;
239
240 /*
241 * pre-serialize the staic part of the call msg and stash it away
242 */
243 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
244 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg))
245 {
246 if (ct->ct_closeit) close(*sockp);
247 goto fooy;
248 }
249
250 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
251 XDR_DESTROY(&(ct->ct_xdrs));
252
253 /*
254 * Create a client handle which uses xdrrec for serialization
255 * and authnone for authentication.
256 */
257 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, readtcp, writetcp);
258 h->cl_ops = &tcp_ops;
259 h->cl_private = (caddr_t)ct;
260 h->cl_auth = authnone_create();
261 return h;
262
263 fooy:
264 mem_free((caddr_t)ct, sizeof(struct ct_data));
265 mem_free((caddr_t)h, sizeof(CLIENT));
266 return NULL;
267 }
268
269 LIBINFO_EXPORT
270 CLIENT *
271 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
272 #ifdef __LP64__
273 struct sockaddr_in *raddr;
274 uint32_t prog;
275 uint32_t vers;
276 int *sockp;
277 uint32_t sendsz;
278 uint32_t recvsz;
279 #else
280 struct sockaddr_in *raddr;
281 u_long prog;
282 u_long vers;
283 register int *sockp;
284 u_int sendsz;
285 u_int recvsz;
286 #endif
287 {
288 return clnttcp_create_timeout(raddr, (uint32_t)prog, (uint32_t)vers, sockp, (uint32_t)sendsz, (uint32_t)recvsz, NULL, NULL);
289 }
290
291 static enum clnt_stat
292 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
293 register CLIENT *h;
294 #ifdef __LP64__
295 uint32_t proc;
296 #else
297 u_long proc;
298 #endif
299 xdrproc_t xdr_args;
300 caddr_t args_ptr;
301 xdrproc_t xdr_results;
302 caddr_t results_ptr;
303 struct timeval timeout;
304 {
305 register struct ct_data *ct = (struct ct_data *) h->cl_private;
306 register XDR *xdrs = &(ct->ct_xdrs);
307 struct rpc_msg reply_msg;
308 #ifdef __LP64__
309 uint32_t x_id;
310 uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall); /* yuk */
311 #else
312 u_long x_id;
313 u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */
314 #endif
315 register bool_t shipnow;
316 int refreshes = 2;
317
318 if (!ct->ct_timeout_set) {
319 ct->ct_timeout = timeout;
320 }
321
322 shipnow =
323 (xdr_results == (xdrproc_t)NULLPROC || (timeout.tv_sec == 0
324 && timeout.tv_usec == 0)) ? FALSE : TRUE;
325
326 call_again:
327 xdrs->x_op = XDR_ENCODE;
328 ct->ct_error.re_status = RPC_SUCCESS;
329 x_id = ntohl(--(*msg_x_id));
330 #ifdef __LP64__
331 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
332 (! XDR_PUTLONG(xdrs, (int *)&proc)) ||
333 (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
334 (! (*xdr_args)(xdrs, args_ptr, 0)))
335 #else
336 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
337 (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
338 (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
339 (! (*xdr_args)(xdrs, args_ptr, 0)))
340 #endif
341 {
342 if (ct->ct_error.re_status == RPC_SUCCESS)
343 ct->ct_error.re_status = RPC_CANTENCODEARGS;
344 (void)xdrrec_endofrecord(xdrs, TRUE);
345 return (ct->ct_error.re_status);
346 }
347 if (! xdrrec_endofrecord(xdrs, shipnow))
348 return (ct->ct_error.re_status = RPC_CANTSEND);
349 if (! shipnow)
350 return (RPC_SUCCESS);
351 /*
352 * Hack to provide rpc-based message passing
353 */
354 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
355 return(ct->ct_error.re_status = RPC_TIMEDOUT);
356 }
357
358
359 /*
360 * Keep receiving until we get a valid transaction id
361 */
362 xdrs->x_op = XDR_DECODE;
363 while (TRUE) {
364 reply_msg.acpted_rply.ar_verf = _null_auth;
365 reply_msg.acpted_rply.ar_results.where = NULL;
366 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
367 if (! xdrrec_skiprecord(xdrs))
368 return (ct->ct_error.re_status);
369 /* now decode and validate the response header */
370 if (! xdr_replymsg(xdrs, &reply_msg)) {
371 if (ct->ct_error.re_status == RPC_SUCCESS)
372 continue;
373 return (ct->ct_error.re_status);
374 }
375 if (reply_msg.rm_xid == x_id)
376 break;
377 }
378
379 /*
380 * process header
381 */
382 _seterr_reply(&reply_msg, &(ct->ct_error));
383 if (ct->ct_error.re_status == RPC_SUCCESS) {
384 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
385 ct->ct_error.re_status = RPC_AUTHERROR;
386 ct->ct_error.re_why = AUTH_INVALIDRESP;
387 } else if (! (*xdr_results)(xdrs, results_ptr, 0)) {
388 if (ct->ct_error.re_status == RPC_SUCCESS)
389 ct->ct_error.re_status = RPC_CANTDECODERES;
390 }
391 /* free verifier ... */
392 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
393 xdrs->x_op = XDR_FREE;
394 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
395 }
396 } /* end successful completion */
397 else {
398 /* maybe our credentials need to be refreshed ... */
399 if (refreshes-- && AUTH_REFRESH(h->cl_auth))
400 goto call_again;
401 } /* end of unsuccessful completion */
402 return (ct->ct_error.re_status);
403 }
404
405 static void
406 clnttcp_geterr(h, errp)
407 CLIENT *h;
408 struct rpc_err *errp;
409 {
410 register struct ct_data *ct =
411 (struct ct_data *) h->cl_private;
412
413 *errp = ct->ct_error;
414 }
415
416 static bool_t
417 clnttcp_freeres(cl, xdr_res, res_ptr)
418 CLIENT *cl;
419 xdrproc_t xdr_res;
420 caddr_t res_ptr;
421 {
422 register struct ct_data *ct = (struct ct_data *)cl->cl_private;
423 register XDR *xdrs = &(ct->ct_xdrs);
424
425 xdrs->x_op = XDR_FREE;
426 return ((*xdr_res)(xdrs, res_ptr, 0));
427 }
428
429 static void
430 clnttcp_abort()
431 {
432 }
433
434 static bool_t
435 clnttcp_control(cl, request, info)
436 CLIENT *cl;
437 int request;
438 char *info;
439 {
440 register struct ct_data *ct = (struct ct_data *)cl->cl_private;
441
442 switch (request) {
443 case CLSET_TIMEOUT:
444 ct->ct_timeout = *(struct timeval *)info;
445 ct->ct_timeout_set = TRUE;
446 break;
447 case CLGET_TIMEOUT:
448 *(struct timeval *)info = ct->ct_timeout;
449 break;
450 case CLGET_SERVER_ADDR:
451 *(struct sockaddr_in *)info = ct->ct_addr;
452 break;
453 default:
454 return (FALSE);
455 }
456 return (TRUE);
457 }
458
459
460 static void
461 clnttcp_destroy(h)
462 CLIENT *h;
463 {
464 register struct ct_data *ct =
465 (struct ct_data *) h->cl_private;
466
467 if (ct->ct_closeit) {
468 (void)close(ct->ct_sock);
469 }
470 XDR_DESTROY(&(ct->ct_xdrs));
471 mem_free((caddr_t)ct, sizeof(struct ct_data));
472 mem_free((caddr_t)h, sizeof(CLIENT));
473 }
474
475 /*
476 * Interface between xdr serializer and tcp connection.
477 * Behaves like the system calls, read & write, but keeps some error state
478 * around for the rpc level.
479 */
480 static int
481 readtcp(ct, buf, len)
482 register struct ct_data *ct;
483 caddr_t buf;
484 register int len;
485 {
486 fd_set mask;
487 fd_set readfds;
488
489 if (len == 0)
490 return (0);
491 FD_ZERO(&mask);
492 FD_SET(ct->ct_sock, &mask);
493 while (TRUE) {
494 readfds = mask;
495 switch (select(ct->ct_sock+1, &readfds, NULL, NULL, &(ct->ct_timeout))) {
496 case 0:
497 ct->ct_error.re_status = RPC_TIMEDOUT;
498 return (-1);
499
500 case -1:
501 if (errno == EINTR)
502 continue;
503 ct->ct_error.re_status = RPC_CANTRECV;
504 ct->ct_error.re_errno = errno;
505 return (-1);
506 }
507 break;
508 }
509 switch (len = read(ct->ct_sock, buf, len)) {
510
511 case 0:
512 /* premature eof */
513 ct->ct_error.re_errno = ECONNRESET;
514 ct->ct_error.re_status = RPC_CANTRECV;
515 len = -1; /* it's really an error */
516 break;
517
518 case -1:
519 ct->ct_error.re_errno = errno;
520 ct->ct_error.re_status = RPC_CANTRECV;
521 break;
522 }
523 return (len);
524 }
525
526 static int
527 writetcp(ct, buf, len)
528 struct ct_data *ct;
529 caddr_t buf;
530 int len;
531 {
532 register int i, cnt;
533
534 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
535 if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
536 ct->ct_error.re_errno = errno;
537 ct->ct_error.re_status = RPC_CANTSEND;
538 return (-1);
539 }
540 }
541 return (len);
542 }