2 static char sfs_clnt_id[] = "@(#)clnt_udp.c 2.1 97/10/23";
4 /* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */
6 * Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
8 * Standard Performance Evaluation Corporation (SPEC)
9 * 6585 Merchant Place, Suite 100
12 * This product contains benchmarks acquired from several sources who
13 * understand and agree with SPEC's goal of creating fair and objective
14 * benchmarks to measure computer performance.
16 * This copyright notice is placed here only to protect SPEC in the
17 * event the source is misused in any manner that is contrary to the
18 * spirit, the goals and the intent of SPEC.
20 * The source code is provided to the user or company under the license
21 * agreement for the SPEC Benchmark Suite for this product.
24 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
25 * unrestricted use provided that this legend is included on all tape
26 * media and as a part of the software program in whole or part. Users
27 * may copy or modify Sun RPC without charge, but are not authorized
28 * to license or distribute it to anyone else except as part of a product or
29 * program developed by the user.
31 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
32 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
35 * Sun RPC is provided with no support and without any obligation on the
36 * part of Sun Microsystems, Inc. to assist in its use, correction,
37 * modification or enhancement.
39 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
40 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
41 * OR ANY PART THEREOF.
43 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
44 * or profits or other special, indirect and consequential damages, even if
45 * Sun has been advised of the possibility of such damages.
47 * Sun Microsystems, Inc.
49 * Mountain View, California 94043
51 #if !defined(lint) && defined(SCCSIDS)
52 static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
56 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
58 * Copyright (C) 1984, Sun Microsystems, Inc.
66 #endif /* ndef Free BSD */
69 #include "rpc/osdep.h"
72 #include "rpc/pmap_clnt.h"
75 * Private data kept per client handle
80 struct sockaddr_in cu_raddr;
82 struct timeval cu_wait;
83 struct timeval cu_total;
84 struct rpc_err cu_error;
94 * UDP bases client side rpc operations
96 static enum clnt_stat clntudp_call(CLIENT *, uint32_t, xdrproc_t, void *,
97 xdrproc_t, void *, struct timeval);
98 static void clntudp_abort(CLIENT *);
99 static void clntudp_geterr(CLIENT *, struct rpc_err *);
100 static bool_t clntudp_freeres(CLIENT *, xdrproc_t, void *);
101 static bool_t clntudp_control(CLIENT *, uint_t, void *);
102 static void clntudp_destroy(CLIENT *);
103 static bool_t clntudp_getreply(CLIENT *, xdrproc_t, void *,
104 int, uint32_t *, uint32_t *, struct timeval *);
105 static int clntudp_poll(CLIENT *, uint32_t);
107 static struct clnt_ops udp_ops = {
119 * Create a UDP based client handle.
120 * If *sockp<0, *sockp is set to a newly created UPD socket.
121 * If raddr->sin_port is 0 a binder on the remote machine
122 * is consulted for the correct port number.
123 * NB: It is the clients responsibility to close *sockp.
124 * NB: The rpch->cl_auth is initialized to null authentication.
125 * Caller may wish to set this something more useful.
127 * wait is the amount of time used between retransmitting a call if
128 * no response has been heard; retransmition occurs until the actual
129 * rpc call times out.
131 * sendsz and recvsz are the maximum allowable packet sizes that can be
136 struct sockaddr_in *raddr,
147 struct rpc_msg call_msg;
149 cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
151 (void) fprintf(stderr, "clntudp_create: out of memory\n");
152 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
153 rpc_createerr.cf_error.re_errno = errno;
156 sendsz = ((sendsz + 3) / 4) * 4;
157 recvsz = ((recvsz + 3) / 4) * 4;
158 cu = (struct cu_data *)mem_alloc(sizeof(struct cu_data) +
161 (void) fprintf(stderr, "clntudp_create: out of memory\n");
162 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
163 rpc_createerr.cf_error.re_errno = errno;
166 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
168 (void)gettimeofday(&now, (struct timezone *)0);
169 if (raddr->sin_port == 0) {
172 pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
175 raddr->sin_port = htons(port);
177 cl->cl_ops = &udp_ops;
178 cl->cl_private = (char *)cu;
179 cu->cu_raddr = *raddr;
180 cu->cu_rlen = sizeof (cu->cu_raddr);
182 cu->cu_total.tv_sec = -1;
183 cu->cu_total.tv_usec = -1;
184 cu->cu_sendsz = sendsz;
185 cu->cu_recvsz = recvsz;
186 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
187 call_msg.rm_direction = CALL;
188 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
189 call_msg.rm_call.cb_prog = program;
190 call_msg.rm_call.cb_vers = version;
191 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
193 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
196 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
198 #if defined(O_NONBLOCK)
200 #elif defined(FIONBIO)
204 *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
206 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
207 rpc_createerr.cf_error.re_errno = errno;
210 /* attempt to bind to prov port */
211 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
212 /* the sockets rpc controls are non-blocking */
213 #if defined(O_NONBLOCK)
214 flags = fcntl(*sockp, F_GETFL, 0) | O_NONBLOCK;
215 (void)fcntl(*sockp, F_SETFL, flags);
216 #elif defined(FIONBIO)
217 (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
219 cu->cu_closeit = TRUE;
221 cu->cu_closeit = FALSE;
223 cu->cu_sock = *sockp;
224 cl->cl_auth = authnone_create();
228 mem_free((void *)cu, sizeof(struct cu_data) + sendsz + recvsz);
230 mem_free((void *)cl, sizeof(CLIENT));
231 return ((CLIENT *)NULL);
236 struct sockaddr_in *raddr,
243 return(clntudp_bufcreate(raddr, program, version, wait, sockp,
244 UDPMSGSIZE, UDPMSGSIZE));
247 static enum clnt_stat
255 struct timeval utimeout)
257 struct cu_data *cu = (struct cu_data *)cl->cl_private;
272 #endif /* def FD_SETSIZE */
273 struct sockaddr_in from;
274 struct rpc_msg reply_msg;
276 struct timeval time_waited;
278 int nrefreshes = 2; /* number of times to refresh cred */
279 struct timeval timeout;
281 if (cu->cu_total.tv_usec == -1) {
282 timeout = utimeout; /* use supplied timeout */
284 timeout = cu->cu_total; /* use default timeout */
287 time_waited.tv_sec = 0;
288 time_waited.tv_usec = 0;
290 xdrs = &(cu->cu_outxdrs);
291 xdrs->x_op = XDR_ENCODE;
292 XDR_SETPOS(xdrs, cu->cu_xdrpos);
294 * the transaction is the first thing in the out buffer
296 (*(uint32_t *)(cu->cu_outbuf))++;
297 if ((! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
298 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
299 (! (*xargs)(xdrs, argsp)))
300 return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
301 outlen = (int)XDR_GETPOS(xdrs);
304 if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
305 (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
307 cu->cu_error.re_errno = errno;
308 return (cu->cu_error.re_status = RPC_CANTSEND);
312 * Hack to provide rpc-based message passing
314 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
315 return (cu->cu_error.re_status = RPC_TIMEDOUT);
318 * sub-optimal code appears here because we have
319 * some clock time to spare while the packets are in flight.
320 * (We assume that this is actually only executed once.)
322 reply_msg.acpted_rply.ar_verf = _null_auth;
323 reply_msg.acpted_rply.ar_results.where = resultsp;
324 reply_msg.acpted_rply.ar_results.proc = xresults;
327 FD_SET(cu->cu_sock, &mask);
329 mask = 1 << cu->cu_sock;
330 #endif /* def FD_SETSIZE */
333 switch (select(_rpc_dtablesize(), &readfds, NULL,
334 NULL, &(cu->cu_wait))) {
337 time_waited.tv_sec += cu->cu_wait.tv_sec;
338 time_waited.tv_usec += cu->cu_wait.tv_usec;
339 while (time_waited.tv_usec >= 1000000) {
340 time_waited.tv_sec++;
341 time_waited.tv_usec -= 1000000;
343 if ((time_waited.tv_sec < timeout.tv_sec) ||
344 ((time_waited.tv_sec == timeout.tv_sec) &&
345 (time_waited.tv_usec < timeout.tv_usec)))
347 return (cu->cu_error.re_status = RPC_TIMEDOUT);
350 * buggy in other cases because time_waited is not being
356 cu->cu_error.re_errno = errno;
357 return (cu->cu_error.re_status = RPC_CANTRECV);
360 fromlen = sizeof(struct sockaddr);
361 inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
362 (int) cu->cu_recvsz, 0,
363 (struct sockaddr *)&from, &fromlen);
364 } while (inlen < 0 && errno == EINTR);
366 if (errno == EWOULDBLOCK)
368 cu->cu_error.re_errno = errno;
369 return (cu->cu_error.re_status = RPC_CANTRECV);
371 if (inlen < sizeof(uint32_t))
373 /* see if reply transaction id matches sent id */
374 if (*((uint32_t *)(cu->cu_inbuf)) != *((uint32_t *)(cu->cu_outbuf)))
376 /* we now assume we have the proper reply */
381 * now decode and validate the response
383 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)inlen, XDR_DECODE);
384 ok = xdr_replymsg(&reply_xdrs, &reply_msg);
385 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
387 _seterr_reply(&reply_msg, &(cu->cu_error));
388 if (cu->cu_error.re_status == RPC_SUCCESS) {
389 if (! AUTH_VALIDATE(cl->cl_auth,
390 &reply_msg.acpted_rply.ar_verf)) {
391 cu->cu_error.re_status = RPC_AUTHERROR;
392 cu->cu_error.re_why = AUTH_INVALIDRESP;
394 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
395 xdrs->x_op = XDR_FREE;
396 (void)xdr_opaque_auth(xdrs,
397 &(reply_msg.acpted_rply.ar_verf));
399 } /* end successful completion */
401 /* maybe our credentials need to be refreshed ... */
402 if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
406 } /* end of unsuccessful completion */
407 } /* end of valid reply message */
409 cu->cu_error.re_status = RPC_CANTDECODERES;
411 return (cu->cu_error.re_status);
417 struct rpc_err *errp)
419 struct cu_data *cu = (struct cu_data *)cl->cl_private;
421 *errp = cu->cu_error;
431 struct cu_data *cu = (struct cu_data *)cl->cl_private;
432 XDR *xdrs = &(cu->cu_outxdrs);
434 xdrs->x_op = XDR_FREE;
435 return ((*xdr_res)(xdrs, res_ptr));
451 struct cu_data *cu = (struct cu_data *)cl->cl_private;
455 cu->cu_total = *(struct timeval *)info;
458 *(struct timeval *)info = cu->cu_total;
460 case CLSET_RETRY_TIMEOUT:
461 cu->cu_wait = *(struct timeval *)info;
463 case CLGET_RETRY_TIMEOUT:
464 *(struct timeval *)info = cu->cu_wait;
466 case CLGET_SERVER_ADDR:
467 *(struct sockaddr_in *)info = cu->cu_raddr;
479 struct cu_data *cu = (struct cu_data *)cl->cl_private;
481 if (cu->cu_closeit) {
482 (void)close(cu->cu_sock);
484 XDR_DESTROY(&(cu->cu_outxdrs));
485 mem_free((void *)cu, (sizeof(struct cu_data) + cu->cu_sendsz + cu->cu_recvsz));
486 mem_free((void *)cl, sizeof(CLIENT));