|
|
1.1 root 1: /*
2: * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3: * unrestricted use provided that this legend is included on all tape
4: * media and as a part of the software program in whole or part. Users
5: * may copy or modify Sun RPC without charge, but are not authorized
6: * to license or distribute it to anyone else except as part of a product or
7: * program developed by the user.
8: *
9: * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10: * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11: * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12: *
13: * Sun RPC is provided with no support and without any obligation on the
14: * part of Sun Microsystems, Inc. to assist in its use, correction,
15: * modification or enhancement.
16: *
17: * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18: * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19: * OR ANY PART THEREOF.
20: *
21: * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22: * or profits or other special, indirect and consequential damages, even if
23: * Sun has been advised of the possibility of such damages.
24: *
25: * Sun Microsystems, Inc.
26: * 2550 Garcia Avenue
27: * Mountain View, California 94043
28: */
29: #ifndef lint
30: static char sccsid[] = "@(#)clnt_tcp.c 1.5 85/03/17 Copyr 1984 Sun Micro";
31: #endif
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 iff 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 "types.h"
54: #include <sys/socket.h>
55: #include <sys/time.h>
56: #include <netinet/in.h>
57: #include <netdb.h>
58: #include <errno.h>
59: #include "xdr.h"
60: #include "auth.h"
61: #include "clnt.h"
62: #include "rpc_msg.h"
63: #include "pmap_clnt.h"
64:
65: #define MCALL_MSG_SIZE 24
66:
67: char *malloc();
68: extern int errno;
69: long random();
70:
71: static int readtcp();
72: static int writetcp();
73:
74: static enum clnt_stat clnttcp_call();
75: static void clnttcp_abort();
76: static void clnttcp_geterr();
77: static bool_t clnttcp_freeres();
78: static void clnttcp_destroy();
79:
80: static struct clnt_ops tcp_ops = {
81: clnttcp_call,
82: clnttcp_abort,
83: clnttcp_geterr,
84: clnttcp_freeres,
85: clnttcp_destroy
86: };
87:
88: struct ct_data {
89: int ct_sock;
90: struct timeval ct_wait;
91: struct rpc_err ct_error;
92: char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
93: u_int ct_mpos; /* pos after marshal */
94: XDR ct_xdrs;
95: };
96:
97: /*
98: * Create a client handle for a tcp/ip connection.
99: * If *sockp<0, *sockp is set to a newly created TCP socket and it is
100: * connected to raddr. If *sockp non-negative then
101: * raddr is ignored. The rpc/tcp package does buffering
102: * similar to stdio, so the client must pick send and receive buffer sizes,];
103: * 0 => use the default.
104: * If raddr->sin_port is 0, then a binder on the remote machine is
105: * consulted for the right port number.
106: * NB: *sockp is copied into a private area.
107: * NB: It is the clients responsibility to close *sockp.
108: * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
109: * something more useful.
110: */
111: CLIENT *
112: clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
113: struct sockaddr_in *raddr;
114: u_long prog;
115: u_long vers;
116: register int *sockp;
117: u_int sendsz;
118: u_int recvsz;
119: {
120: CLIENT *h;
121: register struct ct_data *ct;
122: struct timeval now;
123: struct rpc_msg call_msg;
124:
125: h = (CLIENT *)mem_alloc(sizeof(*h));
126: if (h == NULL) {
127: fprintf(stderr, "clnttcp_create: out of memory\n");
128: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
129: rpc_createerr.cf_error.re_errno = errno;
130: goto fooy;
131: }
132: ct = (struct ct_data *)mem_alloc(sizeof(*ct));
133: if (ct == NULL) {
134: fprintf(stderr, "clnttcp_create: out of memory\n");
135: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
136: rpc_createerr.cf_error.re_errno = errno;
137: goto fooy;
138: }
139:
140: /*
141: * If no port number given ask the pmap for one
142: */
143: if (raddr->sin_port == 0) {
144: u_short port;
145: if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 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: if (((*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
158: || (connect(*sockp, (struct sockaddr *)raddr,
159: sizeof(*raddr)) < 0)) {
160: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
161: rpc_createerr.cf_error.re_errno = errno;
162: goto fooy;
163: }
164: }
165:
166: /*
167: * Set up private data struct
168: */
169: ct->ct_sock = *sockp;
170: ct->ct_wait.tv_usec = 0;
171:
172: /*
173: * Initialize call message
174: */
175: (void)gettimeofday(&now, (struct timezone *)0);
176: call_msg.rm_xid = getpid() ^ (int)random() ^ 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: goto fooy;
189: }
190: ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
191: XDR_DESTROY(&(ct->ct_xdrs));
192:
193: /*
194: * Create a client handle which uses xdrrec for serialization
195: * and authnone for authentication.
196: */
197: xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
198: (caddr_t)ct, readtcp, writetcp);
199: h->cl_ops = &tcp_ops;
200: h->cl_private = (caddr_t) ct;
201: h->cl_auth = authnone_create();
202: return (h);
203:
204: fooy:
205: /*
206: * Something goofed, free stuff and barf
207: */
208: mem_free((caddr_t)ct, sizeof(struct ct_data));
209: mem_free((caddr_t)h, sizeof(CLIENT));
210: (void)close(*sockp);
211: return ((CLIENT *)NULL);
212: }
213:
214: static enum clnt_stat
215: clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
216: register CLIENT *h;
217: u_long proc;
218: xdrproc_t xdr_args;
219: caddr_t args_ptr;
220: xdrproc_t xdr_results;
221: caddr_t results_ptr;
222: struct timeval timeout;
223: {
224: register struct ct_data *ct = (struct ct_data *) h->cl_private;
225: register XDR *xdrs = &(ct->ct_xdrs);
226: struct rpc_msg reply_msg;
227: u_long x_id;
228: u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */
229: register bool_t shipnow;
230:
231: ct->ct_wait = timeout;
232: shipnow =
233: (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
234: && timeout.tv_usec == 0) ? FALSE : TRUE;
235:
236: call_again:
237: xdrs->x_op = XDR_ENCODE;
238: ct->ct_error.re_status = RPC_SUCCESS;
239: x_id = ntohl(--(*msg_x_id));
240: if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
241: (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
242: (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
243: (! (*xdr_args)(xdrs, args_ptr))) {
244: if (ct->ct_error.re_status == RPC_SUCCESS)
245: ct->ct_error.re_status = RPC_CANTENCODEARGS;
246: (void)xdrrec_endofrecord(xdrs, TRUE);
247: return (ct->ct_error.re_status);
248: }
249: if (! xdrrec_endofrecord(xdrs, shipnow))
250: return (ct->ct_error.re_status = RPC_CANTSEND);
251: if (! shipnow)
252: return (RPC_SUCCESS);
253: xdrs->x_op = XDR_DECODE;
254:
255: /*
256: * Keep receiving until we get a valid transaction id
257: */
258: while (TRUE) {
259: reply_msg.acpted_rply.ar_verf = _null_auth;
260: reply_msg.acpted_rply.ar_results.where = NULL;
261: reply_msg.acpted_rply.ar_results.proc = xdr_void;
262: if (! xdrrec_skiprecord(xdrs))
263: return (ct->ct_error.re_status);
264: /* now decode and validate the response header */
265: if (! xdr_replymsg(xdrs, &reply_msg)) {
266: if (ct->ct_error.re_status == RPC_SUCCESS)
267: continue;
268: return (ct->ct_error.re_status);
269: }
270: if (reply_msg.rm_xid == x_id)
271: break;
272: }
273:
274: /*
275: * process header
276: */
277: _seterr_reply(&reply_msg, &(ct->ct_error));
278: if (ct->ct_error.re_status == RPC_SUCCESS) {
279: if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
280: ct->ct_error.re_status = RPC_AUTHERROR;
281: ct->ct_error.re_why = AUTH_INVALIDRESP;
282: } else if (! (*xdr_results)(xdrs, results_ptr)) {
283: if (ct->ct_error.re_status == RPC_SUCCESS)
284: ct->ct_error.re_status = RPC_CANTDECODERES;
285: }
286: /* free verifier ... */
287: if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
288: xdrs->x_op = XDR_FREE;
289: (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
290: }
291: } /* end successful completion */
292: else {
293: /* maybe our credentials need to be refreshed ... */
294: if (AUTH_REFRESH(h->cl_auth))
295: goto call_again;
296: } /* end of unsuccessful completion */
297: return (ct->ct_error.re_status);
298: }
299:
300: static void
301: clnttcp_geterr(h, errp)
302: CLIENT *h;
303: struct rpc_err *errp;
304: {
305: register struct ct_data *ct =
306: (struct ct_data *) h->cl_private;
307:
308: *errp = ct->ct_error;
309: }
310:
311: static bool_t
312: clnttcp_freeres(cl, xdr_res, res_ptr)
313: CLIENT *cl;
314: xdrproc_t xdr_res;
315: caddr_t res_ptr;
316: {
317: register struct ct_data *ct = (struct ct_data *)cl->cl_private;
318: register XDR *xdrs = &(ct->ct_xdrs);
319:
320: xdrs->x_op = XDR_FREE;
321: return ((*xdr_res)(xdrs, res_ptr));
322: }
323:
324: static void
325: clnttcp_abort()
326: {
327: }
328:
329: static void
330: clnttcp_destroy(h)
331: CLIENT *h;
332: {
333: register struct ct_data *ct =
334: (struct ct_data *) h->cl_private;
335:
336: XDR_DESTROY(&(ct->ct_xdrs));
337: mem_free((caddr_t)ct, sizeof(struct ct_data));
338: mem_free((caddr_t)h, sizeof(CLIENT));
339: }
340:
341: /*
342: * Interface between xdr serializer and tcp connection.
343: * Behaves like the system calls, read & write, but keeps some error state
344: * around for the rpc level.
345: */
346: static int
347: readtcp(ct, buf, len)
348: register struct ct_data *ct;
349: caddr_t buf;
350: register int len;
351: {
352: register int mask = 1 << (ct->ct_sock);
353: int readfds;
354:
355: while (TRUE) {
356: readfds = mask;
357: switch (select(32, &readfds, (int*)NULL, (int*)NULL,
358: &(ct->ct_wait))) {
359:
360: case 0:
361: ct->ct_error.re_status = RPC_TIMEDOUT;
362: return (-1);
363:
364: case -1:
365: if (errno == EINTR)
366: continue;
367: ct->ct_error.re_status = RPC_CANTRECV;
368: ct->ct_error.re_errno = errno;
369: return (-1);
370: }
371: if (readfds == mask)
372: break;
373: }
374: if ((len = read(ct->ct_sock, buf, len)) == -1) {
375: ct->ct_error.re_errno = errno;
376: ct->ct_error.re_status = RPC_CANTRECV;
377: }
378: return (len);
379: }
380:
381: static int
382: writetcp(ct, buf, len)
383: struct ct_data *ct;
384: caddr_t buf;
385: int len;
386: {
387: register int i, cnt;
388:
389: for (cnt = len; cnt > 0; cnt -= i, buf += i) {
390: if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
391: ct->ct_error.re_errno = errno;
392: ct->ct_error.re_status = RPC_CANTSEND;
393: return (-1);
394: }
395: }
396: return (len);
397: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.