int iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { struct iscsi_discovery_address *targets = NULL; unsigned char *ptr = in->data; int size = in->data_pos; /* verify the response looks sane */ if (in->hdr[1] != ISCSI_PDU_TEXT_FINAL) { iscsi_set_error(iscsi, "unsupported flags in text " "reply %02x", in->hdr[1]); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } return -1; } while (size > 0) { unsigned char *end; int len; end = memchr(ptr, 0, size); if (end == NULL) { iscsi_set_error(iscsi, "NUL not found after offset %ld " "when parsing discovery data", (long)(ptr - in->data)); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } len = end - ptr; if (len == 0) { break; } /* parse the strings */ if (!strncmp((char *)ptr, "TargetName=", 11)) { struct iscsi_discovery_address *target; target = iscsi_zmalloc(iscsi, sizeof(struct iscsi_discovery_address)); if (target == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target"); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } target->target_name = iscsi_strdup(iscsi,(char *)ptr+11); if (target->target_name == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target name"); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free(iscsi, target); target = NULL; iscsi_free_discovery_addresses(iscsi, targets); return -1; } target->next = targets; targets = target; } else if (!strncmp((char *)ptr, "TargetAddress=", 14)) { struct iscsi_target_portal *portal; if (targets == NULL) { iscsi_set_error(iscsi, "Invalid discovery " "reply"); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } portal = iscsi_zmalloc(iscsi, sizeof(struct iscsi_target_portal)); if (portal == NULL) { iscsi_set_error(iscsi, "Failed to malloc " "portal structure"); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } portal->next = targets->portals; targets->portals = portal; portal->portal = iscsi_strdup(iscsi, (char *)ptr+14); if (portal->portal == NULL) { iscsi_set_error(iscsi, "Failed to allocate " "data for new discovered " "target address"); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } } else { iscsi_set_error(iscsi, "Don't know how to handle " "discovery string : %s", ptr); if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); return -1; } ptr += len + 1; size -= len + 1; } if (pdu->callback) { pdu->callback(iscsi, SCSI_STATUS_GOOD, targets, pdu->private_data); } iscsi_free_discovery_addresses(iscsi, targets); 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; union socket_address sa; int socksize; ISCSI_LOG(iscsi, 2, "connecting to portal %s",portal); if (iscsi->fd != -1) { iscsi_set_error(iscsi, "Trying to connect but already connected."); return -1; } addr = iscsi_strdup(iscsi, 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) { iscsi_free(iscsi, 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) { iscsi_free(iscsi, addr); iscsi_set_error(iscsi, "Invalid target:%s " "Can not resolv into IPv4/v6.", portal); return -1; } iscsi_free(iscsi, addr); memset(&sa, 0, sizeof(sa)); switch (ai->ai_family) { case AF_INET: socksize = sizeof(struct sockaddr_in); memcpy(&sa.sin, ai->ai_addr, socksize); sa.sin.sin_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN sa.sin.sin_len = socksize; #endif break; #ifdef HAVE_SOCKADDR_IN6 case AF_INET6: socksize = sizeof(struct sockaddr_in6); memcpy(&sa.sin6, ai->ai_addr, socksize); sa.sin6.sin6_port = htons(port); #ifdef HAVE_SOCK_SIN_LEN sa.sin6.sin6_len = socksize; #endif break; #endif default: iscsi_set_error(iscsi, "Unknown address family :%d. " "Only IPv4/IPv6 supported so far.", ai->ai_family); freeaddrinfo(ai); return -1; } iscsi->socket_status_cb = cb; iscsi->connect_data = private_data; if (iscsi->t->connect(iscsi, &sa, ai->ai_family) < 0) { iscsi_set_error(iscsi, "Couldn't connect transport"); freeaddrinfo(ai); return -1; } freeaddrinfo(ai); return 0; }