Libiscsi: Adding connect function to transport abstraction
socket: adding tcp_connect function and implement it in the last common part of iSER and TCP in iscsi_connect_async Signed-off-by: Roy Shterman <roysh@mellanox.com>
This commit is contained in:
committed by
Ronnie Sahlberg
parent
9378a39ddc
commit
0d6362ffe6
@@ -40,6 +40,9 @@ extern "C" {
|
|||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#define ISCSI_RAW_HEADER_SIZE 48
|
#define ISCSI_RAW_HEADER_SIZE 48
|
||||||
#define ISCSI_DIGEST_SIZE 4
|
#define ISCSI_DIGEST_SIZE 4
|
||||||
|
|
||||||
@@ -66,9 +69,15 @@ void iscsi_free_iscsi_inqueue(struct iscsi_context *iscsi, struct iscsi_in_pdu *
|
|||||||
/* max length of chap challange */
|
/* max length of chap challange */
|
||||||
#define MAX_CHAP_C_LENGTH 2048
|
#define MAX_CHAP_C_LENGTH 2048
|
||||||
|
|
||||||
|
union socket_address {
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
struct sockaddr sa;
|
||||||
|
};
|
||||||
|
|
||||||
struct iscsi_transport {
|
struct iscsi_transport {
|
||||||
|
|
||||||
int temp;
|
int (*connect)(struct iscsi_context *iscsi, union socket_address *sa, int ai_family);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcp_transport {
|
struct tcp_transport {
|
||||||
|
|||||||
175
lib/socket.c
175
lib/socket.c
@@ -74,13 +74,6 @@
|
|||||||
static uint32_t iface_rr = 0;
|
static uint32_t iface_rr = 0;
|
||||||
struct iscsi_transport;
|
struct iscsi_transport;
|
||||||
|
|
||||||
void iscsi_init_tcp_transport(struct iscsi_context *iscsi)
|
|
||||||
{
|
|
||||||
iscsi->t = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
|
iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
|
||||||
{
|
{
|
||||||
@@ -191,11 +184,83 @@ static int set_tcp_syncnt(struct iscsi_context *iscsi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
union socket_address {
|
static int iscsi_tcp_connect(struct iscsi_context *iscsi, union socket_address *sa, int ai_family) {
|
||||||
struct sockaddr_in sin;
|
|
||||||
struct sockaddr_in6 sin6;
|
int socksize;
|
||||||
struct sockaddr sa;
|
|
||||||
};
|
iscsi->fd = socket(ai_family, SOCK_STREAM, 0);
|
||||||
|
if (iscsi->fd == -1) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to open iscsi socket. "
|
||||||
|
"Errno:%s(%d).", strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscsi->old_iscsi && iscsi->fd != iscsi->old_iscsi->fd) {
|
||||||
|
if (dup2(iscsi->fd, iscsi->old_iscsi->fd) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(iscsi->fd);
|
||||||
|
iscsi->fd = iscsi->old_iscsi->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_nonblocking(iscsi->fd);
|
||||||
|
|
||||||
|
iscsi_set_tcp_keepalive(iscsi, iscsi->tcp_keepidle, iscsi->tcp_keepcnt, iscsi->tcp_keepintvl);
|
||||||
|
|
||||||
|
if (iscsi->tcp_user_timeout > 0) {
|
||||||
|
set_tcp_user_timeout(iscsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscsi->tcp_syncnt > 0) {
|
||||||
|
set_tcp_syncnt(iscsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __linux
|
||||||
|
if (iscsi->bind_interfaces[0]) {
|
||||||
|
char *pchr = iscsi->bind_interfaces, *pchr2;
|
||||||
|
int iface_n = iface_rr++%iscsi->bind_interfaces_cnt;
|
||||||
|
int iface_c = 0;
|
||||||
|
do {
|
||||||
|
pchr2 = strchr(pchr,',');
|
||||||
|
if (iface_c == iface_n) {
|
||||||
|
if (pchr2) pchr2[0]=0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pchr2) {pchr=pchr2+1;}
|
||||||
|
iface_c++;
|
||||||
|
} while (pchr2);
|
||||||
|
|
||||||
|
int res = setsockopt(iscsi->fd, SOL_SOCKET, SO_BINDTODEVICE, pchr, strlen(pchr));
|
||||||
|
if (res < 0) {
|
||||||
|
ISCSI_LOG(iscsi,1,"failed to bind to interface '%s': %s",pchr,strerror(errno));
|
||||||
|
} else {
|
||||||
|
ISCSI_LOG(iscsi,3,"successfully bound to interface '%s'",pchr);
|
||||||
|
}
|
||||||
|
if (pchr2) pchr2[0]=',';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (set_tcp_sockopt(iscsi->fd, TCP_NODELAY, 1) != 0) {
|
||||||
|
ISCSI_LOG(iscsi,1,"failed to set TCP_NODELAY sockopt: %s",strerror(errno));
|
||||||
|
} else {
|
||||||
|
ISCSI_LOG(iscsi,3,"TCP_NODELAY set to 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
socksize = sizeof(struct sockaddr_in); // Work-around for now, need to fix it
|
||||||
|
|
||||||
|
if (connect(iscsi->fd, &sa->sa, socksize) != 0
|
||||||
|
&& errno != EINPROGRESS) {
|
||||||
|
iscsi_set_error(iscsi, "Connect failed with errno : "
|
||||||
|
"%s(%d)", strerror(errno), errno);
|
||||||
|
close(iscsi->fd);
|
||||||
|
iscsi->fd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
|
iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
|
||||||
@@ -259,7 +324,7 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
|
|||||||
iscsi_set_error(iscsi, "Invalid target:%s "
|
iscsi_set_error(iscsi, "Invalid target:%s "
|
||||||
"Can not resolv into IPv4/v6.", portal);
|
"Can not resolv into IPv4/v6.", portal);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
iscsi_free(iscsi, addr);
|
iscsi_free(iscsi, addr);
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
@@ -291,87 +356,14 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iscsi->fd = socket(ai->ai_family, SOCK_STREAM, 0);
|
|
||||||
if (iscsi->fd == -1) {
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
iscsi_set_error(iscsi, "Failed to open iscsi socket. "
|
|
||||||
"Errno:%s(%d).", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iscsi->old_iscsi && iscsi->fd != iscsi->old_iscsi->fd) {
|
|
||||||
if (dup2(iscsi->fd, iscsi->old_iscsi->fd) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(iscsi->fd);
|
|
||||||
iscsi->fd = iscsi->old_iscsi->fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
iscsi->socket_status_cb = cb;
|
iscsi->socket_status_cb = cb;
|
||||||
iscsi->connect_data = private_data;
|
iscsi->connect_data = private_data;
|
||||||
|
|
||||||
set_nonblocking(iscsi->fd);
|
if(iscsi->t->connect(iscsi, &sa, ai->ai_family) < 0) {
|
||||||
|
iscsi_set_error(iscsi, "Couldn't connect transport");
|
||||||
iscsi_set_tcp_keepalive(iscsi, iscsi->tcp_keepidle, iscsi->tcp_keepcnt, iscsi->tcp_keepintvl);
|
|
||||||
|
|
||||||
if (iscsi->tcp_user_timeout > 0) {
|
|
||||||
set_tcp_user_timeout(iscsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iscsi->tcp_syncnt > 0) {
|
|
||||||
set_tcp_syncnt(iscsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __linux
|
|
||||||
if (iscsi->bind_interfaces[0]) {
|
|
||||||
char *pchr = iscsi->bind_interfaces, *pchr2;
|
|
||||||
int iface_n = iface_rr++%iscsi->bind_interfaces_cnt;
|
|
||||||
int iface_c = 0;
|
|
||||||
do {
|
|
||||||
pchr2 = strchr(pchr,',');
|
|
||||||
if (iface_c == iface_n) {
|
|
||||||
if (pchr2) pchr2[0]=0x00;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pchr2) {pchr=pchr2+1;}
|
|
||||||
iface_c++;
|
|
||||||
} while (pchr2);
|
|
||||||
|
|
||||||
int res = setsockopt(iscsi->fd, SOL_SOCKET, SO_BINDTODEVICE, pchr, strlen(pchr));
|
|
||||||
if (res < 0) {
|
|
||||||
ISCSI_LOG(iscsi,1,"failed to bind to interface '%s': %s",pchr,strerror(errno));
|
|
||||||
} else {
|
|
||||||
ISCSI_LOG(iscsi,3,"successfully bound to interface '%s'",pchr);
|
|
||||||
}
|
|
||||||
if (pchr2) pchr2[0]=',';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (set_tcp_sockopt(iscsi->fd, TCP_NODELAY, 1) != 0) {
|
|
||||||
ISCSI_LOG(iscsi,1,"failed to set TCP_NODELAY sockopt: %s",strerror(errno));
|
|
||||||
} else {
|
|
||||||
ISCSI_LOG(iscsi,3,"TCP_NODELAY set to 1");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connect(iscsi->fd, &sa.sa, socksize) != 0
|
|
||||||
#if defined(WIN32)
|
|
||||||
&& WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
||||||
#else
|
|
||||||
&& errno != EINPROGRESS) {
|
|
||||||
#endif
|
|
||||||
iscsi_set_error(iscsi, "Connect failed with errno : "
|
|
||||||
"%s(%d)", strerror(errno), errno);
|
|
||||||
close(iscsi->fd);
|
|
||||||
iscsi->fd = -1;
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
strncpy(iscsi->connected_portal,portal,MAX_STRING_SIZE);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1058,3 +1050,10 @@ void iscsi_set_bind_interfaces(struct iscsi_context *iscsi, char * interfaces _U
|
|||||||
ISCSI_LOG(iscsi,1,"binding to an interface is not supported on your OS");
|
ISCSI_LOG(iscsi,1,"binding to an interface is not supported on your OS");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iscsi_init_tcp_transport(struct iscsi_context *iscsi)
|
||||||
|
{
|
||||||
|
iscsi->t->connect = iscsi_tcp_connect;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user