char * clnt_spcreateerror (const char *msg) { char chrbuf[1024]; char *str = _buf (); char *cp; int len; struct rpc_createerr *ce; if (str == NULL) return NULL; ce = &get_rpc_createerr (); len = sprintf (str, "%s: ", msg); cp = str + len; cp = stpcpy (cp, clnt_sperrno (ce->cf_stat)); switch (ce->cf_stat) { case RPC_PMAPFAILURE: cp = stpcpy (stpcpy (cp, " - "), clnt_sperrno (ce->cf_error.re_status)); break; case RPC_SYSTEMERROR: cp = stpcpy (stpcpy (cp, " - "), __strerror_r (ce->cf_error.re_errno, chrbuf, sizeof chrbuf)); break; default: break; } *cp = '\n'; *++cp = '\0'; return str; }
/* * Generic client creation: takes (hostname, program-number, protocol) and * returns client handle. Default options are set, which the user can * change using the rpc equivalent of ioctl()'s. */ CLIENT *clnt_pci_create(const char *hostname, u_long prog, u_long vers, const char *proto) { CLIENT *client; struct sockaddr_nl src_addr, dest_addr; int sock_fd; sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_RPC_PCI_CLNT); if (sock_fd < 0) goto err; memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); /* self pid */ bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; /* For Linux Kernel */ dest_addr.nl_groups = 0; /* unicast */ client = _clnt_pci_create(sock_fd, &src_addr, &dest_addr, prog, vers); if (client == NULL) close(sock_fd); return client; err: #if 0 if (errno) { struct rpc_createerr *ce = &get_rpc_createerr(); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = error; return NULL; } #endif return NULL; }
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); }
int callrpc (const char *host, u_long prognum, u_long versnum, u_long procnum, xdrproc_t inproc, const char *in, xdrproc_t outproc, char *out) { struct callrpc_private_s *crp = callrpc_private; struct sockaddr_in server_addr; enum clnt_stat clnt_stat; struct hostent hostbuf, *hp; struct timeval timeout, tottimeout; if (crp == 0) { crp = (struct callrpc_private_s *) calloc (1, sizeof (*crp)); if (crp == 0) return 0; callrpc_private = crp; } if (crp->oldhost == NULL) { crp->oldhost = malloc (256); crp->oldhost[0] = 0; crp->socket = RPC_ANYSOCK; } if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum && strcmp (crp->oldhost, host) == 0) { /* reuse old client */ } else { size_t buflen; char *buffer; int herr; crp->valid = 0; if (crp->socket != RPC_ANYSOCK) { (void) close (crp->socket); crp->socket = RPC_ANYSOCK; } if (crp->client) { clnt_destroy (crp->client); crp->client = NULL; } buflen = 1024; buffer = alloca (buflen); while (gethostbyname_r (host, &hostbuf, buffer, buflen, &hp, &herr) != 0 || hp == NULL) if (herr != NETDB_INTERNAL || errno != ERANGE) return (int) RPC_UNKNOWNHOST; else { /* Enlarge the buffer. */ buflen *= 2; buffer = alloca (buflen); } timeout.tv_usec = 0; timeout.tv_sec = 5; memcpy ((char *) &server_addr.sin_addr, hp->h_addr, hp->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = 0; if ((crp->client = clntudp_create (&server_addr, (u_long) prognum, (u_long) versnum, timeout, &crp->socket)) == NULL) return (int) get_rpc_createerr().cf_stat; crp->valid = 1; crp->oldprognum = prognum; crp->oldversnum = versnum; (void) strncpy (crp->oldhost, host, 255); crp->oldhost[255] = '\0'; } tottimeout.tv_sec = 25; tottimeout.tv_usec = 0; clnt_stat = clnt_call (crp->client, procnum, inproc, (char *) in, outproc, out, tottimeout); /* * if call failed, empty cache */ if (clnt_stat != RPC_SUCCESS) crp->valid = 0; return (int) clnt_stat; }
/* 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 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; }
/* * 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; }
/* * Generic client creation: takes (hostname, program-number, protocol) and * returns client handle. Default options are set, which the user can * change using the rpc equivalent of ioctl()'s. */ CLIENT * clnt_create (const char *hostname, u_long prog, u_long vers, const char *proto) { struct hostent hostbuf, *h; size_t hstbuflen; char *hsttmpbuf; struct protoent protobuf, *p; size_t prtbuflen; char *prttmpbuf; struct sockaddr_in sin; struct sockaddr_un sun; int sock; struct timeval tv; CLIENT *client; int herr; if (strcmp (proto, "unix") == 0) { __bzero ((char *)&sun, sizeof (sun)); sun.sun_family = AF_UNIX; strcpy (sun.sun_path, hostname); sock = RPC_ANYSOCK; client = INTUSE(clntunix_create) (&sun, prog, vers, &sock, 0, 0); if (client == NULL) return NULL; #if 0 /* This is not wanted. This would disable the user from having a timeout in the clnt_call() call. Only a call to cnlt_control() by the user should set the timeout value. */ tv.tv_sec = 25; tv.tv_usec = 0; clnt_control (client, CLSET_TIMEOUT, (char *)&tv); #endif return client; } hstbuflen = 1024; hsttmpbuf = __alloca (hstbuflen); while (__gethostbyname_r (hostname, &hostbuf, hsttmpbuf, hstbuflen, &h, &herr) != 0 || h == NULL) if (herr != NETDB_INTERNAL || errno != ERANGE) { get_rpc_createerr().cf_stat = RPC_UNKNOWNHOST; return NULL; } else { /* Enlarge the buffer. */ hstbuflen *= 2; hsttmpbuf = __alloca (hstbuflen); } if (h->h_addrtype != AF_INET) { /* * Only support INET for now */ struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = EAFNOSUPPORT; return NULL; } sin.sin_family = h->h_addrtype; sin.sin_port = 0; __bzero (sin.sin_zero, sizeof (sin.sin_zero)); memcpy ((char *) &sin.sin_addr, h->h_addr, h->h_length); prtbuflen = 1024; prttmpbuf = __alloca (prtbuflen); while (__getprotobyname_r (proto, &protobuf, prttmpbuf, prtbuflen, &p) != 0 || p == NULL) if (errno != ERANGE) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_UNKNOWNPROTO; ce->cf_error.re_errno = EPFNOSUPPORT; return NULL; } else { /* Enlarge the buffer. */ prtbuflen *= 2; prttmpbuf = __alloca (prtbuflen); } sock = RPC_ANYSOCK; switch (p->p_proto) { case IPPROTO_UDP: tv.tv_sec = 5; tv.tv_usec = 0; client = INTUSE(clntudp_create) (&sin, prog, vers, tv, &sock); if (client == NULL) { return NULL; } #if 0 /* This is not wanted. This would disable the user from having a timeout in the clnt_call() call. Only a call to cnlt_control() by the user should set the timeout value. */ tv.tv_sec = 25; clnt_control (client, CLSET_TIMEOUT, (char *)&tv); #endif break; case IPPROTO_TCP: client = INTUSE(clnttcp_create) (&sin, prog, vers, &sock, 0, 0); if (client == NULL) { return NULL; } #if 0 /* This is not wanted. This would disable the user from having a timeout in the clnt_call() call. Only a call to cnlt_control() by the user should set the timeout value. */ tv.tv_sec = 25; tv.tv_usec = 0; clnt_control (client, CLSET_TIMEOUT, (char *)&tv); #endif break; default: { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = EPFNOSUPPORT; } return (NULL); } return client; }