CLIENT * clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct; struct rpc_msg call_msg; h = (CLIENT *) mem_alloc (sizeof (*h)); ct = (struct ct_data *) mem_alloc (sizeof (*ct)); if (h == NULL || ct == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clnttcp_create: out of memory\n")); else #endif (void) fputs (_("clnttcp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } /* * If no port number given ask the pmap for one */ if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0) { mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); } raddr->sin_port = htons (port); } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); (void) bindresvport (*sockp, (struct sockaddr_in *) 0); if ((*sockp < 0) || (connect (*sockp, (struct sockaddr *) raddr, sizeof (*raddr)) < 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; if (*sockp >= 0) (void) close (*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void) close (*sockp); } goto fooy; } ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs)); XDR_DESTROY (&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz, (caddr_t) ct, readtcp, writetcp); h->cl_ops = &tcp_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create (); return h; fooy: /* * Something goofed, free stuff and barf */ mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); }
/* libc_hidden_proto(clntudp_bufcreate) */ CLIENT * clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clntudp_create: out of memory\n")); else #endif (void) fputs (_("clntudp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { int dontblock = 1; *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); /* the sockets rpc controls are non-blocking */ (void) ioctl (*sockp, FIONBIO, (char *) &dontblock); #ifdef IP_RECVERR { int on = 1; setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmission occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT * __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz, int flags) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", "clntudp_create", _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = (struct clnt_ops *) &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { #ifdef SOCK_NONBLOCK # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec >= 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags, IPPROTO_UDP); # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec == 0) __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1; # endif } #endif #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); # ifdef SOCK_CLOEXEC if (flags & SOCK_CLOEXEC) __fcntl (*sockp, F_SETFD, FD_CLOEXEC); # endif } #endif if (__builtin_expect (*sockp < 0, 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { /* the sockets rpc controls are non-blocking */ int dontblock = 1; (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock); } #endif #ifdef IP_RECVERR { int on = 1; __setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
/* * Create a client handle for a tcp/ip connection. * If *sockp<0, *sockp is set to a newly created TCP socket and it is * connected to raddr. If *sockp non-negative then * raddr is ignored. The rpc/tcp package does buffering * similar to stdio, so the client must pick send and receive buffer sizes,]; * 0 => use the default. * If raddr->sin_port is 0, then a binder on the remote machine is * consulted for the right port number. * NB: *sockp is copied into a private area. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this * something more useful. */ CLIENT * clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct)); struct rpc_msg call_msg; int len; h = (CLIENT *) mem_alloc (sizeof (*h)); if (h == NULL || ct == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = __socket (AF_UNIX, SOCK_STREAM, 0); len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1; if (*sockp < 0 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; if (*sockp != -1) __close (*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) __close (*sockp); goto fooy; } ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs)); XDR_DESTROY (&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz, (caddr_t) ct, readunix, writeunix); h->cl_ops = (struct clnt_ops *) &unix_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create (); return h; fooy: /* * Something goofed, free stuff and barf */ mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return (CLIENT *) NULL; }
enum clnt_stat clnt_broadcast ( u_long prog, /* program number */ u_long vers, /* version number */ u_long proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ caddr_t argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ caddr_t resultsp, /* pointer to results */ resultproc_t eachresult /* call with each result obtained */) { enum clnt_stat stat = RPC_FAILED; AUTH *unix_auth = authunix_create_default (); XDR xdr_stream; XDR *xdrs = &xdr_stream; struct timeval t; int outlen, inlen, nets; socklen_t fromlen; int sock; int on = 1; struct pollfd fd; int milliseconds; int i; bool_t done = FALSE; u_long xid; u_long port; struct in_addr addrs[20]; struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ struct rmtcallargs a; struct rmtcallres r; struct rpc_msg msg; char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; /* * initialization: create a socket, a broadcast address, and * preserialize the arguments into a send buffer. */ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror (_("Cannot create socket for broadcast rpc")); stat = RPC_CANTSEND; goto done_broad; } #ifdef SO_BROADCAST if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { perror (_("Cannot set socket option SO_BROADCAST")); stat = RPC_CANTSEND; goto done_broad; } #endif /* def SO_BROADCAST */ fd.fd = sock; fd.events = POLLIN; nets = getbroadcastnets (addrs, sock, inbuf); memset ((char *) &baddr, 0, sizeof (baddr)); baddr.sin_family = AF_INET; baddr.sin_port = htons (PMAPPORT); baddr.sin_addr.s_addr = htonl (INADDR_ANY); /* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ msg.rm_xid = xid = _create_xid (); t.tv_usec = 0; msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; msg.rm_call.cb_prog = PMAPPROG; msg.rm_call.cb_vers = PMAPVERS; msg.rm_call.cb_proc = PMAPPROC_CALLIT; msg.rm_call.cb_cred = unix_auth->ah_cred; msg.rm_call.cb_verf = unix_auth->ah_verf; a.prog = prog; a.vers = vers; a.proc = proc; a.xdr_args = xargs; a.args_ptr = argsp; r.port_ptr = &port; r.xdr_results = xresults; r.results_ptr = resultsp; xdrmem_create (xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); if ((!xdr_callmsg (xdrs, &msg)) || (!xdr_rmtcall_args (xdrs, &a))) { stat = RPC_CANTENCODEARGS; goto done_broad; } outlen = (int) xdr_getpos (xdrs); xdr_destroy (xdrs); /* * Basic loop: broadcast a packet and wait a while for response(s). * The response timeout grows larger per iteration. */ for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { for (i = 0; i < nets; i++) { baddr.sin_addr = addrs[i]; if (sendto (sock, outbuf, outlen, 0, (struct sockaddr *) &baddr, sizeof (struct sockaddr)) != outlen) { perror (_("Cannot send broadcast packet")); stat = RPC_CANTSEND; goto done_broad; } } if (eachresult == NULL) { stat = RPC_SUCCESS; goto done_broad; } recv_again: msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = (caddr_t) & r; msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_rmtcallres; milliseconds = t.tv_sec * 1000 + t.tv_usec / 1000; switch (poll(&fd, 1, milliseconds)) { case 0: /* timed out */ stat = RPC_TIMEDOUT; continue; case -1: /* some kind of error */ if (errno == EINTR) goto recv_again; perror (_("Broadcast poll problem")); stat = RPC_CANTRECV; goto done_broad; } /* end of poll results switch */ try_again: fromlen = sizeof (struct sockaddr); inlen = recvfrom (sock, inbuf, UDPMSGSIZE, 0, (struct sockaddr *) &raddr, &fromlen); if (inlen < 0) { if (errno == EINTR) goto try_again; perror (_("Cannot receive reply to broadcast")); stat = RPC_CANTRECV; goto done_broad; } if ((size_t) inlen < sizeof (u_long)) goto recv_again; /* * see if reply transaction id matches sent id. * If so, decode the results. */ xdrmem_create (xdrs, inbuf, (u_int) inlen, XDR_DECODE); if (xdr_replymsg (xdrs, &msg)) { if (((u_int32_t) msg.rm_xid == (u_int32_t) xid) && (msg.rm_reply.rp_stat == MSG_ACCEPTED) && (msg.acpted_rply.ar_stat == SUCCESS)) { raddr.sin_port = htons ((u_short) port); done = (*eachresult) (resultsp, &raddr); } /* otherwise, we just ignore the errors ... */ } else { #ifdef notdef /* some kind of deserialization problem ... */ if ((u_int32_t) msg.rm_xid == (u_int32_t) xid) fprintf (stderr, "Broadcast deserialization problem"); /* otherwise, just random garbage */ #endif } xdrs->x_op = XDR_FREE; msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; (void) xdr_replymsg (xdrs, &msg); (void) (*xresults) (xdrs, resultsp); xdr_destroy (xdrs); if (done) { stat = RPC_SUCCESS; goto done_broad; } else { goto recv_again; } } done_broad: (void) close (sock); AUTH_DESTROY (unix_auth); return stat; }