Blame usr/io.c

Packit Service 646995
/*
Packit Service 646995
 * iSCSI I/O Library
Packit Service 646995
 *
Packit Service 646995
 * Copyright (C) 2002 Cisco Systems, Inc.
Packit Service 646995
 * maintained by linux-iscsi-devel@lists.sourceforge.net
Packit Service 646995
 *
Packit Service 646995
 * This program is free software; you can redistribute it and/or modify
Packit Service 646995
 * it under the terms of the GNU General Public License as published
Packit Service 646995
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service 646995
 * (at your option) any later version.
Packit Service 646995
 *
Packit Service 646995
 * This program is distributed in the hope that it will be useful, but
Packit Service 646995
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 646995
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit Service 646995
 * General Public License for more details.
Packit Service 646995
 *
Packit Service 646995
 * See the file COPYING included with this distribution for more details.
Packit Service 646995
 */
Packit Service 646995
#include <string.h>
Packit Service 646995
#include <stdint.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
#include <errno.h>
Packit Service 646995
#include <stdio.h>
Packit Service 646995
#include <signal.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
#include <fcntl.h>
Packit Service 646995
#include <poll.h>
Packit Service 646995
#include <sys/ioctl.h>
Packit Service 646995
#include <netinet/tcp.h>
Packit Service 646995
#include <arpa/inet.h>
Packit Service 646995
#include <sys/uio.h>
Packit Service 646995
Packit Service 646995
#include "types.h"
Packit Service 646995
#include "iscsi_proto.h"
Packit Service 646995
#include "iscsi_settings.h"
Packit Service 646995
#include "initiator.h"
Packit Service 646995
#include "iscsi_ipc.h"
Packit Service 646995
#include "log.h"
Packit Service 646995
#include "transport.h"
Packit Service 646995
#include "idbm.h"
Packit Service 646995
#include "iface.h"
Packit Service 646995
#include "sysdeps.h"
Packit Service 646995
Packit Service 646995
#define LOG_CONN_CLOSED(conn) \
Packit Service 646995
do { \
Packit Service 646995
	getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
Packit Service 646995
		    conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
Packit Service 646995
	log_error("Connection to Discovery Address %s closed", conn->host); \
Packit Service 646995
} while (0)
Packit Service 646995
Packit Service 646995
#define LOG_CONN_FAIL(conn) \
Packit Service 646995
do { \
Packit Service 646995
	getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
Packit Service 646995
		    conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
Packit Service 646995
	log_error("Connection to Discovery Address %s failed", conn->host); \
Packit Service 646995
} while (0)
Packit Service 646995
Packit Service 646995
static int timedout;
Packit Service 646995
Packit Service 646995
static void
Packit Service 646995
sigalarm_handler(__attribute__((unused))int unused)
Packit Service 646995
{
Packit Service 646995
	timedout = 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static void
Packit Service 646995
set_non_blocking(int fd)
Packit Service 646995
{
Packit Service 646995
	int res = fcntl(fd, F_GETFL);
Packit Service 646995
Packit Service 646995
	if (res != -1) {
Packit Service 646995
		res = fcntl(fd, F_SETFL, res | O_NONBLOCK);
Packit Service 646995
		if (res)
Packit Service 646995
			log_warning("unable to set fd flags (%s)!",
Packit Service 646995
				    strerror(errno));
Packit Service 646995
	} else
Packit Service 646995
		log_warning("unable to get fd flags (%s)!", strerror(errno));
Packit Service 646995
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#if 0
Packit Service 646995
/* not used by anyone */
Packit Service 646995
static int get_hwaddress_from_netdev(char *netdev, char *hwaddress)
Packit Service 646995
{
Packit Service 646995
	struct ifaddrs *ifap, *ifa;
Packit Service 646995
	struct sockaddr_in *s4;
Packit Service 646995
	struct sockaddr_in6 *s6;
Packit Service 646995
	struct ifreq if_hwaddr;
Packit Service 646995
	int found = 0, sockfd;
Packit Service 646995
	unsigned char *hwaddr;
Packit Service 646995
	char buf[INET6_ADDRSTRLEN];
Packit Service 646995
Packit Service 646995
	if (getifaddrs(&ifap)) {
Packit Service 646995
		log_error("Could not match hwaddress %s to netdev. "
Packit Service 646995
			  "getifaddrs failed %d", hwaddress, errno);
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* Open a basic socket. */
Packit Service 646995
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
Packit Service 646995
	if (sockfd < 0) {
Packit Service 646995
		log_error("Could not open socket for ioctl.");
Packit Service 646995
		goto free_ifap;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
Packit Service 646995
		if (!ifa->ifa_addr)
Packit Service 646995
			continue;
Packit Service 646995
Packit Service 646995
		switch (ifa->ifa_addr->sa_family) {
Packit Service 646995
		case AF_INET:
Packit Service 646995
			s4 = (struct sockaddr_in *)(ifa->ifa_addr);
Packit Service 646995
			if (!inet_ntop(ifa->ifa_addr->sa_family,
Packit Service 646995
				      (void *)&(s4->sin_addr), buf,
Packit Service 646995
				      INET_ADDRSTRLEN))
Packit Service 646995
				continue;
Packit Service 646995
			log_debug(4, "name %s addr %s", ifa->ifa_name, buf);
Packit Service 646995
			break;
Packit Service 646995
		case AF_INET6:
Packit Service 646995
			s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
Packit Service 646995
			if (!inet_ntop(ifa->ifa_addr->sa_family,
Packit Service 646995
			    (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN))
Packit Service 646995
				continue;
Packit Service 646995
			log_debug(4, "name %s addr %s", ifa->ifa_name, buf);
Packit Service 646995
			break;
Packit Service 646995
		default:
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (strcmp(ifa->ifa_name, netdev))
Packit Service 646995
			continue;
Packit Service 646995
Packit Service 646995
		strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ);
Packit Service 646995
		if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
Packit Service 646995
			log_error("Could not match %s to netdevice.",
Packit Service 646995
				  hwaddress);
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		/* check for ARPHRD_ETHER (ethernet) */
Packit Service 646995
		if (if_hwaddr.ifr_hwaddr.sa_family != 1)
Packit Service 646995
			continue;
Packit Service 646995
		hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
Packit Service 646995
Packit Service 646995
		memset(hwaddress, 0, ISCSI_MAX_IFACE_LEN);
Packit Service 646995
		/* TODO should look and covert so we do not need tmp buf */
Packit Service 646995
		sprintf(hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
Packit Service 646995
			hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
Packit Service 646995
			hwaddr[4], hwaddr[5]);
Packit Service 646995
		log_debug(4, "Found hardware address %s", hwaddress);
Packit Service 646995
		found = 1;
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	close(sockfd);
Packit Service 646995
free_ifap:
Packit Service 646995
	freeifaddrs(ifap);
Packit Service 646995
	return found;
Packit Service 646995
}
Packit Service 646995
#endif
Packit Service 646995
Packit Service 646995
Packit Service 646995
#if 0
Packit Service 646995
Packit Service 646995
This is not supported for now, because it is not exactly what we want.
Packit Service 646995
It also turns out that targets will send packets to other interfaces
Packit Service 646995
causing all types of weird things to happen.
Packit Service 646995
Packit Service 646995
Packit Service 646995
static int bind_src_by_address(int sockfd, char *address)
Packit Service 646995
{
Packit Service 646995
	int rc = 0;
Packit Service 646995
	char port[NI_MAXSERV];
Packit Service 646995
	struct sockaddr_storage saddr;
Packit Service 646995
Packit Service 646995
	memset(&saddr, 0, sizeof(struct sockaddr_storage));
Packit Service 646995
	if (resolve_address(address, port, &saddr)) {
Packit Service 646995
		log_error("Could not bind %s to conn.", address);
Packit Service 646995
		return -1;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	switch (saddr.ss_family) {
Packit Service 646995
	case AF_INET:
Packit Service 646995
		rc = bind(sockfd, (struct sockaddr *)&saddr,
Packit Service 646995
			  sizeof(struct sockaddr_in));
Packit Service 646995
		break;
Packit Service 646995
	case AF_INET6:
Packit Service 646995
		rc = bind(sockfd, (struct sockaddr *)&saddr,
Packit Service 646995
			  sizeof(struct sockaddr_in6));
Packit Service 646995
		break;
Packit Service 646995
	default:
Packit Service 646995
		rc = -1;
Packit Service 646995
	}
Packit Service 646995
	if (rc)
Packit Service 646995
		log_error("Could not bind %s to %d.", address, sockfd);
Packit Service 646995
	else
Packit Service 646995
		log_debug(4, "Bound %s to socket fd %d", address, sockfd);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
#endif
Packit Service 646995
Packit Service 646995
static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_session *session = conn->session;
Packit Service 646995
Packit Service 646995
	if (strcmp(iface->transport_name, DEFAULT_TRANSPORT))
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
	memset(session->netdev, 0, IFNAMSIZ);
Packit Service 646995
	if (iface_is_bound_by_hwaddr(iface)) {
Packit Service 646995
		if (net_get_netdev_from_hwaddress(iface->hwaddress,
Packit Service 646995
						  session->netdev)) {
Packit Service 646995
			log_error("Cannot match %s to net/scsi interface.",
Packit Service 646995
				  iface->hwaddress);
Packit Service 646995
			return -1;
Packit Service 646995
		}
Packit Service 646995
	} else if (iface_is_bound_by_netdev(iface)) {
Packit Service 646995
		strcpy(session->netdev, iface->netdev);
Packit Service 646995
	} else if (iface_is_bound_by_ipaddr(iface)) {
Packit Service 646995
		/*
Packit Service 646995
		 * we never supported this but now with offload having to
Packit Service 646995
		 * set the ip address in the iface, useris may forget to
Packit Service 646995
		 * set the offload's transport type and we end up here by
Packit Service 646995
		 * accident.
Packit Service 646995
		 */
Packit Service 646995
		log_error("Cannot bind %s to net/scsi interface. This is not "
Packit Service 646995
			  "supported with software iSCSI (iscsi_tcp).",
Packit Service 646995
			   iface->ipaddress);
Packit Service 646995
		return -1;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (strlen(session->netdev)) {
Packit Service 646995
		struct ifreq ifr;
Packit Service 646995
Packit Service 646995
		log_debug(4, "Binding session %d to %s", session->id,
Packit Service 646995
			  session->netdev);
Packit Service 646995
		memset(&ifr, 0, sizeof(ifr));
Packit Service 646995
		strlcpy(ifr.ifr_name, session->netdev, IFNAMSIZ);
Packit Service 646995
Packit Service 646995
		if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
Packit Service 646995
			       session->netdev,
Packit Service 646995
			       strlen(session->netdev) + 1) < 0) {
Packit Service 646995
			log_error("Could not bind connection %d to %s",
Packit Service 646995
				  conn->id, session->netdev);
Packit Service 646995
			return -1;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int
Packit Service 646995
iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
Packit Service 646995
{
Packit Service 646995
	int rc, onearg;
Packit Service 646995
	struct sockaddr_storage *ss = &conn->saddr;
Packit Service 646995
	char serv[NI_MAXSERV];
Packit Service 646995
Packit Service 646995
	/* create a socket */
Packit Service 646995
	conn->socket_fd = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
Packit Service 646995
Packit Service 646995
	/* the trasport ep handle is used to bind with */
Packit Service 646995
	conn->transport_ep_handle = conn->socket_fd;
Packit Service 646995
Packit Service 646995
	if (conn->socket_fd < 0) {
Packit Service 646995
		log_error("cannot create TCP socket");
Packit Service 646995
		return -1;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
Packit Service 646995
		return -1;
Packit Service 646995
Packit Service 646995
	onearg = 1;
Packit Service 646995
	rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
Packit Service 646995
			sizeof (onearg));
Packit Service 646995
	if (rc < 0) {
Packit Service 646995
		log_error("cannot set TCP_NODELAY option on socket");
Packit Service 646995
		close(conn->socket_fd);
Packit Service 646995
		conn->socket_fd = -1;
Packit Service 646995
		return rc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* optionally set the window sizes */
Packit Service 646995
	if (conn->tcp_window_size) {
Packit Service 646995
		int window_size = conn->tcp_window_size;
Packit Service 646995
		socklen_t arglen = sizeof (window_size);
Packit Service 646995
Packit Service 646995
		if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
Packit Service 646995
		       (char *) &window_size, sizeof (window_size)) < 0) {
Packit Service 646995
			log_warning("failed to set TCP recv window size "
Packit Service 646995
				    "to %u", window_size);
Packit Service 646995
		} else {
Packit Service 646995
			if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
Packit Service 646995
				       (char *) &window_size, &arglen) >= 0) {
Packit Service 646995
				log_debug(4, "set TCP recv window size to %u, "
Packit Service 646995
					  "actually got %u",
Packit Service 646995
					  conn->tcp_window_size, window_size);
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		window_size = conn->tcp_window_size;
Packit Service 646995
		arglen = sizeof (window_size);
Packit Service 646995
Packit Service 646995
		if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
Packit Service 646995
		       (char *) &window_size, sizeof (window_size)) < 0) {
Packit Service 646995
			log_warning("failed to set TCP send window size "
Packit Service 646995
				    "to %u", window_size);
Packit Service 646995
		} else {
Packit Service 646995
			if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
Packit Service 646995
				       (char *) &window_size, &arglen) >= 0) {
Packit Service 646995
				log_debug(4, "set TCP send window size to %u, "
Packit Service 646995
					  "actually got %u",
Packit Service 646995
					  conn->tcp_window_size, window_size);
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Build a TCP connection to the target
Packit Service 646995
	 */
Packit Service 646995
	getnameinfo((struct sockaddr *) ss, sizeof(*ss),
Packit Service 646995
		    conn->host, sizeof(conn->host), serv, sizeof(serv),
Packit Service 646995
		    NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
	log_debug(1, "connecting to %s:%s", conn->host, serv);
Packit Service 646995
	if (non_blocking)
Packit Service 646995
		set_non_blocking(conn->socket_fd);
Packit Service 646995
	rc = connect(conn->socket_fd, (struct sockaddr *) ss, sizeof (*ss));
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int
Packit Service 646995
iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
Packit Service 646995
{
Packit Service 646995
	int rc;
Packit Service 646995
	struct pollfd pdesc;
Packit Service 646995
	char serv[NI_MAXSERV], lserv[NI_MAXSERV];
Packit Service 646995
	struct sockaddr_storage ss;
Packit Service 646995
	socklen_t len;
Packit Service 646995
Packit Service 646995
	pdesc.fd = conn->socket_fd;
Packit Service 646995
	pdesc.events = POLLOUT;
Packit Service 646995
	rc = poll(&pdesc, 1, timeout_ms);
Packit Service 646995
	if (rc == 0)
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
	if (rc < 0) {
Packit Service 646995
		getnameinfo((struct sockaddr *) &conn->saddr,
Packit Service 646995
			    sizeof(conn->saddr),
Packit Service 646995
			    conn->host, sizeof(conn->host), serv, sizeof(serv),
Packit Service 646995
			    NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
		log_error("cannot make connection to %s:%s (%s)",
Packit Service 646995
			  conn->host, serv, strerror(errno));
Packit Service 646995
		return rc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	len = sizeof(int);
Packit Service 646995
	if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
Packit Service 646995
			(char *) &rc, &len) < 0) {
Packit Service 646995
		log_error("getsockopt for connect poll failed");
Packit Service 646995
		return -1;
Packit Service 646995
	}
Packit Service 646995
	if (rc) {
Packit Service 646995
		getnameinfo((struct sockaddr *) &conn->saddr,
Packit Service 646995
			    sizeof(conn->saddr),
Packit Service 646995
			    conn->host, sizeof(conn->host), serv, sizeof(serv),
Packit Service 646995
			    NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
		log_error("connect to %s:%s failed (%s)",
Packit Service 646995
			  conn->host, serv, strerror(rc));
Packit Service 646995
		return -rc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	len = sizeof(ss);
Packit Service 646995
	if (log_level > 0 &&
Packit Service 646995
	    getsockname(conn->socket_fd, (struct sockaddr *) &ss, &len) >= 0) {
Packit Service 646995
		getnameinfo((struct sockaddr *) &conn->saddr,
Packit Service 646995
			    sizeof(conn->saddr), conn->host,
Packit Service 646995
			    sizeof(conn->host), serv, sizeof(serv),
Packit Service 646995
			    NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
		getnameinfo((struct sockaddr *) &ss, sizeof(ss),
Packit Service 646995
			     NULL, 0, lserv, sizeof(lserv), NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
		log_debug(1, "connected local port %s to %s:%s",
Packit Service 646995
			  lserv, conn->host, serv);
Packit Service 646995
	}
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void
Packit Service 646995
iscsi_io_tcp_disconnect(iscsi_conn_t *conn)
Packit Service 646995
{
Packit Service 646995
	struct linger so_linger = { .l_onoff = 1, .l_linger = 0 };
Packit Service 646995
Packit Service 646995
	if (conn->socket_fd >= 0) {
Packit Service 646995
		log_debug(1, "disconnecting conn %p, fd %d", conn,
Packit Service 646995
			 conn->socket_fd);
Packit Service 646995
Packit Service 646995
		/* If the state is not IN_LOGOUT, this isn't a clean shutdown
Packit Service 646995
		 * and there's some sort of error handling going on. In that
Packit Service 646995
		 * case, set a 0 SO_LINGER to force an abortive close (RST) and
Packit Service 646995
		 * free whatever is sitting in the TCP transmit queue. This is
Packit Service 646995
		 * done to prevent stale data from being sent should the
Packit Service 646995
		 * network connection be restored before TCP times out.
Packit Service 646995
		 */
Packit Service 646995
		if (conn->state != ISCSI_CONN_STATE_IN_LOGOUT) {
Packit Service 646995
			setsockopt(conn->socket_fd, SOL_SOCKET, SO_LINGER,
Packit Service 646995
				   &so_linger, sizeof(so_linger));
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		close(conn->socket_fd);
Packit Service 646995
		conn->socket_fd = -1;
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int
Packit Service 646995
iscsi_io_connect(iscsi_conn_t *conn)
Packit Service 646995
{
Packit Service 646995
	int rc, ret;
Packit Service 646995
	struct sigaction action;
Packit Service 646995
	struct sigaction old;
Packit Service 646995
Packit Service 646995
	/* set a timeout, since the socket calls may take a long time to
Packit Service 646995
	 * timeout on their own
Packit Service 646995
	 */
Packit Service 646995
	memset(&action, 0, sizeof (struct sigaction));
Packit Service 646995
	memset(&old, 0, sizeof (struct sigaction));
Packit Service 646995
	action.sa_sigaction = NULL;
Packit Service 646995
	action.sa_flags = 0;
Packit Service 646995
	action.sa_handler = sigalarm_handler;
Packit Service 646995
	sigaction(SIGALRM, &action, &old;;
Packit Service 646995
	timedout = 0;
Packit Service 646995
	alarm(conn->login_timeout);
Packit Service 646995
Packit Service 646995
	/* perform blocking TCP connect operation when no async request
Packit Service 646995
	 * associated. SendTargets Discovery know to work in such a mode.
Packit Service 646995
	 */
Packit Service 646995
	rc = iscsi_io_tcp_connect(conn, 0);
Packit Service 646995
	if (timedout) {
Packit Service 646995
		log_error("connect to %s timed out", conn->host);
Packit Service 646995
			  
Packit Service 646995
		log_debug(1, "socket %d connect timed out", conn->socket_fd);
Packit Service 646995
		ret = 0;
Packit Service 646995
		goto done;
Packit Service 646995
	} else if (rc < 0) {
Packit Service 646995
		log_error("cannot make connection to %s: %s",
Packit Service 646995
			  conn->host, strerror(errno));
Packit Service 646995
		close(conn->socket_fd);
Packit Service 646995
		ret = 0;
Packit Service 646995
		goto done;
Packit Service 646995
	} else if (log_level > 0) {
Packit Service 646995
		struct sockaddr_storage ss;
Packit Service 646995
		char lserv[NI_MAXSERV];
Packit Service 646995
		char serv[NI_MAXSERV];
Packit Service 646995
		socklen_t salen = sizeof(ss);
Packit Service 646995
Packit Service 646995
		if (getsockname(conn->socket_fd, (struct sockaddr *) &ss,
Packit Service 646995
				&salen) >= 0) {
Packit Service 646995
			getnameinfo((struct sockaddr *) &conn->saddr,
Packit Service 646995
				    sizeof(conn->saddr),
Packit Service 646995
				    conn->host, sizeof(conn->host), serv,
Packit Service 646995
				    sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
			getnameinfo((struct sockaddr *) &ss,
Packit Service 646995
				    sizeof(ss),
Packit Service 646995
				    NULL, 0, lserv, sizeof(lserv),
Packit Service 646995
				    NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
			log_debug(1, "connected local port %s to %s:%s",
Packit Service 646995
				  lserv, conn->host, serv);
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	ret = 1;
Packit Service 646995
Packit Service 646995
done:
Packit Service 646995
	alarm(0);
Packit Service 646995
	sigaction(SIGALRM, &old, NULL);
Packit Service 646995
	return ret;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void
Packit Service 646995
iscsi_io_disconnect(iscsi_conn_t *conn)
Packit Service 646995
{
Packit Service 646995
	iscsi_io_tcp_disconnect(conn);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static void
Packit Service 646995
iscsi_log_text(struct iscsi_hdr *pdu, char *data)
Packit Service 646995
{
Packit Service 646995
	int dlength = ntoh24(pdu->dlength);
Packit Service 646995
	char *text = data;
Packit Service 646995
	char *end = text + dlength;
Packit Service 646995
Packit Service 646995
	while (text && (text < end)) {
Packit Service 646995
		log_debug(4, ">    %s", text);
Packit Service 646995
		text += strlen(text);
Packit Service 646995
		while ((text < end) && (*text == '\0'))
Packit Service 646995
			text++;
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int
Packit Service 646995
iscsi_io_send_pdu(iscsi_conn_t *conn,
Packit Service 646995
		  struct iscsi_hdr *hdr,
Packit Service 646995
		  __attribute__((unused))int hdr_digest,
Packit Service 646995
		  char *data,
Packit Service 646995
		  __attribute__((unused))int data_digest,
Packit Service 646995
		  int timeout)
Packit Service 646995
{
Packit Service 646995
	int rc, ret = 0;
Packit Service 646995
	char *header = (char *) hdr;
Packit Service 646995
	char *end;
Packit Service 646995
	char pad[4];
Packit Service 646995
	struct iovec vec[3];
Packit Service 646995
	int pad_bytes;
Packit Service 646995
	int pdu_length = sizeof (*hdr) + hdr->hlength + ntoh24(hdr->dlength);
Packit Service 646995
	int remaining;
Packit Service 646995
	struct sigaction action;
Packit Service 646995
	struct sigaction old;
Packit Service 646995
	iscsi_session_t *session = conn->session;
Packit Service 646995
Packit Service 646995
	/* set a timeout, since the socket calls may take a long time
Packit Service 646995
	 * to timeout on their own
Packit Service 646995
	 */
Packit Service 646995
	if (!session->use_ipc) {
Packit Service 646995
		memset(&action, 0, sizeof (struct sigaction));
Packit Service 646995
		memset(&old, 0, sizeof (struct sigaction));
Packit Service 646995
		action.sa_sigaction = NULL;
Packit Service 646995
		action.sa_flags = 0;
Packit Service 646995
		action.sa_handler = sigalarm_handler;
Packit Service 646995
		sigaction(SIGALRM, &action, &old;;
Packit Service 646995
		timedout = 0;
Packit Service 646995
		alarm(timeout);
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	memset(&pad, 0, sizeof (pad));
Packit Service 646995
	memset(&vec, 0, sizeof (vec));
Packit Service 646995
Packit Service 646995
	switch (hdr->opcode & ISCSI_OPCODE_MASK) {
Packit Service 646995
	case ISCSI_OP_LOGIN:{
Packit Service 646995
		struct iscsi_login *login_hdr = (struct iscsi_login *) hdr;
Packit Service 646995
Packit Service 646995
		log_debug(4, "sending login PDU with current stage "
Packit Service 646995
			 "%d, next stage %d, transit 0x%x, isid"
Packit Service 646995
			 " 0x%02x%02x%02x%02x%02x%02x exp_statsn %u",
Packit Service 646995
			 ISCSI_LOGIN_CURRENT_STAGE(login_hdr->flags),
Packit Service 646995
			 ISCSI_LOGIN_NEXT_STAGE(login_hdr->flags),
Packit Service 646995
			 login_hdr->flags & ISCSI_FLAG_LOGIN_TRANSIT,
Packit Service 646995
			 login_hdr->isid[0], login_hdr->isid[1],
Packit Service 646995
			 login_hdr->isid[2], login_hdr->isid[3],
Packit Service 646995
			 login_hdr->isid[4], login_hdr->isid[5],
Packit Service 646995
			 ntohl(login_hdr->exp_statsn));
Packit Service 646995
Packit Service 646995
			iscsi_log_text(hdr, data);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
	case ISCSI_OP_TEXT:{
Packit Service 646995
		struct iscsi_text *text_hdr = (struct iscsi_text *) hdr;
Packit Service 646995
Packit Service 646995
		log_debug(4, "sending text pdu with CmdSN %x, exp_statsn %u",
Packit Service 646995
			 ntohl(text_hdr->cmdsn), ntohl(text_hdr->cmdsn));
Packit Service 646995
		iscsi_log_text(hdr, data);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
	case ISCSI_OP_NOOP_OUT:{
Packit Service 646995
		struct iscsi_nopout *nopout_hdr = (struct iscsi_nopout *) hdr;
Packit Service 646995
Packit Service 646995
		log_debug(4, "sending Nop-out pdu with ttt %x, CmdSN %x:",
Packit Service 646995
			 ntohl(nopout_hdr->ttt), ntohl(nopout_hdr->cmdsn));
Packit Service 646995
		iscsi_log_text(hdr, data);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
	default:
Packit Service 646995
		log_debug(4, "sending pdu opcode 0x%x:", hdr->opcode);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* send the PDU header */
Packit Service 646995
	header = (char *) hdr;
Packit Service 646995
	end = header + sizeof (*hdr) + hdr->hlength;
Packit Service 646995
Packit Service 646995
	/* send all the data and any padding */
Packit Service 646995
	if (pdu_length % ISCSI_PAD_LEN)
Packit Service 646995
		pad_bytes = ISCSI_PAD_LEN - (pdu_length % ISCSI_PAD_LEN);
Packit Service 646995
	else
Packit Service 646995
		pad_bytes = 0;
Packit Service 646995
Packit Service 646995
	if (session->use_ipc)
Packit Service 646995
		ipc->send_pdu_begin(session->t->handle, session->id,
Packit Service 646995
				    conn->id, end - header,
Packit Service 646995
				    ntoh24(hdr->dlength) + pad_bytes);
Packit Service 646995
Packit Service 646995
	while (header < end) {
Packit Service 646995
		vec[0].iov_base = header;
Packit Service 646995
		vec[0].iov_len = end - header;
Packit Service 646995
Packit Service 646995
		if (!session->use_ipc)
Packit Service 646995
			rc = writev(conn->socket_fd, vec, 1);
Packit Service 646995
		else
Packit Service 646995
			rc = ipc->writev(0, vec, 1);
Packit Service 646995
		if (timedout) {
Packit Service 646995
			log_error("socket %d write timed out",
Packit Service 646995
			       conn->socket_fd);
Packit Service 646995
			ret = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if ((rc <= 0) && (errno != EAGAIN)) {
Packit Service 646995
			LOG_CONN_FAIL(conn);
Packit Service 646995
			ret = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rc > 0) {
Packit Service 646995
			log_debug(4, "wrote %d bytes of PDU header", rc);
Packit Service 646995
			header += rc;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	end = data + ntoh24(hdr->dlength);
Packit Service 646995
	remaining = ntoh24(hdr->dlength) + pad_bytes;
Packit Service 646995
Packit Service 646995
	while (remaining > 0) {
Packit Service 646995
		vec[0].iov_base = data;
Packit Service 646995
		vec[0].iov_len = end - data;
Packit Service 646995
		vec[1].iov_base = (void *) &pad;
Packit Service 646995
		vec[1].iov_len = pad_bytes;
Packit Service 646995
Packit Service 646995
		if (!session->use_ipc)
Packit Service 646995
			rc = writev(conn->socket_fd, vec, 2);
Packit Service 646995
		else
Packit Service 646995
			rc = ipc->writev(0, vec, 2);
Packit Service 646995
		if (timedout) {
Packit Service 646995
			log_error("socket %d write timed out",
Packit Service 646995
				  conn->socket_fd);
Packit Service 646995
			ret = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if ((rc <= 0) && (errno != EAGAIN)) {
Packit Service 646995
			LOG_CONN_FAIL(conn);
Packit Service 646995
			ret = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rc > 0) {
Packit Service 646995
			log_debug(4, "wrote %d bytes of PDU data", rc);
Packit Service 646995
			remaining -= rc;
Packit Service 646995
			if (data < end) {
Packit Service 646995
				data += rc;
Packit Service 646995
				if (data > end)
Packit Service 646995
					data = end;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (session->use_ipc) {
Packit Service 646995
		if (ipc->send_pdu_end(session->t->handle, session->id,
Packit Service 646995
				      conn->id, &rc)) {
Packit Service 646995
			ret = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	ret = 1;
Packit Service 646995
Packit Service 646995
      done:
Packit Service 646995
	if (!session->use_ipc) {
Packit Service 646995
		alarm(0);
Packit Service 646995
		sigaction(SIGALRM, &old, NULL);
Packit Service 646995
		timedout = 0;
Packit Service 646995
	}
Packit Service 646995
	return ret;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int
Packit Service 646995
iscsi_io_recv_pdu(iscsi_conn_t *conn,
Packit Service 646995
		  struct iscsi_hdr *hdr,
Packit Service 646995
		  __attribute__((unused))int hdr_digest,
Packit Service 646995
		  char *data,
Packit Service 646995
		  int max_data_length,
Packit Service 646995
		  __attribute__((unused))int data_digest,
Packit Service 646995
		  int timeout)
Packit Service 646995
{
Packit Service 646995
	uint32_t h_bytes = 0;
Packit Service 646995
	uint32_t ahs_bytes = 0;
Packit Service 646995
	uint32_t d_bytes = 0;
Packit Service 646995
	uint32_t ahslength = 0;
Packit Service 646995
	uint32_t dlength = 0;
Packit Service 646995
	uint32_t pad = 0;
Packit Service 646995
	int rlen = 0;
Packit Service 646995
	int failed = 0;
Packit Service 646995
	char *header = (char *) hdr;
Packit Service 646995
	char *end = data + max_data_length;
Packit Service 646995
	struct sigaction action;
Packit Service 646995
	struct sigaction old;
Packit Service 646995
	iscsi_session_t *session = conn->session;
Packit Service 646995
Packit Service 646995
	memset(data, 0, max_data_length);
Packit Service 646995
Packit Service 646995
	/* set a timeout, since the socket calls may take a long
Packit Service 646995
	 * time to timeout on their own
Packit Service 646995
	 */
Packit Service 646995
	if (!session->use_ipc) {
Packit Service 646995
		memset(&action, 0, sizeof (struct sigaction));
Packit Service 646995
		memset(&old, 0, sizeof (struct sigaction));
Packit Service 646995
		action.sa_sigaction = NULL;
Packit Service 646995
		action.sa_flags = 0;
Packit Service 646995
		action.sa_handler = sigalarm_handler;
Packit Service 646995
		sigaction(SIGALRM, &action, &old;;
Packit Service 646995
		timedout = 0;
Packit Service 646995
		alarm(timeout);
Packit Service 646995
	} else {
Packit Service 646995
		failed = ipc->recv_pdu_begin(conn);
Packit Service 646995
		if (failed == -EAGAIN)
Packit Service 646995
			return -EAGAIN;
Packit Service 646995
		else if (failed < 0) {
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* read a response header */
Packit Service 646995
	do {
Packit Service 646995
		if (!session->use_ipc)
Packit Service 646995
			rlen = read(conn->socket_fd, header,
Packit Service 646995
					sizeof (*hdr) - h_bytes);
Packit Service 646995
		else
Packit Service 646995
			rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
Packit Service 646995
		if (timedout) {
Packit Service 646995
			log_error("socket %d header read timed out",
Packit Service 646995
				  conn->socket_fd);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rlen == 0) {
Packit Service 646995
			LOG_CONN_CLOSED(conn);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if ((rlen < 0) && (errno != EAGAIN)) {
Packit Service 646995
			LOG_CONN_FAIL(conn);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rlen > 0) {
Packit Service 646995
			log_debug(4, "read %d bytes of PDU header", rlen);
Packit Service 646995
			header += rlen;
Packit Service 646995
			h_bytes += rlen;
Packit Service 646995
		}
Packit Service 646995
	} while (h_bytes < sizeof (*hdr));
Packit Service 646995
Packit Service 646995
	log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
Packit Service 646995
		 "data %p, max %u", h_bytes, hdr->opcode & ISCSI_OPCODE_MASK,
Packit Service 646995
		 ntoh24(hdr->dlength), data, max_data_length);
Packit Service 646995
Packit Service 646995
	/* check for additional headers */
Packit Service 646995
	ahslength = hdr->hlength;	/* already includes padding */
Packit Service 646995
	if (ahslength) {
Packit Service 646995
		log_warning("additional header segment length %u not supported",
Packit Service 646995
		       ahslength);
Packit Service 646995
		failed = 1;
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* read exactly what we expect, plus padding */
Packit Service 646995
	dlength = hdr->dlength[0] << 16;
Packit Service 646995
	dlength |= hdr->dlength[1] << 8;
Packit Service 646995
	dlength |= hdr->dlength[2];
Packit Service 646995
Packit Service 646995
	/* if we only expected to receive a header, exit */
Packit Service 646995
	if (dlength == 0)
Packit Service 646995
		goto done;
Packit Service 646995
Packit Service 646995
	if (data + dlength > end) {
Packit Service 646995
		log_warning("buffer size %u too small for data length %u",
Packit Service 646995
		       max_data_length, dlength);
Packit Service 646995
		failed = 1;
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* read the rest into our buffer */
Packit Service 646995
	d_bytes = 0;
Packit Service 646995
	while (d_bytes < dlength) {
Packit Service 646995
		if (!session->use_ipc)
Packit Service 646995
			rlen = read(conn->socket_fd, data + d_bytes,
Packit Service 646995
					dlength - d_bytes);
Packit Service 646995
		else
Packit Service 646995
			rlen = ipc->read(data + d_bytes, dlength - d_bytes);
Packit Service 646995
		if (timedout) {
Packit Service 646995
			log_error("socket %d data read timed out",
Packit Service 646995
				  conn->socket_fd);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rlen == 0) {
Packit Service 646995
			LOG_CONN_CLOSED(conn);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if ((rlen < 0 && errno != EAGAIN)) {
Packit Service 646995
			LOG_CONN_FAIL(conn);
Packit Service 646995
			failed = 1;
Packit Service 646995
			goto done;
Packit Service 646995
		} else if (rlen > 0) {
Packit Service 646995
			log_debug(4, "read %d bytes of PDU data", rlen);
Packit Service 646995
			d_bytes += rlen;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* handle PDU data padding.
Packit Service 646995
	 * data is padded in case of kernel_io */
Packit Service 646995
	pad = dlength % ISCSI_PAD_LEN;
Packit Service 646995
	if (pad && !session->use_ipc) {
Packit Service 646995
		int pad_bytes = pad = ISCSI_PAD_LEN - pad;
Packit Service 646995
		char bytes[ISCSI_PAD_LEN];
Packit Service 646995
Packit Service 646995
		while (pad_bytes > 0) {
Packit Service 646995
			rlen = read(conn->socket_fd, &bytes, pad_bytes);
Packit Service 646995
			if (timedout) {
Packit Service 646995
				log_error("socket %d pad read timed out",
Packit Service 646995
					  conn->socket_fd);
Packit Service 646995
				failed = 1;
Packit Service 646995
				goto done;
Packit Service 646995
			} else if (rlen == 0) {
Packit Service 646995
				LOG_CONN_CLOSED(conn);
Packit Service 646995
				failed = 1;
Packit Service 646995
				goto done;
Packit Service 646995
			} else if ((rlen < 0 && errno != EAGAIN)) {
Packit Service 646995
				LOG_CONN_FAIL(conn);
Packit Service 646995
				failed = 1;
Packit Service 646995
				goto done;
Packit Service 646995
			} else if (rlen > 0) {
Packit Service 646995
				log_debug(4, "read %d pad bytes", rlen);
Packit Service 646995
				pad_bytes -= rlen;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	switch (hdr->opcode) {
Packit Service 646995
	case ISCSI_OP_TEXT_RSP:
Packit Service 646995
		log_debug(4, "finished reading text PDU, %u hdr, %u "
Packit Service 646995
			 "ah, %u data, %u pad",
Packit Service 646995
			 h_bytes, ahs_bytes, d_bytes, pad);
Packit Service 646995
		iscsi_log_text(hdr, data);
Packit Service 646995
		break;
Packit Service 646995
	case ISCSI_OP_LOGIN_RSP:{
Packit Service 646995
		struct iscsi_login_rsp *login_rsp =
Packit Service 646995
			    (struct iscsi_login_rsp *) hdr;
Packit Service 646995
Packit Service 646995
		log_debug(4, "finished reading login PDU, %u hdr, "
Packit Service 646995
			 "%u ah, %u data, %u pad",
Packit Service 646995
			  h_bytes, ahs_bytes, d_bytes, pad);
Packit Service 646995
		log_debug(4, "login current stage %d, next stage "
Packit Service 646995
			 "%d, transit 0x%x",
Packit Service 646995
			 ISCSI_LOGIN_CURRENT_STAGE(login_rsp->flags),
Packit Service 646995
			 ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags),
Packit Service 646995
			 login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT);
Packit Service 646995
		iscsi_log_text(hdr, data);
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
	case ISCSI_OP_ASYNC_EVENT:
Packit Service 646995
		/* FIXME: log the event info */
Packit Service 646995
		break;
Packit Service 646995
	default:
Packit Service 646995
		break;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
done:
Packit Service 646995
	if (!session->use_ipc) {
Packit Service 646995
		alarm(0);
Packit Service 646995
		sigaction(SIGALRM, &old, NULL);
Packit Service 646995
	} else {
Packit Service 646995
		/* finalyze receive transaction */
Packit Service 646995
		if (ipc->recv_pdu_end(conn)) {
Packit Service 646995
			failed = 1;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (timedout || failed) {
Packit Service 646995
		timedout = 0;
Packit Service 646995
		return -EIO;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return h_bytes + ahs_bytes + d_bytes;
Packit Service 646995
}