1 /* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */
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.
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.
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.
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.
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.
26 * Sun Microsystems, Inc.
28 * Mountain View, California 94043
30 #if !defined(lint) && defined(SCCSIDS)
31 static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
35 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
37 * Copyright (C) 1984, Sun Microsystems, Inc.
42 #include <gssrpc/rpc.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
46 #include <sys/filio.h>
51 #include <gssrpc/pmap_clnt.h>
56 * UDP bases client side rpc operations
58 static enum clnt_stat clntudp_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
59 xdrproc_t, void *, struct timeval);
60 static void clntudp_abort(CLIENT *);
61 static void clntudp_geterr(CLIENT *, struct rpc_err *);
62 static bool_t clntudp_freeres(CLIENT *, xdrproc_t, void *);
63 static bool_t clntudp_control(CLIENT *, int, void *);
64 static void clntudp_destroy(CLIENT *);
66 static struct clnt_ops udp_ops = {
76 * Private data kept per client handle
81 struct sockaddr_in cu_raddr;
83 struct sockaddr_in cu_laddr;
85 struct timeval cu_wait;
86 struct timeval cu_total;
87 struct rpc_err cu_error;
97 * Create a UDP based client handle.
98 * If *sockp<0, *sockp is set to a newly created UPD socket.
99 * If raddr->sin_port is 0 a binder on the remote machine
100 * is consulted for the correct port number.
101 * NB: It is the clients responsibility to close *sockp.
102 * NB: The rpch->cl_auth is initialized to null authentication.
103 * Caller may wish to set this something more useful.
105 * wait is the amount of time used between retransmitting a call if
106 * no response has been heard; retransmition occurs until the actual
107 * rpc call times out.
109 * sendsz and recvsz are the maximum allowable packet sizes that can be
114 struct sockaddr_in *raddr,
123 register struct cu_data *cu = 0;
125 struct rpc_msg call_msg;
127 cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
129 (void) fprintf(stderr, "clntudp_create: out of memory\n");
130 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
131 rpc_createerr.cf_error.re_errno = errno;
134 sendsz = ((sendsz + 3) / 4) * 4;
135 recvsz = ((recvsz + 3) / 4) * 4;
136 cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
138 (void) fprintf(stderr, "clntudp_create: out of memory\n");
139 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
140 rpc_createerr.cf_error.re_errno = errno;
143 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
145 (void)gettimeofday(&now, (struct timezone *)0);
146 if (raddr->sin_port == 0) {
149 pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
152 raddr->sin_port = htons(port);
154 cl->cl_ops = &udp_ops;
155 cl->cl_private = (caddr_t)cu;
156 cu->cu_raddr = *raddr;
157 cu->cu_rlen = sizeof (cu->cu_raddr);
159 cu->cu_total.tv_sec = -1;
160 cu->cu_total.tv_usec = -1;
161 cu->cu_sendsz = sendsz;
162 cu->cu_recvsz = recvsz;
163 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
164 call_msg.rm_direction = CALL;
165 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
166 call_msg.rm_call.cb_prog = program;
167 call_msg.rm_call.cb_vers = version;
168 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
170 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
173 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
177 *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
179 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
180 rpc_createerr.cf_error.re_errno = errno;
183 /* attempt to bind to prov port */
184 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
185 /* the sockets rpc controls are non-blocking */
186 (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
187 cu->cu_closeit = TRUE;
189 cu->cu_closeit = FALSE;
191 if (connect(*sockp, (struct sockaddr *)raddr, sizeof(*raddr)) < 0)
193 cu->cu_llen = sizeof(cu->cu_laddr);
194 if (getsockname(*sockp, (struct sockaddr *)&cu->cu_laddr, &cu->cu_llen) < 0)
197 cu->cu_sock = *sockp;
198 cl->cl_auth = authnone_create();
202 mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
204 mem_free((caddr_t)cl, sizeof(CLIENT));
205 return ((CLIENT *)NULL);
210 struct sockaddr_in *raddr,
217 return(clntudp_bufcreate(raddr, program, version, wait, sockp,
218 UDPMSGSIZE, UDPMSGSIZE));
221 static enum clnt_stat
223 register CLIENT *cl, /* client handle */
224 rpcproc_t proc, /* procedure number */
225 xdrproc_t xargs, /* xdr routine for args */
226 void * argsp, /* pointer to args */
227 xdrproc_t xresults, /* xdr routine for results */
228 void * resultsp, /* pointer to results */
229 struct timeval utimeout /* seconds to wait before
233 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
244 #endif /* def FD_SETSIZE */
245 struct sockaddr_in from;
246 struct rpc_msg reply_msg;
248 struct timeval time_waited, seltimeout;
250 int nrefreshes = 2; /* number of times to refresh cred */
251 struct timeval timeout;
254 if (cu->cu_total.tv_usec == -1) {
255 timeout = utimeout; /* use supplied timeout */
257 timeout = cu->cu_total; /* use default timeout */
260 time_waited.tv_sec = 0;
261 time_waited.tv_usec = 0;
263 xdrs = &(cu->cu_outxdrs);
264 xdrs->x_op = XDR_ENCODE;
265 XDR_SETPOS(xdrs, cu->cu_xdrpos);
267 * the transaction is the first thing in the out buffer
269 (*(uint32_t *)(void *)(cu->cu_outbuf))++;
270 if ((! XDR_PUTLONG(xdrs, &procl)) ||
271 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
272 (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp)))
273 return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
274 outlen = (int)XDR_GETPOS(xdrs);
277 if (send(cu->cu_sock, cu->cu_outbuf, (u_int)outlen, 0) != outlen) {
278 cu->cu_error.re_errno = errno;
279 return (cu->cu_error.re_status = RPC_CANTSEND);
283 * Hack to provide rpc-based message passing
285 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
286 return (cu->cu_error.re_status = RPC_TIMEDOUT);
289 * sub-optimal code appears here because we have
290 * some clock time to spare while the packets are in flight.
291 * (We assume that this is actually only executed once.)
293 reply_msg.acpted_rply.ar_verf = gssrpc__null_auth;
294 reply_msg.acpted_rply.ar_results.where = NULL;
295 reply_msg.acpted_rply.ar_results.proc = xdr_void;
298 FD_SET(cu->cu_sock, &mask);
300 mask = 1 << cu->cu_sock;
301 #endif /* def FD_SETSIZE */
304 seltimeout = cu->cu_wait;
305 switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set *)NULL,
306 (fd_set *)NULL, &seltimeout)) {
309 time_waited.tv_sec += cu->cu_wait.tv_sec;
310 time_waited.tv_usec += cu->cu_wait.tv_usec;
311 while (time_waited.tv_usec >= 1000000) {
312 time_waited.tv_sec++;
313 time_waited.tv_usec -= 1000000;
315 if ((time_waited.tv_sec < timeout.tv_sec) ||
316 ((time_waited.tv_sec == timeout.tv_sec) &&
317 (time_waited.tv_usec < timeout.tv_usec)))
319 return (cu->cu_error.re_status = RPC_TIMEDOUT);
322 * buggy in other cases because time_waited is not being
328 cu->cu_error.re_errno = errno;
329 return (cu->cu_error.re_status = RPC_CANTRECV);
332 fromlen = sizeof(struct sockaddr);
333 inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
335 (struct sockaddr *)&from, &fromlen);
336 } while (inlen < 0 && errno == EINTR);
338 if (errno == EWOULDBLOCK)
340 cu->cu_error.re_errno = errno;
341 return (cu->cu_error.re_status = RPC_CANTRECV);
343 if (inlen < sizeof(uint32_t))
345 /* see if reply transaction id matches sent id */
346 if (*((uint32_t *)(void *)(cu->cu_inbuf)) !=
347 *((uint32_t *)(void *)(cu->cu_outbuf)))
349 /* we now assume we have the proper reply */
354 * now decode and validate the response
356 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
357 ok = xdr_replymsg(&reply_xdrs, &reply_msg);
358 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
360 gssrpc__seterr_reply(&reply_msg, &(cu->cu_error));
361 if (cu->cu_error.re_status == RPC_SUCCESS) {
362 if (! AUTH_VALIDATE(cl->cl_auth,
363 &reply_msg.acpted_rply.ar_verf)) {
364 cu->cu_error.re_status = RPC_AUTHERROR;
365 cu->cu_error.re_why = AUTH_INVALIDRESP;
366 } else if (! AUTH_UNWRAP(cl->cl_auth, &reply_xdrs,
367 xresults, resultsp)) {
368 if (cu->cu_error.re_status == RPC_SUCCESS)
369 cu->cu_error.re_status = RPC_CANTDECODERES;
371 } /* end successful completion */
373 /* maybe our credentials need to be refreshed ... */
374 if (nrefreshes > 0 &&
375 AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
379 } /* end of unsuccessful completion */
381 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
382 (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) {
383 xdrs->x_op = XDR_FREE;
384 (void)xdr_opaque_auth(xdrs,
385 &(reply_msg.acpted_rply.ar_verf));
387 } /* end of valid reply message */
390 * It's possible for xdr_replymsg() to fail partway
391 * through its attempt to decode the result from the
392 * server. If this happens, it will leave the reply
393 * structure partially populated with dynamically
394 * allocated memory. (This can happen if someone uses
395 * clntudp_bufcreate() to create a CLIENT handle and
396 * specifies a receive buffer size that is too small.)
397 * This memory must be free()ed to avoid a leak.
399 enum xdr_op op = reply_xdrs.x_op;
400 reply_xdrs.x_op = XDR_FREE;
401 xdr_replymsg(&reply_xdrs, &reply_msg);
402 reply_xdrs.x_op = op;
403 return (RPC_CANTDECODERES);
404 cu->cu_error.re_status = RPC_CANTDECODERES;
406 return (cu->cu_error.re_status);
412 struct rpc_err *errp)
414 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
416 *errp = cu->cu_error;
426 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
427 register XDR *xdrs = &(cu->cu_outxdrs);
429 xdrs->x_op = XDR_FREE;
430 return ((*xdr_res)(xdrs, res_ptr));
436 clntudp_abort(CLIENT *h)
446 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
450 cu->cu_total = *(struct timeval *)info;
453 *(struct timeval *)info = cu->cu_total;
455 case CLSET_RETRY_TIMEOUT:
456 cu->cu_wait = *(struct timeval *)info;
458 case CLGET_RETRY_TIMEOUT:
459 *(struct timeval *)info = cu->cu_wait;
461 case CLGET_SERVER_ADDR:
462 *(struct sockaddr_in *)info = cu->cu_raddr;
464 case CLGET_LOCAL_ADDR:
465 *(struct sockaddr_in *)info = cu->cu_laddr;
474 clntudp_destroy(CLIENT *cl)
476 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
478 if (cu->cu_closeit) {
479 (void)close(cu->cu_sock);
481 XDR_DESTROY(&(cu->cu_outxdrs));
482 mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
483 mem_free((caddr_t)cl, sizeof(CLIENT));