OSDN Git Service

Adjust naming for __FORCE_GLIBC__ to __FORCE_GLIBC and add
[uclinux-h8/uClibc.git] / libc / inet / rpc / clnt_tcp.c
1 /* @(#)clnt_tcp.c       2.2 88/08/01 4.0 RPCSRC */
2 /*
3  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4  * unrestricted use provided that this legend is included on all tape
5  * media and as a part of the software program in whole or part.  Users
6  * may copy or modify Sun RPC without charge, but are not authorized
7  * to license or distribute it to anyone else except as part of a product or
8  * program developed by the user.
9  * 
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  * 
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  * 
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  * 
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  * 
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30 #define __FORCE_GLIBC
31 #include <features.h>
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 <stdio.h>
53 #include <rpc/rpc.h>
54 #include <sys/socket.h>
55 #include <netdb.h>
56 #include <errno.h>
57 #include <rpc/pmap_clnt.h>
58 #include <unistd.h>
59
60 #define MCALL_MSG_SIZE 24
61
62 extern int errno;
63
64 static int readtcp();
65 static int writetcp();
66
67 static enum clnt_stat clnttcp_call();
68 static void clnttcp_abort();
69 static void clnttcp_geterr();
70 static bool_t clnttcp_freeres();
71 static bool_t clnttcp_control();
72 static void clnttcp_destroy();
73
74 static struct clnt_ops tcp_ops = {
75         clnttcp_call,
76         clnttcp_abort,
77         clnttcp_geterr,
78         clnttcp_freeres,
79         clnttcp_destroy,
80         clnttcp_control
81 };
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 set this
107  * something more useful.
108  */
109 CLIENT *clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
110 struct sockaddr_in *raddr;
111 u_long prog;
112 u_long vers;
113 register int *sockp;
114 u_int sendsz;
115 u_int recvsz;
116 {
117         CLIENT *h;
118         register struct ct_data *ct;
119         struct timeval now;
120         struct rpc_msg call_msg;
121
122         ct = NULL;                                      /* in case of fooy */
123         h = (CLIENT *) mem_alloc(sizeof(*h));
124         if (h == NULL) {
125                 (void) fprintf(stderr, "clnttcp_create: out of memory\n");
126                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
127                 rpc_createerr.cf_error.re_errno = errno;
128                 goto fooy;
129         }
130         ct = (struct ct_data *) mem_alloc(sizeof(*ct));
131         if (ct == NULL) {
132                 (void) fprintf(stderr, "clnttcp_create: out of memory\n");
133                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
134                 rpc_createerr.cf_error.re_errno = errno;
135                 goto fooy;
136         }
137
138         /*
139          * If no port number given ask the pmap for one
140          */
141         if (raddr->sin_port == 0) {
142                 u_short port;
143
144                 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
145                         mem_free((caddr_t) ct, sizeof(struct ct_data));
146
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                 (void) 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 = &tcp_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
221         mem_free((caddr_t) h, sizeof(CLIENT));
222         return ((CLIENT *) NULL);
223 }
224
225 static enum clnt_stat
226 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr,
227                          timeout)
228 register CLIENT *h;
229 u_long proc;
230 xdrproc_t xdr_args;
231 caddr_t args_ptr;
232 xdrproc_t xdr_results;
233 caddr_t results_ptr;
234 struct timeval timeout;
235 {
236         register struct ct_data *ct = (struct ct_data *) h->cl_private;
237         register XDR *xdrs = &(ct->ct_xdrs);
238         struct rpc_msg reply_msg;
239         u_long x_id;
240         u_long *msg_x_id = (u_long *) (ct->ct_mcall);   /* yuk */
241         register bool_t shipnow;
242         int refreshes = 2;
243
244         if (!ct->ct_waitset) {
245                 ct->ct_wait = timeout;
246         }
247
248         shipnow =
249                 (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
250                  && timeout.tv_usec == 0) ? FALSE : TRUE;
251
252   call_again:
253         xdrs->x_op = XDR_ENCODE;
254         ct->ct_error.re_status = RPC_SUCCESS;
255         x_id = ntohl(--(*msg_x_id));
256         if ((!XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
257                 (!XDR_PUTLONG(xdrs, (long *) &proc)) ||
258                 (!AUTH_MARSHALL(h->cl_auth, xdrs)) ||
259                 (!(*xdr_args) (xdrs, args_ptr))) {
260                 if (ct->ct_error.re_status == RPC_SUCCESS)
261                         ct->ct_error.re_status = RPC_CANTENCODEARGS;
262                 (void) xdrrec_endofrecord(xdrs, TRUE);
263                 return (ct->ct_error.re_status);
264         }
265         if (!xdrrec_endofrecord(xdrs, shipnow))
266                 return (ct->ct_error.re_status = RPC_CANTSEND);
267         if (!shipnow)
268                 return (RPC_SUCCESS);
269         /*
270          * Hack to provide rpc-based message passing
271          */
272         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
273                 return (ct->ct_error.re_status = RPC_TIMEDOUT);
274         }
275
276
277         /*
278          * Keep receiving until we get a valid transaction id
279          */
280         xdrs->x_op = XDR_DECODE;
281         while (TRUE) {
282                 reply_msg.acpted_rply.ar_verf = _null_auth;
283                 reply_msg.acpted_rply.ar_results.where = NULL;
284                 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
285                 if (!xdrrec_skiprecord(xdrs))
286                         return (ct->ct_error.re_status);
287                 /* now decode and validate the response header */
288                 if (!xdr_replymsg(xdrs, &reply_msg)) {
289                         if (ct->ct_error.re_status == RPC_SUCCESS)
290                                 continue;
291                         return (ct->ct_error.re_status);
292                 }
293                 if (reply_msg.rm_xid == x_id)
294                         break;
295         }
296
297         /*
298          * process header
299          */
300         _seterr_reply(&reply_msg, &(ct->ct_error));
301         if (ct->ct_error.re_status == RPC_SUCCESS) {
302                 if (!AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
303                         ct->ct_error.re_status = RPC_AUTHERROR;
304                         ct->ct_error.re_why = AUTH_INVALIDRESP;
305                 } else if (!(*xdr_results) (xdrs, results_ptr)) {
306                         if (ct->ct_error.re_status == RPC_SUCCESS)
307                                 ct->ct_error.re_status = RPC_CANTDECODERES;
308                 }
309                 /* free verifier ... */
310                 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
311                         xdrs->x_op = XDR_FREE;
312                         (void) xdr_opaque_auth(xdrs, &(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))
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 CLIENT *h;
325 struct rpc_err *errp;
326 {
327         register struct ct_data *ct = (struct ct_data *) h->cl_private;
328
329         *errp = ct->ct_error;
330 }
331
332 static bool_t clnttcp_freeres(cl, xdr_res, res_ptr)
333 CLIENT *cl;
334 xdrproc_t xdr_res;
335 caddr_t res_ptr;
336 {
337         register struct ct_data *ct = (struct ct_data *) cl->cl_private;
338         register XDR *xdrs = &(ct->ct_xdrs);
339
340         xdrs->x_op = XDR_FREE;
341         return ((*xdr_res) (xdrs, res_ptr));
342 }
343
344 static void clnttcp_abort()
345 {
346 }
347
348 static bool_t clnttcp_control(cl, request, info)
349 CLIENT *cl;
350 int request;
351 char *info;
352 {
353         register struct ct_data *ct = (struct ct_data *) cl->cl_private;
354
355         switch (request) {
356         case CLSET_TIMEOUT:
357                 ct->ct_wait = *(struct timeval *) info;
358                 ct->ct_waitset = TRUE;
359                 break;
360         case CLGET_TIMEOUT:
361                 *(struct timeval *) info = ct->ct_wait;
362                 break;
363         case CLGET_SERVER_ADDR:
364                 *(struct sockaddr_in *) info = ct->ct_addr;
365                 break;
366         default:
367                 return (FALSE);
368         }
369         return (TRUE);
370 }
371
372
373 static void clnttcp_destroy(h)
374 CLIENT *h;
375 {
376         register struct ct_data *ct = (struct ct_data *) h->cl_private;
377
378         if (ct->ct_closeit) {
379                 (void) close(ct->ct_sock);
380         }
381         XDR_DESTROY(&(ct->ct_xdrs));
382         mem_free((caddr_t) ct, sizeof(struct ct_data));
383
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(ct, buf, len)
393 register struct ct_data *ct;
394 caddr_t buf;
395 register int len;
396 {
397 #ifdef FD_SETSIZE
398         fd_set mask;
399         fd_set readfds;
400
401         if (len == 0)
402                 return (0);
403         FD_ZERO(&mask);
404         FD_SET(ct->ct_sock, &mask);
405 #else
406         register int mask = 1 << (ct->ct_sock);
407         int readfds;
408
409         if (len == 0)
410                 return (0);
411
412 #endif                                                  /* def FD_SETSIZE */
413         while (TRUE) {
414                 readfds = mask;
415                 switch (select
416                                 (_rpc_dtablesize(), &readfds,  NULL,  NULL,
417                                  &(ct->ct_wait))) {
418                 case 0:
419                         ct->ct_error.re_status = RPC_TIMEDOUT;
420                         return (-1);
421
422                 case -1:
423                         if (errno == EINTR)
424                                 continue;
425                         ct->ct_error.re_status = RPC_CANTRECV;
426                         ct->ct_error.re_errno = errno;
427                         return (-1);
428                 }
429                 break;
430         }
431         switch (len = read(ct->ct_sock, buf, len)) {
432
433         case 0:
434                 /* premature eof */
435                 ct->ct_error.re_errno = ECONNRESET;
436                 ct->ct_error.re_status = RPC_CANTRECV;
437                 len = -1;                               /* it's really an error */
438                 break;
439
440         case -1:
441                 ct->ct_error.re_errno = errno;
442                 ct->ct_error.re_status = RPC_CANTRECV;
443                 break;
444         }
445         return (len);
446 }
447
448 static int writetcp(ct, buf, len)
449 struct ct_data *ct;
450 caddr_t buf;
451 int len;
452 {
453         register int i, cnt;
454
455         for (cnt = len; cnt > 0; cnt -= i, buf += i) {
456                 if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
457                         ct->ct_error.re_errno = errno;
458                         ct->ct_error.re_status = RPC_CANTSEND;
459                         return (-1);
460                 }
461         }
462         return (len);
463 }