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_tcp.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_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
46 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
48 * Copyright (C) 1984, Sun Microsystems, Inc.
50 * TCP based RPC supports 'batched calls'.
51 * A sequence of calls may be batched-up in a send buffer. The rpc call
52 * return immediately to the client even though the call was not necessarily
53 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
54 * the rpc timeout value is zero (see clnt.h, rpc).
56 * Clients should NOT casually batch calls that in fact return results; that is,
57 * the server side should be aware that a call is batched and not produce any
58 * return message. Batched calls that produce many result messages can
59 * deadlock (netlock) the client and the server....
61 * Now go hang yourself.
68 #include <rpc/pmap_clnt.h>
70 #include <sys/socket.h>
73 #include <rpc/pmap_clnt.h>
76 #define MCALL_MSG_SIZE 24
83 static int writetcp();
85 static enum clnt_stat clnttcp_call();
86 static void clnttcp_abort();
87 static void clnttcp_geterr();
88 static bool_t clnttcp_freeres();
89 static bool_t clnttcp_control();
90 static void clnttcp_destroy();
92 static struct clnt_ops tcp_ops = {
104 struct timeval ct_wait;
105 bool_t ct_waitset; /* wait set by clnt_control? */
106 struct sockaddr_in ct_addr;
107 struct rpc_err ct_error;
108 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
109 u_int ct_mpos; /* pos after marshal */
114 * Create a client handle for a tcp/ip connection.
115 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
116 * connected to raddr. If *sockp non-negative then
117 * raddr is ignored. The rpc/tcp package does buffering
118 * similar to stdio, so the client must pick send and receive buffer sizes,];
119 * 0 => use the default.
120 * If raddr->sin_port is 0, then a binder on the remote machine is
121 * consulted for the right port number.
122 * NB: *sockp is copied into a private area.
123 * NB: It is the clients responsibility to close *sockp.
124 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
125 * something more useful.
128 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
129 struct sockaddr_in *raddr;
137 register struct ct_data *ct;
139 struct rpc_msg call_msg;
141 h = (CLIENT *)mem_alloc(sizeof(*h));
144 nt_rpc_report("clnttcp_create: out of memory\n");
145 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
146 rpc_createerr.cf_error.re_errno = ENOMEM;
148 (void)fprintf(stderr, "clnttcp_create: out of memory\n");
149 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
150 rpc_createerr.cf_error.re_errno = errno;
154 ct = (struct ct_data *)mem_alloc(sizeof(*ct));
157 nt_rpc_report("clnttcp_create: out of memory\n");
158 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
159 rpc_createerr.cf_error.re_errno = ENOMEM;
161 (void)fprintf(stderr, "clnttcp_create: out of memory\n");
162 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
163 rpc_createerr.cf_error.re_errno = errno;
169 * If no port number given ask the pmap for one
171 if (raddr->sin_port == 0) {
173 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
174 mem_free((caddr_t)ct, sizeof(struct ct_data));
175 mem_free((caddr_t)h, sizeof(CLIENT));
176 return ((CLIENT *)NULL);
178 raddr->sin_port = htons(port);
182 * If no socket given, open one
185 if (*sockp == INVALID_SOCKET) {
186 struct linger slinger;
188 *sockp = socket(AF_INET, SOCK_STREAM, 0);
189 bindresvport(*sockp, (struct sockaddr_in *)0);
192 slinger.l_linger = 0;
193 setsockopt(*sockp, SOL_SOCKET, SO_LINGER, &slinger, sizeof(struct linger));
195 if ((*sockp == INVALID_SOCKET)
196 || (connect(*sockp, (struct sockaddr *)raddr,
197 sizeof(*raddr)) < 0)) {
198 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
199 rpc_createerr.cf_error.re_errno = WSAerrno;
200 (void)closesocket(*sockp);
203 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
204 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
206 || (connect(*sockp, (struct sockaddr *)raddr,
207 sizeof(*raddr)) < 0)) {
208 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
209 rpc_createerr.cf_error.re_errno = errno;
214 ct->ct_closeit = TRUE;
216 ct->ct_closeit = FALSE;
220 * Set up private data struct
222 ct->ct_sock = *sockp;
223 ct->ct_wait.tv_usec = 0;
224 ct->ct_waitset = FALSE;
225 ct->ct_addr = *raddr;
228 * Initialize call message
230 (void)gettimeofday(&now, (struct timezone *)0);
231 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
232 call_msg.rm_direction = CALL;
233 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
234 call_msg.rm_call.cb_prog = prog;
235 call_msg.rm_call.cb_vers = vers;
238 * pre-serialize the staic part of the call msg and stash it away
240 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
242 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
243 if (ct->ct_closeit) {
245 (void)closesocket(*sockp);
252 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
253 XDR_DESTROY(&(ct->ct_xdrs));
256 * Create a client handle which uses xdrrec for serialization
257 * and authnone for authentication.
259 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
260 (caddr_t)ct, readtcp, writetcp);
261 h->cl_ops = &tcp_ops;
262 h->cl_private = (caddr_t) ct;
263 h->cl_auth = authnone_create();
268 * Something goofed, free stuff and barf
270 mem_free((caddr_t)ct, sizeof(struct ct_data));
271 mem_free((caddr_t)h, sizeof(CLIENT));
272 return ((CLIENT *)NULL);
275 static enum clnt_stat
276 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
281 xdrproc_t xdr_results;
283 struct timeval timeout;
285 register struct ct_data *ct = (struct ct_data *) h->cl_private;
286 register XDR *xdrs = &(ct->ct_xdrs);
287 struct rpc_msg reply_msg;
289 u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */
290 register bool_t shipnow;
293 if (!ct->ct_waitset) {
294 ct->ct_wait = timeout;
298 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
299 && timeout.tv_usec == 0) ? FALSE : TRUE;
302 xdrs->x_op = XDR_ENCODE;
303 ct->ct_error.re_status = RPC_SUCCESS;
304 x_id = ntohl(--(*msg_x_id));
305 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
306 (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
307 (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
308 (! (*xdr_args)(xdrs, args_ptr))) {
309 if (ct->ct_error.re_status == RPC_SUCCESS)
310 ct->ct_error.re_status = RPC_CANTENCODEARGS;
311 (void)xdrrec_endofrecord(xdrs, TRUE);
312 return (ct->ct_error.re_status);
314 if (! xdrrec_endofrecord(xdrs, shipnow))
315 return (ct->ct_error.re_status = RPC_CANTSEND);
317 return (RPC_SUCCESS);
319 * Hack to provide rpc-based message passing
321 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
322 return(ct->ct_error.re_status = RPC_TIMEDOUT);
327 * Keep receiving until we get a valid transaction id
329 xdrs->x_op = XDR_DECODE;
331 reply_msg.acpted_rply.ar_verf = _null_auth;
332 reply_msg.acpted_rply.ar_results.where = NULL;
333 reply_msg.acpted_rply.ar_results.proc = xdr_void;
334 if (! xdrrec_skiprecord(xdrs))
335 return (ct->ct_error.re_status);
336 /* now decode and validate the response header */
337 if (! xdr_replymsg(xdrs, &reply_msg)) {
338 if (ct->ct_error.re_status == RPC_SUCCESS)
340 return (ct->ct_error.re_status);
342 if (reply_msg.rm_xid == x_id)
349 _seterr_reply(&reply_msg, &(ct->ct_error));
350 if (ct->ct_error.re_status == RPC_SUCCESS) {
351 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
352 ct->ct_error.re_status = RPC_AUTHERROR;
353 ct->ct_error.re_why = AUTH_INVALIDRESP;
354 } else if (! (*xdr_results)(xdrs, results_ptr)) {
355 if (ct->ct_error.re_status == RPC_SUCCESS)
356 ct->ct_error.re_status = RPC_CANTDECODERES;
358 /* free verifier ... */
359 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
360 xdrs->x_op = XDR_FREE;
361 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
363 } /* end successful completion */
365 /* maybe our credentials need to be refreshed ... */
366 if (refreshes-- && AUTH_REFRESH(h->cl_auth))
368 } /* end of unsuccessful completion */
369 return (ct->ct_error.re_status);
373 clnttcp_geterr(h, errp)
375 struct rpc_err *errp;
377 register struct ct_data *ct =
378 (struct ct_data *) h->cl_private;
380 *errp = ct->ct_error;
384 clnttcp_freeres(cl, xdr_res, res_ptr)
389 register struct ct_data *ct = (struct ct_data *)cl->cl_private;
390 register XDR *xdrs = &(ct->ct_xdrs);
392 xdrs->x_op = XDR_FREE;
393 return ((*xdr_res)(xdrs, res_ptr));
402 clnttcp_control(cl, request, info)
407 register struct ct_data *ct = (struct ct_data *)cl->cl_private;
411 ct->ct_wait = *(struct timeval *)info;
412 ct->ct_waitset = TRUE;
415 *(struct timeval *)info = ct->ct_wait;
417 case CLGET_SERVER_ADDR:
418 *(struct sockaddr_in *)info = ct->ct_addr;
431 register struct ct_data *ct =
432 (struct ct_data *) h->cl_private;
434 if (ct->ct_closeit) {
436 (void)closesocket(ct->ct_sock);
438 (void)close(ct->ct_sock);
441 XDR_DESTROY(&(ct->ct_xdrs));
442 mem_free((caddr_t)ct, sizeof(struct ct_data));
443 mem_free((caddr_t)h, sizeof(CLIENT));
447 * Interface between xdr serializer and tcp connection.
448 * Behaves like the system calls, read & write, but keeps some error state
449 * around for the rpc level.
452 readtcp(ct, buf, len)
453 register struct ct_data *ct;
464 FD_SET(ct->ct_sock, &mask);
466 register int mask = 1 << (ct->ct_sock);
472 #endif /* def FD_SETSIZE */
476 switch (select(0 /* unused in winsock */, &readfds, (int*)NULL, (int*)NULL,
479 ct->ct_error.re_status = RPC_TIMEDOUT;
483 if (WSAerrno == EINTR)
485 ct->ct_error.re_status = RPC_CANTRECV;
486 ct->ct_error.re_errno = WSAerrno;
491 switch (len = recv(ct->ct_sock, buf, len, 0)) {
495 ct->ct_error.re_errno = WSAECONNRESET;
496 ct->ct_error.re_status = RPC_CANTRECV;
497 len = -1; /* it's really an error */
501 ct->ct_error.re_errno = WSAerrno;
502 ct->ct_error.re_status = RPC_CANTRECV;
507 switch (select(FD_SETSIZE, &readfds, NULL, NULL,
510 ct->ct_error.re_status = RPC_TIMEDOUT;
516 ct->ct_error.re_status = RPC_CANTRECV;
517 ct->ct_error.re_errno = errno;
522 switch (len = read(ct->ct_sock, buf, len)) {
526 ct->ct_error.re_errno = ECONNRESET;
527 ct->ct_error.re_status = RPC_CANTRECV;
528 len = -1; /* it's really an error */
532 ct->ct_error.re_errno = errno;
533 ct->ct_error.re_status = RPC_CANTRECV;
541 writetcp(ct, buf, len)
548 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
550 if ((i = send(ct->ct_sock, buf, cnt, 0)) == -1) {
551 ct->ct_error.re_errno = WSAerrno;
553 if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
554 ct->ct_error.re_errno = errno;
556 ct->ct_error.re_status = RPC_CANTSEND;