|
|
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_udp.c 1.5 85/03/17 Copyr 1984 Sun Micro";
31: #endif
32:
33: /*
34: * clnt_udp.c, Implements a UPD/IP based, client side RPC.
35: *
36: * Copyright (C) 1984, Sun Microsystems, Inc.
37: */
38:
39: #include <stdio.h>
40: #include "types.h"
41: #include <sys/socket.h>
42: #include <sys/time.h>
43: #include <netinet/in.h>
44: #include <netdb.h>
45: #include <errno.h>
46: #include "xdr.h"
47: #include "auth.h"
48: #include "clnt.h"
49: #include "rpc_msg.h"
50: #include "pmap_clnt.h"
51:
52: char *malloc();
53: extern int errno;
54: long random();
55:
56: /*
57: * UDP bases client side rpc operations
58: */
59: static enum clnt_stat clntudp_call();
60: static void clntudp_abort();
61: static void clntudp_geterr();
62: static bool_t clntudp_freeres();
63: static void clntudp_destroy();
64:
65: static struct clnt_ops udp_ops = {
66: clntudp_call,
67: clntudp_abort,
68: clntudp_geterr,
69: clntudp_freeres,
70: clntudp_destroy
71: };
72:
73: /*
74: * Private data kept per client handle
75: */
76: struct cu_data {
77: int cu_sock;
78: struct sockaddr_in cu_raddr;
79: int cu_rlen;
80: struct timeval cu_wait;
81: struct rpc_err cu_error;
82: XDR cu_outxdrs;
83: u_int cu_xdrpos;
84: char cu_outbuf[UDPMSGSIZE];
85: char cu_inbuf[UDPMSGSIZE];
86: };
87:
88: /*
89: * Create a UDP based client handle.
90: * If *sockp<0, *sockp is set to a newly created UPD socket.
91: * If raddr->sin_port is 0 a binder on the remote machine
92: * is consulted for the correct port number.
93: * NB: It is the clients responsibility to close *sockp.
94: * NB: The rpch->cl_auth is initialized to null authentication.
95: * Caller may wish to set this something more useful.
96: *
97: * wait is the amount of time used between retransmitting a call if
98: * no response has been heard; retransmition occurs until the actual
99: * rpc call times out.
100: */
101: CLIENT *
102: clntudp_create(raddr, program, version, wait, sockp)
103: struct sockaddr_in *raddr;
104: u_long program;
105: u_long version;
106: struct timeval wait;
107: register int *sockp;
108: {
109: CLIENT *cl;
110: register struct cu_data *cu;
111: struct timeval now;
112: struct rpc_msg call_msg;
113:
114: cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
115: if (cl == NULL) {
116: fprintf(stderr, "clntudp_create: out of memory\n");
117: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
118: rpc_createerr.cf_error.re_errno = errno;
119: goto fooy;
120: }
121: cu = (struct cu_data *)mem_alloc(sizeof(*cu));
122: if (cu == NULL) {
123: fprintf(stderr, "clntudp_create: out of memory\n");
124: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
125: rpc_createerr.cf_error.re_errno = errno;
126: goto fooy;
127: }
128:
129: (void)gettimeofday(&now, (struct timezone *)0);
130: if (raddr->sin_port == 0) {
131: u_short port;
132: if ((port =
133: pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
134: goto fooy;
135: }
136: raddr->sin_port = htons(port);
137: }
138: cl->cl_ops = &udp_ops;
139: cl->cl_private = (caddr_t)cu;
140: cu->cu_raddr = *raddr;
141: cu->cu_rlen = sizeof (cu->cu_raddr);
142: cu->cu_wait = wait;
143: call_msg.rm_xid = getpid() ^ (int)random() ^ now.tv_sec ^ now.tv_usec;
144: call_msg.rm_direction = CALL;
145: call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
146: call_msg.rm_call.cb_prog = program;
147: call_msg.rm_call.cb_vers = version;
148: xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
149: UDPMSGSIZE, XDR_ENCODE);
150: if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
151: goto fooy;
152: }
153: cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
154: cu->cu_sock = (*sockp < 0) ?
155: (*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) :
156: *sockp;
157: if (cu->cu_sock < 0) {
158: rpc_createerr.cf_stat = RPC_SYSTEMERROR;
159: rpc_createerr.cf_error.re_errno = errno;
160: goto fooy;
161: }
162: cl->cl_auth = authnone_create();
163: return (cl);
164: fooy:
165: mem_free((caddr_t)cu, sizeof(*cu));
166: mem_free((caddr_t)cl, sizeof(CLIENT));
167: return ((CLIENT *)NULL);
168: }
169:
170: static enum clnt_stat
171: clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, timeout)
172: register CLIENT *cl; /* client handle */
173: u_long proc; /* procedure number */
174: xdrproc_t xargs; /* xdr routine for args */
175: caddr_t argsp; /* pointer to args */
176: xdrproc_t xresults; /* xdr routine for results */
177: caddr_t resultsp; /* pointer to results */
178: struct timeval timeout; /* seconds to wait before giving up */
179: {
180: register struct cu_data *cu = (struct cu_data *)cl->cl_private;
181: register XDR *xdrs;
182: register int outlen;
183: register int inlen;
184: int readfds, fromlen;
185: register int mask;
186: struct sockaddr_in from;
187: struct rpc_msg reply_msg;
188: XDR reply_xdrs;
189: struct timeval time_waited;
190: bool_t ok;
191:
192: call_again:
193: time_waited.tv_sec = 0;
194: time_waited.tv_usec = 0;
195: xdrs = &(cu->cu_outxdrs);
196: xdrs->x_op = XDR_ENCODE;
197: XDR_SETPOS(xdrs, cu->cu_xdrpos);
198: /*
199: * the transaction is the first thing in the out buffer
200: */
201: (*(u_short *)(cu->cu_outbuf))++;
202: if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
203: (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
204: (! (*xargs)(xdrs, argsp)))
205: return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
206: outlen = (int)XDR_GETPOS(xdrs);
207: while (TRUE) {
208:
209: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
210: (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
211: != outlen) {
212: cu->cu_error.re_errno = errno;
213: return (cu->cu_error.re_status = RPC_CANTSEND);
214: }
215: /*
216: * sub-optimal code appears inside the loop because we have
217: * some clock time to spare while the packets are in flight.
218: * (We assume that this is actually only executed once.)
219: */
220: reply_msg.acpted_rply.ar_verf = _null_auth;
221: reply_msg.acpted_rply.ar_results.where = resultsp;
222: reply_msg.acpted_rply.ar_results.proc = xresults;
223: mask = 1 << cu->cu_sock;
224: rcv_again:
225: readfds = mask;
226: switch (select(32, &readfds, (int *)NULL, (int *)NULL,
227: &(cu->cu_wait))) {
228:
229: case 0:
230: time_waited.tv_sec += cu->cu_wait.tv_sec;
231: time_waited.tv_usec += cu->cu_wait.tv_usec;
232: while (time_waited.tv_usec >= 1000000) {
233: time_waited.tv_sec++;
234: time_waited.tv_usec -= 1000000;
235: }
236: if ((time_waited.tv_sec < timeout.tv_sec) ||
237: ((time_waited.tv_sec == timeout.tv_sec) &&
238: (time_waited.tv_usec < timeout.tv_usec)))
239: continue;
240: return (cu->cu_error.re_status = RPC_TIMEDOUT);
241:
242: case -1:
243: if (errno == EINTR)
244: goto rcv_again;
245: cu->cu_error.re_errno = errno;
246: return (cu->cu_error.re_status = RPC_CANTRECV);
247: }
248: if ((readfds & mask) == 0)
249: goto rcv_again;
250: tryagain:
251: fromlen = sizeof(struct sockaddr);
252: inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, UDPMSGSIZE, 0,
253: (struct sockaddr *)&from, &fromlen);
254: if (inlen < 0) {
255: if (errno == EINTR)
256: goto tryagain;
257: cu->cu_error.re_errno = errno;
258: return (cu->cu_error.re_status = RPC_CANTRECV);
259: }
260: if (inlen < sizeof(u_long))
261: goto rcv_again;
262: /* see if reply transaction id matches sent id */
263: if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
264: goto rcv_again;
265: /* we now assume we have the proper reply */
266: break;
267: }
268:
269: /*
270: * now decode and validate the response
271: */
272: xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
273: ok = xdr_replymsg(&reply_xdrs, &reply_msg);
274: /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
275: if (ok) {
276: _seterr_reply(&reply_msg, &(cu->cu_error));
277: if (cu->cu_error.re_status == RPC_SUCCESS) {
278: if (! AUTH_VALIDATE(cl->cl_auth,
279: &reply_msg.acpted_rply.ar_verf)) {
280: cu->cu_error.re_status = RPC_AUTHERROR;
281: cu->cu_error.re_why = AUTH_INVALIDRESP;
282: }
283: if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
284: xdrs->x_op = XDR_FREE;
285: (void)xdr_opaque_auth(xdrs,
286: &(reply_msg.acpted_rply.ar_verf));
287: }
288: } /* end successful completion */
289: else {
290: /* maybe our credentials need to be refreshed ... */
291: if (AUTH_REFRESH(cl->cl_auth))
292: goto call_again;
293: } /* end of unsuccessful completion */
294: } /* end of valid reply message */
295: else {
296: cu->cu_error.re_status = RPC_CANTDECODERES;
297: }
298: return (cu->cu_error.re_status);
299: }
300:
301: static void
302: clntudp_geterr(cl, errp)
303: CLIENT *cl;
304: struct rpc_err *errp;
305: {
306: register struct cu_data *cu = (struct cu_data *)cl->cl_private;
307:
308: *errp = cu->cu_error;
309: }
310:
311:
312: static bool_t
313: clntudp_freeres(cl, xdr_res, res_ptr)
314: CLIENT *cl;
315: xdrproc_t xdr_res;
316: caddr_t res_ptr;
317: {
318: register struct cu_data *cu = (struct cu_data *)cl->cl_private;
319: register XDR *xdrs = &(cu->cu_outxdrs);
320:
321: xdrs->x_op = XDR_FREE;
322: return ((*xdr_res)(xdrs, res_ptr));
323: }
324:
325: static void
326: clntudp_abort(/*h*/)
327: /*CLIENT *h;*/
328: {
329: }
330:
331: static void
332: clntudp_destroy(cl)
333: CLIENT *cl;
334: {
335: register struct cu_data *cu = (struct cu_data *)cl->cl_private;
336:
337: XDR_DESTROY(&(cu->cu_outxdrs));
338: mem_free((caddr_t)cu, sizeof(*cu));
339: mem_free((caddr_t)cl, sizeof(CLIENT));
340: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.