add tcp-syncnt URL param to adjust TCP_SYNCNT sockopt
This allows indirect support for a configurable connect timeout. Linux uses a exponential backoff for SYN retries starting with 1 second. This means for a value n for TCP_SYNCNT, the connect will effectively timeout after 2^(n+1)-1 seconds. Example: examples/nfs-ls nfs://10.0.0.1/export?tcp-syncnt=1 Signed-off-by: Peter Lieven <pl@kamp.de>libnfs-4.0.0-vitalif
parent
d2ec73c75a
commit
1c8b4547ce
|
@ -121,6 +121,10 @@ AC_CHECK_HEADERS([sys/statvfs.h])
|
|||
dnl Check for sys/socket.h
|
||||
AC_CHECK_HEADERS([sys/socket.h])
|
||||
|
||||
# check for netinet/tcp.h
|
||||
dnl Check for netinet/tcp.h
|
||||
AC_CHECK_HEADERS([netinet/tcp.h])
|
||||
|
||||
# check for netinet/in.h
|
||||
dnl Check for netinet/in.h
|
||||
AC_CHECK_HEADERS([netinet/in.h])
|
||||
|
|
|
@ -56,9 +56,10 @@ struct rpc_fragment {
|
|||
};
|
||||
|
||||
#define RPC_CONTEXT_MAGIC 0xc6e46435
|
||||
#define RPC_PARAM_UNDEFINED -1
|
||||
|
||||
struct rpc_context {
|
||||
uint32_t magic;
|
||||
uint32_t magic;
|
||||
int fd;
|
||||
int is_connected;
|
||||
|
||||
|
@ -70,29 +71,32 @@ struct rpc_context {
|
|||
struct AUTH *auth;
|
||||
uint32_t xid;
|
||||
|
||||
/* buffer used for encoding RPC PDU */
|
||||
char *encodebuf;
|
||||
int encodebuflen;
|
||||
/* buffer used for encoding RPC PDU */
|
||||
char *encodebuf;
|
||||
int encodebuflen;
|
||||
|
||||
struct rpc_pdu *outqueue;
|
||||
struct sockaddr_storage udp_src;
|
||||
struct rpc_pdu *waitpdu;
|
||||
struct rpc_pdu *outqueue;
|
||||
struct sockaddr_storage udp_src;
|
||||
struct rpc_pdu *waitpdu;
|
||||
|
||||
uint32_t inpos;
|
||||
uint32_t insize;
|
||||
char *inbuf;
|
||||
uint32_t inpos;
|
||||
uint32_t insize;
|
||||
char *inbuf;
|
||||
|
||||
/* special fields for UDP, which can sometimes be BROADCASTed */
|
||||
int is_udp;
|
||||
struct sockaddr *udp_dest;
|
||||
int is_broadcast;
|
||||
/* special fields for UDP, which can sometimes be BROADCASTed */
|
||||
int is_udp;
|
||||
struct sockaddr *udp_dest;
|
||||
int is_broadcast;
|
||||
|
||||
/* track the address we connect to so we can auto-reconnect on session failure */
|
||||
struct sockaddr_storage s;
|
||||
int auto_reconnect;
|
||||
/* track the address we connect to so we can auto-reconnect on session failure */
|
||||
struct sockaddr_storage s;
|
||||
int auto_reconnect;
|
||||
|
||||
/* fragment reassembly */
|
||||
struct rpc_fragment *fragments;
|
||||
|
||||
/* parameters passable via URL */
|
||||
int tcp_syncnt;
|
||||
};
|
||||
|
||||
struct rpc_pdu {
|
||||
|
@ -135,6 +139,8 @@ struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc);
|
|||
void rpc_set_autoreconnect(struct rpc_context *rpc);
|
||||
void rpc_unset_autoreconnect(struct rpc_context *rpc);
|
||||
|
||||
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
|
||||
|
||||
int rpc_add_fragment(struct rpc_context *rpc, char *data, uint64_t size);
|
||||
void rpc_free_all_fragments(struct rpc_context *rpc);
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ struct rpc_context *rpc_init_context(void)
|
|||
rpc->xid = salt + time(NULL) + getpid() << 16;
|
||||
salt += 0x01000000;
|
||||
rpc->fd = -1;
|
||||
rpc->tcp_syncnt = RPC_PARAM_UNDEFINED;
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
|
|
@ -280,6 +280,9 @@ flags:
|
|||
if (strp2) {
|
||||
*strp2 = 0;
|
||||
strp2++;
|
||||
if (!strncmp(strp, "tcp-syncnt", 10)) {
|
||||
rpc_set_tcp_syncnt(nfs->rpc, atoi(strp2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
36
lib/socket.c
36
lib/socket.c
|
@ -46,6 +46,10 @@
|
|||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
@ -92,6 +96,26 @@ static void set_nonblocking(int fd)
|
|||
#endif //FIXME
|
||||
}
|
||||
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
int set_tcp_sockopt(int sockfd, int optname, int value)
|
||||
{
|
||||
int level;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__sun) || (defined(__APPLE__) && defined(__MACH__))
|
||||
struct protoent *buf;
|
||||
|
||||
if ((buf = getprotobyname("tcp")) != NULL)
|
||||
level = buf->p_proto;
|
||||
else
|
||||
return -1;
|
||||
#else
|
||||
level = SOL_TCP;
|
||||
#endif
|
||||
|
||||
return setsockopt(sockfd, level, optname, (char *)&value, sizeof(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
int rpc_get_fd(struct rpc_context *rpc)
|
||||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
@ -368,6 +392,13 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc)
|
|||
rpc->auto_reconnect = 0;
|
||||
}
|
||||
|
||||
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v)
|
||||
{
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
rpc->tcp_syncnt = v;
|
||||
}
|
||||
|
||||
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s)
|
||||
{
|
||||
int socksize;
|
||||
|
@ -378,6 +409,11 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
|
|||
case AF_INET:
|
||||
socksize = sizeof(struct sockaddr_in);
|
||||
rpc->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
|
||||
set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
rpc_set_error(rpc, "Can not handle AF_FAMILY:%d", s->ss_family);
|
||||
|
|
Loading…
Reference in New Issue