Esempio n. 1
0
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;
}
Esempio n. 2
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;
}