int getrpcport (const char *host, u_long prognum, u_long versnum, u_int proto) { struct sockaddr_in addr; struct hostent hostbuf, *hp; size_t buflen; char *buffer; int herr; buflen = 1024; buffer = __alloca (buflen); while (__gethostbyname_r (host, &hostbuf, buffer, buflen, &hp, &herr) != 0 || hp == NULL) if (herr != NETDB_INTERNAL || errno != ERANGE) return 0; else { /* Enlarge the buffer. */ buflen *= 2; buffer = __alloca (buflen); } memcpy ((char *) &addr.sin_addr, hp->h_addr, hp->h_length); addr.sin_family = AF_INET; addr.sin_port = 0; return pmap_getport (&addr, prognum, versnum, proto); }
/* * 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; }
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; }