Пример #1
0
/* libc_hidden_proto(clntudp_create) */
CLIENT *
clntudp_create (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp)
{

  return clntudp_bufcreate (raddr, program, version, wait, sockp,
			    UDPMSGSIZE, UDPMSGSIZE);
}
Пример #2
0
/*
 * Find the mapped port for program,version.
 * Calls the pmap service remotely to do the lookup.
 * Returns 0 if no map exists.
 */
u_short
pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
    u_int protocol)
{
	u_short port = 0;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;

	assert(address != NULL);

	address->sin_port = htons(PMAPPORT);
	client = clntudp_bufcreate(address, PMAPPROG,
	    PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client != NULL) {
		parms.pm_prog = program;
		parms.pm_vers = version;
		parms.pm_prot = protocol;
		parms.pm_port = 0;  /* not needed or used */
		if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
		    (xdrproc_t)xdr_pmap,
		    &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) !=
		    RPC_SUCCESS){
			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
			clnt_geterr(client, &rpc_createerr.cf_error);
		} else if (port == 0) {
			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
		}
		CLNT_DESTROY(client);
	}
	address->sin_port = 0;
	return (port);
}
Пример #3
0
CLIENT *
clntudp_create(struct sockaddr_in *raddr, rpcprog_t program, rpcvers_t version,
	struct timeval wait, int *sockp)
{
	return (clntudp_bufcreate(raddr, program, version, wait, sockp,
					UDPMSGSIZE, UDPMSGSIZE));
}
Пример #4
0
/*
 * Set a mapping between program,version and port.
 * Calls the pmap service remotely to do the mapping.
 */
bool_t
pmap_set(
	rpcprog_t program,
	rpcvers_t version,
	rpcprot_t protocol,
	u_int port)
{
	struct sockaddr_in myaddress;
	int socket = -1;
	register CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	get_myaddress(&myaddress);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == (CLIENT *)NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_prot = protocol;
	parms.pm_port = port;
	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout) != RPC_SUCCESS) {
		clnt_perror(client, "Cannot register service");
		return (FALSE);
	}
	CLNT_DESTROY(client);
	(void)close(socket);
	return (rslt);
}
Пример #5
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(
	rpcprog_t program,
	rpcvers_t version)
{
	struct sockaddr_in myaddress;
	int socket = -1;
	register CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	get_myaddress(&myaddress);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == (CLIENT *)NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_port = parms.pm_prot = 0;
	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout);
	CLNT_DESTROY(client);
	(void)close(socket);
	return (rslt);
}
Пример #6
0
int
key_gendes (des_block *key)
{
  struct sockaddr_in sin;
  CLIENT *client;
  int socket;
  enum clnt_stat stat;

  sin.sin_family = AF_INET;
  sin.sin_port = 0;
  sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  __bzero (sin.sin_zero, sizeof (sin.sin_zero));
  socket = RPC_ANYSOCK;
  client = clntudp_bufcreate (&sin, (u_long) KEY_PROG, (u_long) KEY_VERS,
			      trytimeout, &socket, RPCSMALLMSGSIZE,
			      RPCSMALLMSGSIZE);
  if (client == NULL)
    return -1;

  stat = clnt_call (client, KEY_GEN, (xdrproc_t) xdr_void, NULL,
		    (xdrproc_t) xdr_des_block, (caddr_t) key, tottimeout);
  clnt_destroy (client);
  __close (socket);
  if (stat != RPC_SUCCESS)
    return -1;

  return 0;
}
Пример #7
0
/*
 * Find the mapped port for program,version.
 * Calls the pmap service remotely to do the lookup.
 * Returns 0 if no map exists.
 */
u_short
pmap_getport(
    struct sockaddr_in *address,
    rpcprog_t program,
    rpcvers_t version,
    rpcprot_t protocol)
{
    unsigned short port = 0;
    int sock = -1;
    register CLIENT *client;
    struct pmap parms;

    address->sin_port = htons(PMAPPORT);
    client = clntudp_bufcreate(address, PMAPPROG,
                               PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
    if (client != (CLIENT *)NULL) {
        parms.pm_prog = program;
        parms.pm_vers = version;
        parms.pm_prot = protocol;
        parms.pm_port = 0;  /* not needed or used */
        if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
                      xdr_u_short, &port, tottimeout) != RPC_SUCCESS) {
            rpc_createerr.cf_stat = RPC_PMAPFAILURE;
            clnt_geterr(client, &rpc_createerr.cf_error);
        } else if (port == 0) {
            rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
        }
        CLNT_DESTROY(client);
    }
    (void)close(sock);
    address->sin_port = 0;
    return (port);
}
Пример #8
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(u_long program, u_long version)
{
	struct sockaddr_in myaddress;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	if (get_myaddress(&myaddress) != 0)
		return (FALSE);
	myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_port = parms.pm_prot = 0;
	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout);
	CLNT_DESTROY(client);
	if (sock != -1)
		(void)close(sock);
	return (rslt);
}
Пример #9
0
/*
 * Set a mapping between program,version and port.
 * Calls the pmap service remotely to do the mapping.
 */
bool_t
pmap_set(u_long program, u_long version, u_int protocol, int iport)
{
	struct sockaddr_in myaddress;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;
	bool_t rslt;
	u_short port = iport;

	if (get_myaddress(&myaddress) != 0)
		return (FALSE);
	myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_prot = protocol;
	parms.pm_port = port;
	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout) != RPC_SUCCESS) {
		int save_errno = errno;

		clnt_perror(client, "Cannot register service");
		errno = save_errno;
		return (FALSE);
	}
	CLNT_DESTROY(client);
	if (sock != -1)
		(void)close(sock);
	return (rslt);
}
Пример #10
0
CLIENT *
clntudp_create(
	struct sockaddr_in *raddr,
	unsigned long program,
	unsigned long version,
	struct timeval waitval,
	register int *sockp)
{
	return(clntudp_bufcreate(raddr, program, version, waitval, sockp,
	    UDPMSGSIZE, UDPMSGSIZE));
}
Пример #11
0
/*
 * Create a UDP RPC client
 */
static CLIENT* create_udp_client(struct conn_info *info)
{
	int fd;
	CLIENT *client;
	struct sockaddr_in laddr, raddr;
	struct hostent *hp;

	if (info->proto->p_proto != IPPROTO_UDP)
		return NULL;

	memset(&laddr, 0, sizeof(laddr));
	memset(&raddr, 0, sizeof(raddr));

	hp = gethostbyname(info->host);
	if (!hp)
		return NULL;

	raddr.sin_family = AF_INET;
	raddr.sin_port = htons(info->port);
	memcpy(&raddr.sin_addr.s_addr, hp->h_addr, hp->h_length);

	/*
	 * bind to any unused port.  If we left this up to the rpc
	 * layer, it would bind to a reserved port, which has been shown
	 * to exhaust the reserved port range in some situations.
	 */
	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fd < 0)
		return NULL;
	laddr.sin_family = AF_INET;
	laddr.sin_port = 0;
	laddr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(fd, (struct sockaddr *)&laddr, 
		 sizeof(struct sockaddr_in)) < 0) {
		close(fd);
		fd = RPC_ANYSOCK;
		/* FALLTHROUGH */
	}

	client = clntudp_bufcreate(&raddr,
				   info->program, info->version,
				   info->timeout, &fd,
				   info->send_sz, info->recv_sz);
	if (client)
		clnt_control(client, CLSET_FD_CLOSE, NULL);

	return client;
}
Пример #12
0
int main(int argn, char *argc[])
{
	//Program parameters : argc[1] : HostName or Host IP
	//					   argc[2] : Server Program Number
	//					   other arguments depend on test case

	//run_mode can switch into stand alone program or program launch by shell script
	//1 : stand alone, debug mode, more screen information
	//0 : launch by shell script as test case, only one printf -> result status
	int run_mode = 0;
	int test_status = 1; //Default test result set to FAILED
	int progNum = atoi(argc[2]);
	CLIENT *clnt = NULL;
	struct sockaddr_in server_addr;
	struct hostent *hp = NULL;
	struct timeval pertry_timeout;
	int sock = RPC_ANYSOCK;

	//Test initialization
	if ((hp = gethostbyname(argc[1])) == NULL) {
        fprintf(stderr, "can't get addr for %s\n",argc[1]);
        exit(-1);
    }

    pertry_timeout.tv_sec = 1;
    pertry_timeout.tv_usec = 0;

    bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = 0;

	//First of all, create a client
	clnt = clntudp_bufcreate(&server_addr, progNum, VERSNUM, pertry_timeout, &sock, 1024, 1024);

	if (run_mode == 1)
	{
		printf("CLIENT : %d\n", clnt);
	}

	//If we are here, macro call was successful
	test_status = ((CLIENT *)clnt != NULL) ? 0 : 1;

	//This last printf gives the result status to the tests suite
	//normally should be 0: test has passed or 1: test has failed
	printf("%d\n", test_status);

	return test_status;
}
Пример #13
0
InitRFSnfsClient(HPERIPHERAL PrinterHandle,
                 RFSItemCount MaxTransferSize)
{
#ifdef CLIENT_USING_TAL

    #define TIMEOUT_SEC 5

    struct timeval timeout;

    timeout.tv_usec  = 0;
    timeout.tv_sec   = TIMEOUT_SEC;
    return clnttal_bufcreate(PrinterHandle,
                             NFS_PROGRAM, NFS_VERSION,
                             timeout,
                             MaxTransferSize, MaxTransferSize);

#else /* not CLIENT_USING_TAL */

    /*
     * This was modelled after callrpc() in the
     * pre-TLI version of clntsimp.c  .
     *
     * If we get serious about non-TAL platforms, this
     * should use the TLI interface and a generic
     * clnt_create (see TLI version of clntgnc.c).
     */

    #define TIMEOUT_SEC 5

    struct sockaddr_in server_addr;
    struct hostent *hp;
    struct timeval timeout;
    socket_t ClientSocket = RPC_ANYSOCK;

    if ((hp = gethostbyname((char *)PrinterHandle)) == NULL)
        return NULL;
    timeout.tv_usec = 0;
    timeout.tv_sec = TIMEOUT_SEC;
    memmove((char *)&(server_addr.sin_addr), hp->h_addr, hp->h_length);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = 0;
    return clntudp_bufcreate(&server_addr,
                             NFS_PROGRAM, NFS_VERSION,
                             timeout, &ClientSocket,
                             MaxTransferSize, MaxTransferSize);
#endif /* not CLIENT_USING_TAL */
} /* InitRFSnfsClient */
Пример #14
0
fsal_status_t
fsal_proxy_create_rpc_clnt(proxyfsal_op_context_t * ctx)
{
  int sock;
  struct sockaddr_in addr_rpc;
  struct timeval timeout = TIMEOUTRPC;
  int rc;
  int priv_port = 0 ; 
  fsal_status_t fsal_status;
  char addr[INET_ADDRSTRLEN];

  memset(&addr_rpc, 0, sizeof(addr_rpc));
  addr_rpc.sin_port = ctx->srv_port;
  addr_rpc.sin_family = AF_INET;
  addr_rpc.sin_addr.s_addr = ctx->srv_addr;

  if(!strcmp(ctx->srv_proto, "udp"))
    {
      struct timeval tv = { 25, 0};

      if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        ReturnCode(ERR_FSAL_FAULT, errno);

      ctx->rpc_client = clntudp_bufcreate(&addr_rpc,
                                          ctx->srv_prognum,
                                          FSAL_PROXY_NFS_V4,
                                          tv,
                                          &sock,
                                          ctx->srv_sendsize,
                                          ctx->srv_recvsize);

      if(ctx->rpc_client == NULL)
        {

          LogCrit(COMPONENT_FSAL,
                  "Cannot contact server addr=%s port=%u prognum=%u using NFSv4 protocol",
                  inet_ntop(AF_INET, &ctx->srv_addr, addr, sizeof(addr)),
                  ntohs(ctx->srv_port), ctx->srv_prognum);

          ReturnCode(ERR_FSAL_INVAL, 0);
        }
    }
  else if(!strcmp(ctx->srv_proto, "tcp"))
    {
      if( ctx->use_privileged_client_port  == TRUE )
        {
	  if( (sock = rresvport( &priv_port ) )< 0 )
           {
             LogCrit(COMPONENT_FSAL, "Cannot create a tcp socket on a privileged port");
             ReturnCode(ERR_FSAL_FAULT, 0);
           }
        }
      else
        {
          if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
            {
              LogCrit(COMPONENT_FSAL, "Cannot create a tcp socket - %d", errno);
              ReturnCode(ERR_FSAL_FAULT, 0);
            }
        }

      if(connect(sock, (struct sockaddr *)&addr_rpc, sizeof(addr_rpc)) < 0)
        {
          LogCrit(COMPONENT_FSAL,
                  "Cannot connect to server addr=%s port=%u",
                  inet_ntop(AF_INET, &ctx->srv_addr, addr, sizeof(addr)),
                  ntohs(ctx->srv_port));

          ReturnCode(ERR_FSAL_FAULT, 0);
        }

      ctx->rpc_client = clnttcp_create(&addr_rpc,
                                       ctx->srv_prognum,
                                       FSAL_PROXY_NFS_V4,
                                       &sock,
                                       ctx->srv_sendsize,
                                       ctx->srv_recvsize);
      if(ctx->rpc_client == NULL)
        {
          LogCrit(COMPONENT_FSAL,
                  "Cannot contact server addr=%s port=%u prognum=%u using NFSv4 protocol",
                  inet_ntop(AF_INET, &ctx->srv_addr, addr, sizeof(addr)),
                  ntohs(ctx->srv_port), ctx->srv_prognum);

          ReturnCode(ERR_FSAL_INVAL, 0);
        }
    }
  else
    {
      ReturnCode(ERR_FSAL_INVAL, 0);
    }

  ctx->socket = sock;

#ifdef _USE_GSSRPC
  if(global_fsal_proxy_specific_info.active_krb5 == TRUE)
    {
      fsal_status = fsal_internal_set_auth_gss(ctx);
      if(FSAL_IS_ERROR(fsal_status))
        ReturnCode(fsal_status.major, fsal_status.minor);
    }
  else
#endif                          /* _USE_GSSRPC */

  if((ctx->rpc_auth = authunix_create_default()) == NULL)
    ReturnCode(ERR_FSAL_INVAL, 0);

  /* test if the newly created context can 'ping' the server via PROC_NULL */
  rc = clnt_call(ctx->rpc_client, ctx->rpc_auth, NFSPROC4_NULL,
                 (xdrproc_t) xdr_void, (caddr_t) NULL,
                 (xdrproc_t) xdr_void, (caddr_t) NULL, timeout);
  if(rc  != RPC_SUCCESS)
    ReturnCode(ERR_FSAL_INVAL, rc);

  fsal_status = FSAL_proxy_setclientid(ctx);
  if(FSAL_IS_ERROR(fsal_status))
    ReturnCode(ERR_FSAL_FAULT, 0);

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
Пример #15
0
void setup_resolv(bool *fwding, int *child,
			CLIENT **client, char *tp_type, long prognum)
{
	enum clnt_stat stat;
	struct timeval tv;
	char prog_str[15], fd_str[5];
	SVCXPRT *xprt = NULL;
	char *tp;
#ifdef	TDRPC
	struct sockaddr_in addr;
	int sock;
#else
	char name[257];
	struct netconfig *nc;
	void *h;
#endif
	verbose = silent == FALSE ? 1 : 0;

	if (! *fwding)
		return;

#ifdef	TDRPC
	tp = (tp_type && strcmp(tp_type, "udp") != 0) ? "udp" : "tcp";
#else
	/* try the specified netid (default ticots), then any loopback */
	tp = (tp_type && *tp_type) ? tp_type : "ticots";
	if (!getconf(tp, &h, &nc)) { /* dont forget endnetconfig() */
		syslog(LOG_ERR, "can't get resolv_clnt netconf %s.\n", tp);
		*fwding = FALSE;
		return;
	}
	tp = nc->nc_netid;
#endif

	/*
	 * Startup the resolv server: use transient prognum if prognum
	 * isn't set. Using transient means we create mapping then
	 * pass child the fd to use for service.
	 */
	if (!getprognum(&prognum, &xprt, fd_str, prog_str, YPDNSVERS, tp)) {
		syslog(LOG_ERR, "can't create resolv xprt for transient.\n");
		*fwding = FALSE;
#ifndef TDRPC
		endnetconfig(h);
#endif
		return;
	}
	switch (*child = vfork()) {
	case -1: /* error  */
		syslog(LOG_ERR, "can't startup resolv daemon\n");
#ifndef TDRPC
		endnetconfig(h);
#endif
		*fwding = FALSE;
		return;
	case 0:  /* child  */
		/*
		 * if using transient we must maintain fd across
		 * exec cause unset/set on prognum isn't automic.
		 *
		 * if using transient we'll just do svc_tli_create
		 * in child on our bound fd.
		 */
		execlp(RESOLV_EXEC_PATH, "rpc.nisd_resolv",
				"-F",		/* forground  */
				"-C", fd_str,	/* dont close */
				"-p", prog_str,	/* prognum    */
				"-t", tp,	/* tp type    */
				NULL);
		syslog(LOG_ERR, RESOLV_EXEC_ERR, strerror(errno));
		exit(1);
	default: /* parent */
		/* close fd, free xprt, but leave mapping */
		if (xprt)
			svc_destroy(xprt);

		/* let it crank up before we create client */
		sleep(4);
	}
#ifdef TDRPC
	get_myaddress(&addr);
	addr.sin_port = 0;
	sock = RPC_ANYSOCK;
	tv.tv_sec = 3; tv.tv_usec = 0;
	if (strcmp(tp, "udp") != 0) {
		*client = clntudp_bufcreate(&addr, prognum, YPDNSVERS,
					tv, &sock, YPMSGSZ, YPMSGSZ);
	} else {
		*client = clnttcp_create(&addr, prognum, YPDNSVERS,
					&sock, YPMSGSZ, YPMSGSZ);
	}
	if (*client == NULL) {
		syslog(LOG_ERR, "can't create resolv client handle.\n");
		(void) kill (*child, SIGINT);
		*fwding = FALSE;
		return;
	}
#else
	if (sysinfo(SI_HOSTNAME, name, sizeof (name)-1) == -1) {
		syslog(LOG_ERR, "can't get local hostname.\n");
		(void) kill (*child, SIGINT);
		endnetconfig(h);
		*fwding = FALSE;
		return;
	}
	if ((*client = clnt_tp_create(HOST_SELF_CONNECT, prognum,
			YPDNSVERS, nc)) == NULL) {
		syslog(LOG_ERR, "can't create resolv_clnt\n");
		(void) kill (*child, SIGINT);
		endnetconfig(h);
		*fwding = FALSE;
		return;
	}
	endnetconfig(h);
#endif

	/* ping for comfort */
	tv.tv_sec = 10; tv.tv_usec = 0;
	if ((stat = clnt_call(*client, 0, xdr_void, 0,
				xdr_void, 0, tv)) != RPC_SUCCESS) {
		syslog(LOG_ERR, "can't talk with resolv server\n");
		clnt_destroy (*client);
		(void) kill (*child, SIGINT);
		*fwding = FALSE;
		return;
	}

	if (verbose)
		syslog(LOG_INFO, "finished setup for dns fwding.\n");
}
Пример #16
0
static int nfs_probe_statd(void)
{
	struct sockaddr_in addr = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);

	return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr),
				program, (rpcvers_t)1, IPPROTO_UDP);
}

/**
 * start_statd - attempt to start rpc.statd
 *
 * Returns 1 if statd is running; otherwise zero.
 */
int start_statd(void)
{
#ifdef START_STATD
	struct stat stb;
#endif

	if (nfs_probe_statd())
		return 1;

#ifdef START_STATD
	if (stat(START_STATD, &stb) == 0) {
		if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
			pid_t pid = fork();
			switch (pid) {
			case 0: /* child */
				execl(START_STATD, START_STATD, NULL);
				exit(1);
			case -1: /* error */
				nfs_error(_("fork failed: %s"),
							strerror(errno));
				break;
			default: /* parent */
				waitpid(pid, NULL,0);
				break;
			}
			if (nfs_probe_statd())
				return 1;
		}
	}
#endif

	return 0;
}

/**
 * nfs_advise_umount - ask the server to remove a share from it's rmtab
 * @sap: pointer to IP address of server to call
 * @salen: length of server address
 * @pmap: partially filled-in mountd RPC service tuple
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason;  rpccreateerr.cf_stat is set to reflect
 * the nature of the error.
 *
 * We use a fast timeout since this call is advisory only.
 */
int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
		      const struct pmap *pmap, const dirpath *argp)
{
	struct sockaddr_storage address;
	struct sockaddr *saddr = (struct sockaddr *)&address;
	struct pmap mnt_pmap = *pmap;
	struct timeval timeout = {
		.tv_sec		= MOUNT_TIMEOUT >> 3,
	};
	CLIENT *client;
	enum clnt_stat res = 0;

	if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0)
		return 0;

	memcpy(saddr, sap, salen);
	nfs_set_port(saddr, mnt_pmap.pm_port);

	client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot,
					mnt_pmap.pm_prog, mnt_pmap.pm_vers,
					&timeout);
	if (client == NULL)
		return 0;

	client->cl_auth = authunix_create_default();

	res = CLNT_CALL(client, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			timeout);

	auth_destroy(client->cl_auth);
	CLNT_DESTROY(client);

	if (res != RPC_SUCCESS)
		return 0;

	return 1;
}

/**
 * nfs_call_umount - ask the server to remove a share from it's rmtab
 * @mnt_server: address of RPC MNT program server
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason.
 *
 * Note that a side effect of calling this function is that rpccreateerr
 * is set.
 */
int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
{
	struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr;
	socklen_t salen = sizeof(mnt_server->saddr);
	struct pmap *pmap = &mnt_server->pmap;
	CLIENT *clnt;
	enum clnt_stat res = 0;
	int msock;

	if (!nfs_probe_mntport(sap, salen, pmap))
		return 0;
	clnt = mnt_openclnt(mnt_server, &msock);
	if (!clnt)
		return 0;
	res = clnt_call(clnt, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			TIMEOUT);
	mnt_closeclnt(clnt, msock);

	if (res == RPC_SUCCESS)
		return 1;
	return 0;
}

/**
 * mnt_openclnt - get a handle for a remote mountd service
 * @mnt_server: address and pmap arguments of mountd service
 * @msock: returns a file descriptor of the underlying transport socket
 *
 * Returns an active handle for the remote's mountd service
 */
CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
{
	struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
	struct pmap *mnt_pmap = &mnt_server->pmap;
	CLIENT *clnt = NULL;

	mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
	*msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
				TRUE, FALSE);
	if (*msock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
			/*
			 * Probably in-use by a TIME_WAIT connection,
			 * It is worth waiting a while and trying again.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		return NULL;
	}

	switch (mnt_pmap->pm_prot) {
	case IPPROTO_UDP:
		clnt = clntudp_bufcreate(mnt_saddr,
					 mnt_pmap->pm_prog, mnt_pmap->pm_vers,
					 RETRY_TIMEOUT, msock,
					 MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(mnt_saddr,
				      mnt_pmap->pm_prog, mnt_pmap->pm_vers,
				      msock,
				      MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	}
	if (clnt) {
		/* try to mount hostname:dirname */
		clnt->cl_auth = authunix_create_default();
		return clnt;
	}
	return NULL;
}

/**
 * mnt_closeclnt - terminate a handle for a remote mountd service
 * @clnt: pointer to an active handle for a remote mountd service
 * @msock: file descriptor of the underlying transport socket
 *
 */
void mnt_closeclnt(CLIENT *clnt, int msock)
{
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);
	close(msock);
}

/**
 * clnt_ping - send an RPC ping to the remote RPC service endpoint
 * @saddr: server's address
 * @prog: target RPC program number
 * @vers: target RPC version number
 * @prot: target RPC protocol
 * @caddr: filled in with our network address
 *
 * Sigh... GETPORT queries don't actually check the version number.
 * In order to make sure that the server actually supports the service
 * we're requesting, we open an RPC client, and fire off a NULL
 * RPC call.
 *
 * caddr is the network address that the server will use to call us back.
 * On multi-homed clients, this address depends on which NIC we use to
 * route requests to the server.
 *
 * Returns one if successful, otherwise zero.
 */
int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
		const unsigned long vers, const unsigned int prot,
		struct sockaddr_in *caddr)
{
	CLIENT *clnt = NULL;
	int sock, stat;
	static char clnt_res;
	struct sockaddr dissolve;

	rpc_createerr.cf_stat = stat = 0;
	sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
	if (sock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
			/*
			 * TCP timeout. Bubble up the error to see 
			 * how it should be handled.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		}
		return 0;
	}

	if (caddr) {
		/* Get the address of our end of this connection */
		socklen_t len = sizeof(*caddr);
		if (getsockname(sock, caddr, &len) != 0)
			caddr->sin_family = 0;
	}

	switch(prot) {
	case IPPROTO_UDP:
		/* The socket is connected (so we could getsockname successfully),
		 * but some servers on multi-homed hosts reply from
		 * the wrong address, so if we stay connected, we lose the reply.
		 */
		dissolve.sa_family = AF_UNSPEC;
		connect(sock, &dissolve, sizeof(dissolve));

		clnt = clntudp_bufcreate(saddr, prog, vers,
					 RETRY_TIMEOUT, &sock,
					 RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(saddr, prog, vers, &sock,
				      RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	}
	if (!clnt) {
		close(sock);
		return 0;
	}
	memset(&clnt_res, 0, sizeof(clnt_res));
	stat = clnt_call(clnt, NULLPROC,
			 (xdrproc_t)xdr_void, (caddr_t)NULL,
			 (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
			 TIMEOUT);
	if (stat) {
		clnt_geterr(clnt, &rpc_createerr.cf_error);
		rpc_createerr.cf_stat = stat;
	}
	clnt_destroy(clnt);
	close(sock);

	if (stat == RPC_SUCCESS)
		return 1;
	else
		return 0;
}