static int iscsi_tcp_connect(struct iscsi_context *iscsi, union socket_address *sa, int ai_family) { int socksize; 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 iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_command_cb cb, void *private_data) { int port = 3260; char *str; char *addr, *host; 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."); return -1; } addr = strdup(portal); if (addr == NULL) { iscsi_set_error(iscsi, "Out-of-memory: " "Failed to strdup portal address."); return -1; } host = addr; /* check if we have a target portal group tag */ str = strrchr(host, ','); if (str != NULL) { str[0] = 0; } str = strrchr(host, ':'); if (str != NULL) { if (strchr(str, ']') == NULL) { if (str != NULL) { port = atoi(str+1); str[0] = 0; } } } /* ipv6 in [...] form ? */ if (host[0] == '[') { host ++; str = strchr(host, ']'); if (str == NULL) { free(addr); iscsi_set_error(iscsi, "Invalid target:%s " "Missing ']' in IPv6 address", portal); return -1; } *str = 0; } /* is it a hostname ? */ if (getaddrinfo(host, NULL, NULL, &ai) != 0) { free(addr); iscsi_set_error(iscsi, "Invalid target:%s " "Can not resolv into IPv4/v6.", portal); return -1; } free(addr); switch (ai->ai_family) { case AF_INET: socksize = sizeof(struct sockaddr_in); ((struct sockaddr_in *)(ai->ai_addr))->sin_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in *)(ai->ai_addr))->sin_len = socksize; #endif break; case AF_INET6: socksize = sizeof(struct sockaddr_in6); ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_len = socksize; #endif break; default: iscsi_set_error(iscsi, "Unknown address family :%d. " "Only IPv4/IPv6 supported so far.", ai->ai_family); freeaddrinfo(ai); return -1; } 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; } iscsi->socket_status_cb = cb; iscsi->connect_data = private_data; 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 (connect(iscsi->fd, ai->ai_addr, socksize) != 0 && errno != EINPROGRESS) { iscsi_set_error(iscsi, "Connect failed with errno : " "%s(%d)", strerror(errno), errno); close(iscsi->fd); iscsi->fd = -1; freeaddrinfo(ai); return -1; } freeaddrinfo(ai); if (iscsi->connected_portal) free(discard_const(iscsi->connected_portal)); iscsi->connected_portal=strdup(portal); return 0; }