*
*/
+#include "config.h"
#include <errno.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include "conn.h"
-extern int verbose;
+#if SIZEOF_SOCKLEN_T - 0 == 0
+#define socklen_t int
+#endif
-/* Map an NFS version into the corresponding Mountd version */
-u_long nfsvers_to_mnt(const u_long vers)
-{
- static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 };
- if (vers <= 3)
- return nfs_to_mnt[vers];
- return 0;
-}
-
-/* Map a Mountd version into the corresponding NFS version */
-u_long mntvers_to_nfs(const u_long vers)
-{
- static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 };
- if (vers <= 3)
- return mnt_to_nfs[vers];
- return 0;
-}
+extern int verbose;
/*
* Create a socket that is locally bound to a
* RPC_ANYSOCK is returned which will cause
* the RPC code to create the socket instead.
*/
-int get_socket(struct sockaddr_in *saddr, u_int p_prot, int resvp)
+int get_socket(struct sockaddr_in *saddr, u_int p_prot, int resvp, int conn)
{
int so, cc, type;
struct sockaddr_in laddr;
return RPC_ANYSOCK;
}
}
- if (type == SOCK_STREAM) {
+ if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
cc = connect(so, (struct sockaddr *)saddr, namelen);
if (cc < 0) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
*/
int
clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers,
- const u_int prot)
+ const u_int prot, struct sockaddr_in *caddr)
{
CLIENT *clnt=NULL;
int sock, stat;
static char clnt_res;
+ struct sockaddr dissolve;
rpc_createerr.cf_stat = stat = errno = 0;
- sock = get_socket(saddr, prot, FALSE);
- if (sock == RPC_ANYSOCK && errno == ETIMEDOUT) {
- /*
- * TCP timeout. Bubble up the error to see
- * how it should be handled.
- */
- rpc_createerr.cf_stat = RPC_TIMEDOUT;
- goto out_bad;
+ sock = get_socket(saddr, prot, FALSE, TRUE);
+ if (sock == RPC_ANYSOCK) {
+ if (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);
clnt = clnttcp_create(saddr, prog, vers, &sock,
RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
break;
- default:
- goto out_bad;
}
- if (!clnt)
- goto out_bad;
+ 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,
rpc_createerr.cf_stat = stat;
}
clnt_destroy(clnt);
- if (sock != -1)
- close(sock);
+ close(sock);
if (stat == RPC_SUCCESS)
return 1;
-
- out_bad:
- return 0;
+ else
+ return 0;
}
-
-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;
-
- /* contact the mount daemon via TCP */
- mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
- *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE);
-
- 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;
-}
-
-void mnt_closeclnt(CLIENT *clnt, int msock)
-{
- auth_destroy(clnt->cl_auth);
- clnt_destroy(clnt);
- close(msock);
-}
-