From 91267f5aaaaf705d4bb3a690dcba4eb7fb1c91b9 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 09:21:54 +0200 Subject: [PATCH 1/7] Limit immediate and unsolicited data to FirstBurstLength RFC3270 describes in section 12.14 that immediate and unsolicited data sent from the initiator to the target must not exceed FristBurstLength bytes in total. --- lib/scsi-command.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/scsi-command.c b/lib/scsi-command.c index 7c6770e..3122b52 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -242,8 +242,8 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) { uint32_t len = data.size; - if (len > iscsi->target_max_recv_data_segment_length) { - len = iscsi->target_max_recv_data_segment_length; + if (len > iscsi->first_burst_length) { + len = iscsi->first_burst_length; } if (iscsi_pdu_add_data(iscsi, pdu, data.data, len) @@ -302,7 +302,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, } /* Can we send some unsolicited data ? */ - if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { + if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO && iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_NO) { uint32_t len = pdu->nidata.size - offset; if (len > iscsi->first_burst_length) { From c4592550d645aa5d1fb5edd64a5cff6e91a4bcdd Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 09:40:05 +0200 Subject: [PATCH 2/7] Move iscsi_set_tcp_keepalive after socket creation Socket options should be set directly after socket creation. --- lib/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/socket.c b/lib/socket.c index 8ec437a..806ce7b 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -157,6 +157,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi->connect_data = private_data; set_nonblocking(iscsi->fd); + iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { @@ -437,7 +438,6 @@ iscsi_service(struct iscsi_context *iscsi, int revents) return -1; } - iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); iscsi->is_connected = 1; iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL, iscsi->connect_data); From 4cb845477d1b99ae100f1d2f638aa6412c214e45 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 10:36:26 +0200 Subject: [PATCH 3/7] Add debugging framework This patch adds a user configurable debug level. For testing it includes connection info and reporting errors. --- include/iscsi-private.h | 2 ++ include/iscsi.h | 8 ++++++++ lib/connect.c | 4 ++++ lib/init.c | 16 ++++++++++++++-- lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + lib/socket.c | 9 +++++++++ src/iscsi-inq.c | 8 +++++++- src/iscsi-ls.c | 9 +++++++-- 9 files changed, 53 insertions(+), 5 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index bbc0462..eb54a84 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -65,6 +65,7 @@ struct iscsi_context { const char *initiator_name; const char *target_name; const char *target_address; /* If a redirect */ + const char *connected_portal; const char *alias; const char *user; @@ -120,6 +121,7 @@ struct iscsi_context { const char *portal; int no_auto_reconnect; int reconnect_deferred; + int debug; }; #define ISCSI_PDU_IMMEDIATE 0x40 diff --git a/include/iscsi.h b/include/iscsi.h index ea00f31..60df33d 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -958,6 +958,14 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi, EXTERN void iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); +#define DPRINTF(iscsi,level,fmt,args...) do { if ((iscsi)->debug >= level) {fprintf(stderr,"libiscsi: ");fprintf(stderr, (fmt), ##args); fprintf(stderr,"\n");} } while (0); + +/* + * This function is to set the debugging level (0=disabled). + */ +EXTERN void +iscsi_set_debug(struct iscsi_context *iscsi, int level); + #ifdef __cplusplus } #endif diff --git a/lib/connect.c b/lib/connect.c index 931f571..db24a3a 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -158,6 +158,8 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi) { struct iscsi_context *iscsi = old_iscsi; + DPRINTF(iscsi,2,"reconnect initiated"); + /* This is mainly for tests, where we do not want to automatically reconnect but rather want the commands to fail with an error if the target drops the session. @@ -213,6 +215,8 @@ try_again: iscsi->lun = old_iscsi->lun; iscsi->portal = strdup(old_iscsi->portal); + + iscsi->debug = old_iscsi->debug; if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { iscsi_destroy_context(iscsi); diff --git a/lib/init.c b/lib/init.c index 1c11bcf..9c6bcac 100644 --- a/lib/init.c +++ b/lib/init.c @@ -244,6 +244,11 @@ iscsi_destroy_context(struct iscsi_context *iscsi) free(discard_const(iscsi->chap_c)); iscsi->chap_c = NULL; + if (iscsi->connected_portal != NULL) { + free(discard_const(iscsi->connected_portal)); + iscsi->connected_portal = NULL; + } + iscsi->connect_data = NULL; free(iscsi); @@ -251,8 +256,6 @@ iscsi_destroy_context(struct iscsi_context *iscsi) return 0; } - - void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) { @@ -270,9 +273,18 @@ iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) free(iscsi->error_string); iscsi->error_string = str; + va_end(ap); + + DPRINTF(iscsi,1,str); } +void +iscsi_set_debug(struct iscsi_context *iscsi, int level) +{ + iscsi->debug = level; + DPRINTF(iscsi,2,"set debug level to %d",level); +} const char * iscsi_get_error(struct iscsi_context *iscsi) diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 865a62f..0b6529e 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -62,6 +62,7 @@ iscsi_scsi_command_sync iscsi_scsi_task_cancel iscsi_service iscsi_set_alias +iscsi_set_debug iscsi_set_header_digest iscsi_set_initiator_username_pwd iscsi_set_isid_en diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 9c6bc3a..cee6081 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -60,6 +60,7 @@ iscsi_scsi_command_sync iscsi_scsi_task_cancel iscsi_service iscsi_set_alias +iscsi_set_debug iscsi_set_header_digest iscsi_set_initiator_username_pwd iscsi_set_isid_en diff --git a/lib/socket.c b/lib/socket.c index 806ce7b..b038c0b 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -68,6 +68,8 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, struct addrinfo *ai = NULL; int socksize; + DPRINTF(iscsi,2,"connecting to portal %s",portal); + if (iscsi->fd != -1) { iscsi_set_error(iscsi, "Trying to connect but already connected."); @@ -170,6 +172,10 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, } freeaddrinfo(ai); + + if (iscsi->connected_portal) free(iscsi->connected_portal); + iscsi->connected_portal=strdup(portal); + return 0; } @@ -183,6 +189,9 @@ iscsi_disconnect(struct iscsi_context *iscsi) } close(iscsi->fd); + + if (iscsi->connected_portal) + DPRINTF(iscsi,2,"disconnected from portal %s",iscsi->connected_portal); iscsi->fd = -1; iscsi->is_connected = 0; diff --git a/src/iscsi-inq.c b/src/iscsi-inq.c index e0fe471..87b6d35 100644 --- a/src/iscsi-inq.c +++ b/src/iscsi-inq.c @@ -196,6 +196,7 @@ void print_help(void) fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -e, --evpd=integer evpd\n"); fprintf(stderr, " -c, --pagecode=integer page code\n"); + fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Help options:\n"); fprintf(stderr, " -?, --help Show this help message\n"); @@ -218,7 +219,7 @@ int main(int argc, const char *argv[]) const char *url = NULL; struct iscsi_url *iscsi_url = NULL; int evpd = 0, pagecode = 0; - int show_help = 0, show_usage = 0; + int show_help = 0, show_usage = 0, debug = 0; int res; struct poptOption popt_options[] = { @@ -227,6 +228,7 @@ int main(int argc, const char *argv[]) { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" }, { "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" }, + { "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" }, POPT_TABLEEND }; @@ -263,6 +265,10 @@ int main(int argc, const char *argv[]) exit(10); } + if (debug > 0) { + iscsi_set_debug(iscsi, debug); + } + if (url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); diff --git a/src/iscsi-ls.c b/src/iscsi-ls.c index 1ce5b3b..6951a57 100644 --- a/src/iscsi-ls.c +++ b/src/iscsi-ls.c @@ -291,6 +291,7 @@ void print_help(void) fprintf(stderr, "Usage: iscsi-ls [OPTION...] \n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -s, --show-luns Show the luns for each target\n"); + fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Help options:\n"); fprintf(stderr, " -?, --help Show this help message\n"); @@ -314,13 +315,14 @@ int main(int argc, const char *argv[]) const char *url = NULL; poptContext pc; int res; - int show_help = 0, show_usage = 0; + int show_help = 0, show_usage = 0, debug = 0; struct poptOption popt_options[] = { { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL }, + { "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" }, POPT_TABLEEND }; @@ -353,7 +355,6 @@ int main(int argc, const char *argv[]) poptFreeContext(pc); - if (url == NULL) { fprintf(stderr, "You must specify iscsi target portal.\n"); print_usage(); @@ -366,6 +367,10 @@ int main(int argc, const char *argv[]) exit(10); } + if (debug > 0) { + iscsi_set_debug(iscsi, debug); + } + iscsi_url = iscsi_parse_portal_url(iscsi, url); if (iscsi_url == NULL) { fprintf(stderr, "Failed to parse URL: %s\n", From cb6f2ce252cb7009252f94aae8d1f774c800243c Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 10:48:52 +0200 Subject: [PATCH 4/7] iSCSI Redirect support This patch adds support for persistant portals like they are common to storage arrays with different interfaces or physical members. --- include/iscsi.h | 1 + lib/connect.c | 12 ++++++++++++ lib/login.c | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/include/iscsi.h b/include/iscsi.h index 60df33d..309c081 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -231,6 +231,7 @@ enum scsi_status { SCSI_STATUS_GOOD = 0, SCSI_STATUS_CHECK_CONDITION = 2, SCSI_STATUS_RESERVATION_CONFLICT = 0x18, + SCSI_STATUS_REDIRECT = 0x101, SCSI_STATUS_CANCELLED = 0x0f000000, SCSI_STATUS_ERROR = 0x0f000001 }; diff --git a/lib/connect.c b/lib/connect.c index db24a3a..eb9b7c7 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -35,6 +35,10 @@ struct connect_task { int lun; }; +static void +iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, + void *private_data); + static void iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) @@ -82,6 +86,14 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_, { struct connect_task *ct = private_data; + if (status == 0x101 && iscsi->target_address) { + iscsi_disconnect(iscsi); + if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) { + return; + } + return; + } + if (status != 0) { ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); return; diff --git a/lib/login.c b/lib/login.c index b685743..d841a4b 100644 --- a/lib/login.c +++ b/lib/login.c @@ -1088,6 +1088,13 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, size -= len + 1; } + if (status == 0x101 && iscsi->target_address) { + DPRINTF(iscsi,2,"target requests redirect to %s",iscsi->target_address); + pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL, + pdu->private_data); + return 0; + } + if (status != 0) { iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)", login_error_str(status), status); From f973608578a73e526fc09f107f5f9ca28eb28dcb Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 11:55:15 +0200 Subject: [PATCH 5/7] Add iscsi_tcp_set_user_timeout function This patch adds a user configurable option to set the TCP_USER_TIMEOUT socket option. With this timeout set a broken TCP session is shutdown after a given timeout even there are unacked packets. SO_KEEPALIVE seems not to work in this case. --- include/iscsi-private.h | 2 ++ include/iscsi.h | 7 ++++++ lib/connect.c | 2 ++ lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + lib/socket.c | 47 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index eb54a84..010eeb8 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -84,6 +84,8 @@ struct iscsi_context { int fd; int is_connected; + + int tcp_user_timeout; int current_phase; int next_phase; diff --git a/include/iscsi.h b/include/iscsi.h index 309c081..70881f6 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -967,6 +967,13 @@ iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); EXTERN void iscsi_set_debug(struct iscsi_context *iscsi, int level); +/* + * This function is to set the TCP_USER_TIMEOUT option. It has to be called after iscsi + * context creation. The value given in ms is then applied each time a new socket is created. + */ +EXTERN void +iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms); + #ifdef __cplusplus } #endif diff --git a/lib/connect.c b/lib/connect.c index eb9b7c7..23ed62f 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -229,6 +229,8 @@ try_again: iscsi->portal = strdup(old_iscsi->portal); iscsi->debug = old_iscsi->debug; + + iscsi->tcp_user_timeout = old_iscsi->tcp_user_timeout; if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { iscsi_destroy_context(iscsi); diff --git a/lib/libiscsi.def b/lib/libiscsi.def index 0b6529e..56ca61a 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -72,6 +72,7 @@ iscsi_set_isid_reserved iscsi_set_session_type iscsi_set_targetname iscsi_set_tcp_keepalive +iscsi_set_tcp_user_timeout iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index cee6081..dba697a 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -70,6 +70,7 @@ iscsi_set_isid_reserved iscsi_set_session_type iscsi_set_targetname iscsi_set_tcp_keepalive +iscsi_set_tcp_user_timeout iscsi_startstopunit_sync iscsi_startstopunit_task iscsi_synchronizecache10_sync diff --git a/lib/socket.c b/lib/socket.c index b038c0b..0da1d95 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -159,7 +159,14 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi->connect_data = private_data; set_nonblocking(iscsi->fd); - iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); + + if (iscsi->tcp_user_timeout > 0) { + set_tcp_user_timeout(iscsi); + } + else + { + iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); + } if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { @@ -524,6 +531,40 @@ iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue) } } +#ifndef TCP_USER_TIMEOUT +#define TCP_USER_TIMEOUT 18 +#endif + +int set_tcp_user_timeout(struct iscsi_context *iscsi) +{ + int level, value; + + #if defined(__FreeBSD__) || defined(__sun) + struct protoent *buf; + + if ((buf = getprotobyname("tcp")) != NULL) + level = buf->p_proto; + else + return -1; + #else + level = SOL_TCP; + #endif + + value = iscsi->tcp_user_timeout; + if (setsockopt(iscsi->fd, level, TCP_USER_TIMEOUT, &value, sizeof(value)) != 0) { + iscsi_set_error(iscsi, "TCP: Failed to set tcp user timeout. Error %s(%d)", strerror(errno), errno); + return -1; + } + DPRINTF(iscsi,3,"TCP_USER_TIMEOUT set to %d",value); + return 0; +} + +void iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms) +{ + iscsi->tcp_user_timeout=timeout_ms; + DPRINTF(iscsi,2,"TCP_USER_TIMEOUT will be set to %dms on next socket creation",timeout_ms); +} + int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval) { int level, value; @@ -544,6 +585,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno); return -1; } + DPRINTF(iscsi,3,"SO_KEEPALIVE set to %d",value); #endif #ifdef TCP_KEEPCNT value = count; @@ -551,6 +593,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno); return -1; } + DPRINTF(iscsi,3,"TCP_KEEPCNT set to %d",value); #endif #ifdef TCP_KEEPINTVL value = interval; @@ -558,6 +601,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno); return -1; } + DPRINTF(iscsi,3,"TCP_KEEPINTVL set to %d",value); #endif #ifdef TCP_KEEPIDLE value = idle; @@ -565,6 +609,7 @@ int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, in iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno); return -1; } + DPRINTF(iscsi,3,"TCP_KEEPIDLE set to %d",value); #endif return 0; From 326b2ea49dab81ac5adb3f8e30d340943e13a602 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 12:18:40 +0200 Subject: [PATCH 6/7] Add backoff mechanism to iscsi_reconnect This patch adds a linear backoff mechanishm + jitter in case a reconnect fails. If there is a longer outage this is to avoid a large amount of simultaneous connects to the storage. --- lib/connect.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/connect.c b/lib/connect.c index 23ed62f..f82df28 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -209,6 +209,9 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi) return 0; } + int retry = 0; + srand (time(NULL)^getpid()); + try_again: iscsi = iscsi_create_context(old_iscsi->initiator_name); @@ -234,7 +237,17 @@ try_again: if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { iscsi_destroy_context(iscsi); - sleep(1); + int backoff=retry; + if (backoff > 10) { + backoff+=rand()%10; + backoff-=5; + } + if (backoff > 30) { + backoff=30; + } + DPRINTF(iscsi,1,"reconnect try %d failed, waiting %d seconds",retry,backoff); + sleep(backoff); + retry++; goto try_again; } From cc2b0c9b1dc90aa6fd5d3fe63ea832fdcc0ba66a Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 18 Oct 2012 14:31:09 +0200 Subject: [PATCH 7/7] Set SO_KEEPALIVE before TCP_USER_TIMEOUT For TCP_USER_TIMEOUT to work it seems to be necessary that SO_KEEPALIVE is enabled. RFC5482 section 4.2 also says that the TCP_USER_TIMEOUT has to be less than the keepalive timeout. This means less than 30000 ms in the current libiscsi default settings for TCP keepalives. --- lib/socket.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/socket.c b/lib/socket.c index 0da1d95..9912976 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -160,13 +160,11 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, set_nonblocking(iscsi->fd); + iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); + if (iscsi->tcp_user_timeout > 0) { set_tcp_user_timeout(iscsi); } - else - { - iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); - } if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) {