/*
 * 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)
    {
      memset ((char *)&sun, 0, sizeof (sun));
      sun.sun_family = AF_UNIX;
      strcpy (sun.sun_path, hostname);
      sock = RPC_ANYSOCK;
      client = 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;
  memset (sin.sin_zero, 0, 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 = 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 = 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;
}
Example #2
0
/*
 * 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,
	rpcprog_t prog,
	rpcvers_t vers,
	const char *proto)
{
	struct hostent *h;
	struct protoent *p;
	struct sockaddr_in sin;
#ifndef __rtems__
	struct sockaddr_un sun;
#endif
	int sock;
	struct timeval tv;
	CLIENT *client;

#ifndef __rtems__
	if (!strcmp(proto, "unix")) {
		bzero((char *)&sun, sizeof(sun));
		sun.sun_family = AF_UNIX;
		strcpy(sun.sun_path, hostname);
		sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) +
				strlen(sun.sun_path) + 1;
		sock = RPC_ANYSOCK;
		client = clntunix_create(&sun, prog, vers, &sock, 0, 0);
		if (client == NULL)
			return(NULL);
		tv.tv_sec = 25;
		tv.tv_usec = 0;
		clnt_control(client, CLSET_TIMEOUT, &tv);
		return(client);
	}
#endif

	h = gethostbyname(hostname);
	if (h == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
		return (NULL);
	}
	if (h->h_addrtype != AF_INET) {
		/*
		 * Only support INET for now
		 */
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = EAFNOSUPPORT;
		return (NULL);
	}
	memset(&sin, 0, sizeof(sin));
	sin.sin_len = sizeof(struct sockaddr_in);
	sin.sin_family = h->h_addrtype;
	sin.sin_port = 0;
	memcpy((char*)&sin.sin_addr, h->h_addr, h->h_length);
	p = getprotobyname(proto);
	if (p == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT;
		return (NULL);
	}
	sock = RPC_ANYSOCK;
	switch (p->p_proto) {
	case IPPROTO_UDP:
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		client = clntudp_create(&sin, prog, vers, tv, &sock);
		if (client == NULL) {
			return (NULL);
		}
#if 0	/* XXX do we need this? */
		tv.tv_sec = 25;
		tv.tv_usec = 0;
		clnt_control(client, CLSET_TIMEOUT, &tv);
#endif
		break;
	case IPPROTO_TCP:
		client = clnttcp_create(&sin, prog, vers, &sock, 0, 0);
		if (client == NULL) {
			return (NULL);
		}
#if 0	/* XXX do we need this? */
		tv.tv_sec = 25;
		tv.tv_usec = 0;
		clnt_control(client, CLSET_TIMEOUT, &tv);
#endif
		break;
	default:
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT;
		return (NULL);
	}
	return (client);
}