1 /*********************************************************************
2 * RPC for the Windows NT Operating System
3 * 1993 by Martin F. Gergeleit
4 * Users may use, copy or modify Sun RPC for the Windows NT Operating
5 * System according to the Sun copyright below.
7 * RPC for the Windows NT Operating System COMES WITH ABSOLUTELY NO
8 * WARRANTY, NOR WILL I BE LIABLE FOR ANY DAMAGES INCURRED FROM THE
9 * USE OF. USE ENTIRELY AT YOUR OWN RISK!!!
10 *********************************************************************/
12 /* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */
14 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
15 * unrestricted use provided that this legend is included on all tape
16 * media and as a part of the software program in whole or part. Users
17 * may copy or modify Sun RPC without charge, but are not authorized
18 * to license or distribute it to anyone else except as part of a product or
19 * program developed by the user.
21 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
22 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
25 * Sun RPC is provided with no support and without any obligation on the
26 * part of Sun Microsystems, Inc. to assist in its use, correction,
27 * modification or enhancement.
29 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
30 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
31 * OR ANY PART THEREOF.
33 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
34 * or profits or other special, indirect and consequential damages, even if
35 * Sun has been advised of the possibility of such damages.
37 * Sun Microsystems, Inc.
39 * Mountain View, California 94043
41 #if !defined(lint) && defined(SCCSIDS)
42 static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
46 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
48 * Copyright (C) 1984, Sun Microsystems, Inc.
55 #include <rpc/pmap_clnt.h>
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
61 #include <rpc/pmap_clnt.h>
64 #include <sys/filio.h>
71 * UDP bases client side rpc operations
73 static enum clnt_stat clntudp_call();
74 static void clntudp_abort();
75 static void clntudp_geterr();
76 static bool_t clntudp_freeres();
77 static bool_t clntudp_control();
78 static void clntudp_destroy();
80 static struct clnt_ops udp_ops = {
90 * Private data kept per client handle
95 struct sockaddr_in cu_raddr;
97 struct timeval cu_wait;
98 struct timeval cu_total;
99 struct rpc_err cu_error;
109 * Create a UDP based client handle.
110 * If *sockp<0, *sockp is set to a newly created UPD socket.
111 * If raddr->sin_port is 0 a binder on the remote machine
112 * is consulted for the correct port number.
113 * NB: It is the clients responsibility to close *sockp.
114 * NB: The rpch->cl_auth is initialized to null authentication.
115 * Caller may wish to set this something more useful.
117 * wait is the amount of time used between retransmitting a call if
118 * no response has been heard; retransmition occurs until the actual
119 * rpc call times out.
121 * sendsz and recvsz are the maximum allowable packet sizes that can be
125 clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
126 struct sockaddr_in *raddr;
135 register struct cu_data *cu;
137 struct rpc_msg call_msg;
139 cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
142 nt_rpc_report("clntudp_create: out of memory\n");
143 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
144 rpc_createerr.cf_error.re_errno = ENOMEM;
146 (void) fprintf(stderr, "clntudp_create: out of memory\n");
147 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
148 rpc_createerr.cf_error.re_errno = errno;
152 sendsz = ((sendsz + 3) / 4) * 4;
153 recvsz = ((recvsz + 3) / 4) * 4;
154 cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
157 nt_rpc_report("clntudp_create: out of memory\n");
158 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
159 rpc_createerr.cf_error.re_errno = ENOMEM;
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;
167 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
169 (void)gettimeofday(&now, (struct timezone *)0);
170 if (raddr->sin_port == 0) {
173 pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
176 raddr->sin_port = htons(port);
178 cl->cl_ops = &udp_ops;
179 cl->cl_private = (caddr_t)cu;
180 cu->cu_raddr = *raddr;
181 cu->cu_rlen = sizeof (cu->cu_raddr);
183 cu->cu_total.tv_sec = -1;
184 cu->cu_total.tv_usec = -1;
185 cu->cu_sendsz = sendsz;
186 cu->cu_recvsz = recvsz;
187 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
188 call_msg.rm_direction = CALL;
189 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
190 call_msg.rm_call.cb_prog = program;
191 call_msg.rm_call.cb_vers = version;
192 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
194 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
197 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
201 *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
203 if (*sockp == INVALID_SOCKET) {
204 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
205 rpc_createerr.cf_error.re_errno = WSAerrno;
208 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
209 rpc_createerr.cf_error.re_errno = errno;
213 /* attempt to bind to prov port */
214 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
215 /* the sockets rpc controls are non-blocking */
217 (void)ioctlsocket(*sockp, FIONBIO, (char *) &dontblock);
219 (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
221 cu->cu_closeit = TRUE;
223 cu->cu_closeit = FALSE;
225 cu->cu_sock = *sockp;
226 cl->cl_auth = authnone_create();
230 mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
232 mem_free((caddr_t)cl, sizeof(CLIENT));
233 return ((CLIENT *)NULL);
237 clntudp_create(raddr, program, version, wait, sockp)
238 struct sockaddr_in *raddr;
245 return(clntudp_bufcreate(raddr, program, version, wait, sockp,
246 UDPMSGSIZE, UDPMSGSIZE));
249 static enum clnt_stat
250 clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
251 register CLIENT *cl; /* client handle */
252 u_long proc; /* procedure number */
253 xdrproc_t xargs; /* xdr routine for args */
254 caddr_t argsp; /* pointer to args */
255 xdrproc_t xresults; /* xdr routine for results */
256 caddr_t resultsp; /* pointer to results */
257 struct timeval utimeout; /* seconds to wait before giving up */
259 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
270 #endif /* def FD_SETSIZE */
271 struct sockaddr_in from;
272 struct rpc_msg reply_msg;
274 struct timeval time_waited;
276 int nrefreshes = 2; /* number of times to refresh cred */
277 struct timeval timeout;
279 if (cu->cu_total.tv_usec == -1) {
280 timeout = utimeout; /* use supplied timeout */
282 timeout = cu->cu_total; /* use default timeout */
285 time_waited.tv_sec = 0;
286 time_waited.tv_usec = 0;
288 xdrs = &(cu->cu_outxdrs);
289 xdrs->x_op = XDR_ENCODE;
290 XDR_SETPOS(xdrs, cu->cu_xdrpos);
292 * the transaction is the first thing in the out buffer
294 (*(u_short *)(cu->cu_outbuf))++;
296 if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
297 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
298 (! (*xargs)(xdrs, argsp)))
299 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)
308 cu->cu_error.re_errno = WSAerrno;
310 cu->cu_error.re_errno = errno;
312 return (cu->cu_error.re_status = RPC_CANTSEND);
316 * Hack to provide rpc-based message passing
318 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
319 return (cu->cu_error.re_status = RPC_TIMEDOUT);
322 * sub-optimal code appears here because we have
323 * some clock time to spare while the packets are in flight.
324 * (We assume that this is actually only executed once.)
326 reply_msg.acpted_rply.ar_verf = _null_auth;
327 reply_msg.acpted_rply.ar_results.where = resultsp;
328 reply_msg.acpted_rply.ar_results.proc = xresults;
331 FD_SET(cu->cu_sock, &mask);
333 mask = 1 << cu->cu_sock;
334 #endif /* def FD_SETSIZE */
338 switch (select(0 /* unused in winsock */, &readfds, (int *)NULL, (int *)NULL,
340 switch (select(FD_SETSIZE, &readfds, NULL, NULL,
345 time_waited.tv_sec += cu->cu_wait.tv_sec;
346 time_waited.tv_usec += cu->cu_wait.tv_usec;
347 while (time_waited.tv_usec >= 1000000) {
348 time_waited.tv_sec++;
349 time_waited.tv_usec -= 1000000;
351 if ((time_waited.tv_sec < timeout.tv_sec) ||
352 ((time_waited.tv_sec == timeout.tv_sec) &&
353 (time_waited.tv_usec < timeout.tv_usec)))
355 return (cu->cu_error.re_status = RPC_TIMEDOUT);
358 * buggy in other cases because time_waited is not being
363 if (WSAerrno == WSAEINTR)
365 cu->cu_error.re_errno = WSAerrno;
369 cu->cu_error.re_errno = errno;
371 return (cu->cu_error.re_status = RPC_CANTRECV);
374 fromlen = sizeof(struct sockaddr);
375 inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
376 (int) cu->cu_recvsz, 0,
377 (struct sockaddr *)&from, &fromlen);
379 } while (inlen < 0 && WSAerrno == EINTR);
381 if (WSAerrno == WSAEWOULDBLOCK)
383 cu->cu_error.re_errno = WSAerrno;
385 } while (inlen < 0 && errno == EINTR);
387 if (errno == EWOULDBLOCK)
389 cu->cu_error.re_errno = errno;
391 return (cu->cu_error.re_status = RPC_CANTRECV);
393 if (inlen < sizeof(u_long))
395 /* see if reply transaction id matches sent id */
396 if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
398 /* we now assume we have the proper reply */
403 * now decode and validate the response
405 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
406 ok = xdr_replymsg(&reply_xdrs, &reply_msg);
407 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
409 _seterr_reply(&reply_msg, &(cu->cu_error));
410 if (cu->cu_error.re_status == RPC_SUCCESS) {
411 if (! AUTH_VALIDATE(cl->cl_auth,
412 &reply_msg.acpted_rply.ar_verf)) {
413 cu->cu_error.re_status = RPC_AUTHERROR;
414 cu->cu_error.re_why = AUTH_INVALIDRESP;
416 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
417 xdrs->x_op = XDR_FREE;
418 (void)xdr_opaque_auth(xdrs,
419 &(reply_msg.acpted_rply.ar_verf));
421 } /* end successful completion */
423 /* maybe our credentials need to be refreshed ... */
424 if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
428 } /* end of unsuccessful completion */
429 } /* end of valid reply message */
431 cu->cu_error.re_status = RPC_CANTDECODERES;
433 return (cu->cu_error.re_status);
437 clntudp_geterr(cl, errp)
439 struct rpc_err *errp;
441 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
443 *errp = cu->cu_error;
448 clntudp_freeres(cl, xdr_res, res_ptr)
453 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
454 register XDR *xdrs = &(cu->cu_outxdrs);
456 xdrs->x_op = XDR_FREE;
457 return ((*xdr_res)(xdrs, res_ptr));
467 clntudp_control(cl, request, info)
472 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
476 cu->cu_total = *(struct timeval *)info;
479 *(struct timeval *)info = cu->cu_total;
481 case CLSET_RETRY_TIMEOUT:
482 cu->cu_wait = *(struct timeval *)info;
484 case CLGET_RETRY_TIMEOUT:
485 *(struct timeval *)info = cu->cu_wait;
487 case CLGET_SERVER_ADDR:
488 *(struct sockaddr_in *)info = cu->cu_raddr;
500 register struct cu_data *cu = (struct cu_data *)cl->cl_private;
502 if (cu->cu_closeit) {
504 (void)closesocket(cu->cu_sock);
506 (void)close(cu->cu_sock);
509 XDR_DESTROY(&(cu->cu_outxdrs));
510 mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
511 mem_free((caddr_t)cl, sizeof(CLIENT));