⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi-io.c

📁 ISCSI user client software.Client would be used to access the IPSAN server.
💻 C
字号:
/* * iSCSI driver for Linux * Copyright (C) 2002 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsi-io.c,v 1.10 2005/01/11 03:47:08 mikenc Exp $ * */#include <stdint.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <sys/uio.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h>#include "iscsi-sfnet.h"#include "iscsi-protocol.h"#include "iscsi-session.h"#include "iscsi-config.h"#include "iscsi-hooks.h"#include "iscsid.h"#define LOG_CONN_CLOSED(session) \	logmsg(AS_ERROR, "Connection to Discovery Address %u.%u.%u.%u closed", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3])#define LOG_CONN_FAIL(session) \	logmsg(AS_ERROR, "Connection to Discovery Address %u.%u.%u.%u failed", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3])static int timedout;static voidsigalarm_handler(int unused){	timedout = 1;}intiscsi_connect(struct iscsi_session *session){	int ret, rc, sock, onearg;	struct sockaddr_in addr;	struct sigaction action;	struct sigaction old;	/* set a timeout, since the socket calls may take a long time to 	 * timeout on their own 	 */	memset(&action, 0, sizeof (struct sigaction));	memset(&old, 0, sizeof (struct sigaction));	action.sa_sigaction = NULL;	action.sa_flags = 0;	action.sa_handler = sigalarm_handler;	sigaction(SIGALRM, &action, &old);	timedout = 0;	alarm(session->login_timeout);	/* create a socket */	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if (sock < 0) {		errormsg("cannot create TCP socket");		ret = 0;		goto done;	}	onearg = 1;	rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &onearg,			sizeof (onearg));	if (rc < 0) {		ret = 0;		errormsg("cannot set TCP_NODELAY option on socket");		close(sock);		goto done;	}	/* optionally set the window sizes */	if (session->tcp_window_size) {		int window_size = session->tcp_window_size;		socklen_t arglen = sizeof (window_size);		if (setsockopt		    (sock, SOL_SOCKET, SO_RCVBUF, (char *) &window_size,		     sizeof (window_size)) < 0) {			logmsg(AS_NOTICE,			       "failed to set TCP recv window size to %u\n",			       window_size);		} else		    if (getsockopt			(sock, SOL_SOCKET, SO_RCVBUF, (char *) &window_size,			 &arglen) >= 0) {			debugmsg(4,				 "set TCP recv window size to %u, "				 "actually got %u\n",				 session->tcp_window_size, window_size);		}		window_size = session->tcp_window_size;		arglen = sizeof (window_size);		if (setsockopt		    (sock, SOL_SOCKET, SO_SNDBUF, (char *) &window_size,		     sizeof (window_size)) < 0) {			logmsg(AS_NOTICE,			       "failed to set TCP send window size to %u\n",			       window_size);		} else		    if (getsockopt			(sock, SOL_SOCKET, SO_SNDBUF, (char *) &window_size,			 &arglen) >= 0) {			debugmsg(4,				 "set TCP send window size to %u, "				 "actually got %u\n",				 session->tcp_window_size, window_size);		}	}	/*	 * Build a TCP connection to the target	 */	memset(&addr, 0, sizeof (addr));	addr.sin_family = AF_INET;	addr.sin_port = htons(session->port);	memcpy(&addr.sin_addr.s_addr, session->ip_address,	       MIN(sizeof (addr.sin_addr.s_addr), session->ip_length));	debugmsg(1, "connecting to %s:%d", inet_ntoa(addr.sin_addr),		 session->port);	rc = connect(sock, (struct sockaddr *) &addr, sizeof (addr));	if (timedout) {		debugmsg(1, "socket %d connect timed out", sock);		ret = 0;		goto done;	} else if (rc < 0) {		errormsg("cannot make connection to %s:%d",			 inet_ntoa(addr.sin_addr), session->port);		close(sock);		ret = 0;		goto done;	} else if (daemon_config.debug_level > 0) {		struct sockaddr_in local;		socklen_t len = sizeof (local);		if (getsockname(sock, (struct sockaddr *) &local, &len) >= 0) {			debugmsg(1, "connected local port %d to %s:%d",				 ntohs(local.sin_port),				 inet_ntoa(addr.sin_addr), session->port);		}	}	ret = 1;      done:	alarm(0);	sigaction(SIGALRM, &old, NULL);	session->socket_fd = sock;	return ret;}voidiscsi_disconnect(struct iscsi_session *session){	if (session->socket_fd >= 0) {		debugmsg(1, "disconnecting session %p, fd %d", session,			 session->socket_fd);		close(session->socket_fd);		session->socket_fd = -1;	}}static voidiscsi_log_text(struct iscsi_hdr *pdu, char *data){	int dlength = ntoh24(pdu->dlength);	char *text = data;	char *end = text + dlength;	while (text && (text < end)) {		debugmsg(4, ">    %s", text);		text += strlen(text);		while ((text < end) && (*text == '\0'))			text++;	}}intiscsi_send_pdu(struct iscsi_session *session, struct iscsi_hdr *pdu,	       int hdr_digest, char *data, int data_digest, int timeout){	int rc, ret = 0;	char *header = (char *) pdu;	char *end;	char pad[4];	struct iovec vec[3];	int pad_bytes;	int pdu_length = sizeof (*pdu) + pdu->hlength + ntoh24(pdu->dlength);	int remaining;	struct sigaction action;	struct sigaction old;	/* set a timeout, since the socket calls may take a long time 	 * to timeout on their own 	 */	memset(&action, 0, sizeof (struct sigaction));	memset(&old, 0, sizeof (struct sigaction));	action.sa_sigaction = NULL;	action.sa_flags = 0;	action.sa_handler = sigalarm_handler;	sigaction(SIGALRM, &action, &old);	timedout = 0;	alarm(timeout);	memset(&pad, 0, sizeof (pad));	memset(&vec, 0, sizeof (vec));	if (daemon_config.debug_level > 0) {		switch (pdu->opcode & ISCSI_OPCODE_MASK) {		case ISCSI_OP_LOGIN_CMD:{				struct iscsi_login_hdr *login_pdu =				    (struct iscsi_login_hdr *) pdu;				debugmsg(4,					 "sending login PDU with current stage "					 "%d, next stage %d, transit 0x%x, isid"					 " 0x%02x%02x%02x%02x%02x%02x",					 ISCSI_LOGIN_CURRENT_STAGE(login_pdu->								   flags),					 ISCSI_LOGIN_NEXT_STAGE(login_pdu->								flags),					 login_pdu->					 flags & ISCSI_FLAG_LOGIN_TRANSIT,					 login_pdu->isid[0], login_pdu->isid[1],					 login_pdu->isid[2], login_pdu->isid[3],					 login_pdu->isid[4],					 login_pdu->isid[5]);				iscsi_log_text(pdu, data);				break;			}		case ISCSI_OP_TEXT_CMD:{				struct iscsi_txt_hdr *text_pdu =				    (struct iscsi_txt_hdr *) pdu;				debugmsg(4,					 "sending text pdu with itt %u, "					 "CmdSN %u:",					 ntohl(text_pdu->itt),					 ntohl(text_pdu->cmdsn));				iscsi_log_text(pdu, data);				break;			}		case ISCSI_OP_NOOP_OUT:{				struct iscsi_nop_out_hdr *text_pdu =				    (struct iscsi_nop_out_hdr *) pdu;				debugmsg(4,					 "sending Nop-out pdu with itt %u, "					 "ttt %u, CmdSN %u:",					 ntohl(text_pdu->itt),					 ntohl(text_pdu->ttt),					 ntohl(text_pdu->cmdsn));				iscsi_log_text(pdu, data);				break;			}		default:			debugmsg(4, "sending pdu opcode 0x%x:", pdu->opcode);			break;		}	}	/* send the PDU header */	header = (char *) pdu;	end = header + sizeof (*pdu) + pdu->hlength;	while (header < end) {		vec[0].iov_base = header;		vec[0].iov_len = end - header;		rc = writev(session->socket_fd, vec, 1);		if (timedout) {			logmsg(AS_ERROR, "socket %d write timed out",			       session->socket_fd);			ret = 0;			goto done;		} else if ((rc <= 0) && (errno != EAGAIN)) {			LOG_CONN_FAIL(session);			ret = 0;			goto done;		} else if (rc > 0) {			debugmsg(4, "wrote %d bytes of PDU header", rc);			header += rc;		}		if (iscsi_process_should_exit()) {			ret = 0;			goto done;		}	}	/* send all the data and any padding */	if (pdu_length % PAD_WORD_LEN)		pad_bytes = PAD_WORD_LEN - (pdu_length % PAD_WORD_LEN);	else		pad_bytes = 0;	end = data + ntoh24(pdu->dlength);	remaining = ntoh24(pdu->dlength) + pad_bytes;	while (remaining > 0) {		vec[0].iov_base = data;		vec[0].iov_len = end - data;		vec[1].iov_base = (void *) &pad;		vec[1].iov_len = pad_bytes;		rc = writev(session->socket_fd, vec, 2);		if (timedout) {			logmsg(AS_ERROR, "socket %d write timed out",			       session->socket_fd);			ret = 0;			goto done;		} else if ((rc <= 0) && (errno != EAGAIN)) {			LOG_CONN_FAIL(session);			ret = 0;			goto done;		} else if (rc > 0) {			debugmsg(4, "wrote %d bytes of PDU data", rc);			remaining -= rc;			if (data < end) {				data += rc;				if (data > end)					data = end;			}		}		if (iscsi_process_should_exit()) {			ret = 0;			goto done;		}	}	ret = 1;      done:	alarm(0);	sigaction(SIGALRM, &old, NULL);	timedout = 0;	return ret;}intiscsi_recv_pdu(struct iscsi_session *session, struct iscsi_hdr *pdu,	       int hdr_digest, char *data, int max_data_length, int data_digest,	       int timeout){	uint32_t h_bytes = 0;	uint32_t ahs_bytes = 0;	uint32_t d_bytes = 0;	uint32_t ahslength = 0;	uint32_t dlength = 0;	uint32_t pad = 0;	int rlen = 0;	int failed = 0;	char *header = (char *) pdu;	char *end = data + max_data_length;	struct sigaction action;	struct sigaction old;	/* set a timeout, since the socket calls may take a long 	 * time to timeout on their own 	 */	memset(data, 0, max_data_length);	memset(&action, 0, sizeof (struct sigaction));	memset(&old, 0, sizeof (struct sigaction));	action.sa_sigaction = NULL;	action.sa_flags = 0;	action.sa_handler = sigalarm_handler;	sigaction(SIGALRM, &action, &old);	timedout = 0;	alarm(timeout);	/* read a response header */	do {		rlen =		    read(session->socket_fd, header, sizeof (*pdu) - h_bytes);		if (timedout) {			logmsg(AS_ERROR, "socket %d header read timed out",			       session->socket_fd);			failed = 1;			goto done;		} else if (rlen == 0) {			LOG_CONN_CLOSED(session);			failed = 1;			goto done;		} else if ((rlen < 0) && (errno != EAGAIN)) {			LOG_CONN_FAIL(session);			failed = 1;			goto done;		} else if (rlen > 0) {			debugmsg(4, "read %d bytes of PDU header", rlen);			header += rlen;			h_bytes += rlen;		}		if (iscsi_process_should_exit()) {			failed = 1;			goto done;		}	} while (h_bytes < sizeof (*pdu));	debugmsg(4,		 "read %d PDU header bytes, opcode 0x%x, dlength %u, "		 "data %p, max %u",		 h_bytes, pdu->opcode, ntoh24(pdu->dlength), data,		 max_data_length);	/* check for additional headers */	ahslength = pdu->hlength;	/* already includes padding */	if (ahslength) {		logmsg(LOG_NOTICE,		       "additional header segment length %u not supported",		       ahslength);		failed = 1;		goto done;	}	/* read exactly what we expect, plus padding */	dlength = pdu->dlength[0] << 16;	dlength |= pdu->dlength[1] << 8;	dlength |= pdu->dlength[2];	/* if we only expected to receive a header, exit */	if (dlength == 0)		goto done;    	if (data + dlength >= end) {		logmsg(LOG_NOTICE,		       "buffer size %u too small for data length %u",		       max_data_length, dlength);		failed = 1;		goto done;	}	/* read the rest into our buffer */	d_bytes = 0;	while (d_bytes < dlength) {		rlen =		    read(session->socket_fd, data + d_bytes, dlength - d_bytes);		if (timedout) {			logmsg(AS_ERROR, "socket %d data read timed out",			       session->socket_fd);			failed = 1;			goto done;		} else if (rlen == 0) {			LOG_CONN_CLOSED(session);			failed = 1;			goto done;		} else if ((rlen < 0 && errno != EAGAIN)) {			LOG_CONN_FAIL(session);			failed = 1;			goto done;		} else if (rlen > 0) {			debugmsg(4, "read %d bytes of PDU data", rlen);			d_bytes += rlen;		}		if (iscsi_process_should_exit()) {			failed = 1;			goto done;		}	}	/* handle PDU data padding */	pad = dlength % PAD_WORD_LEN;	if (pad) {		int pad_bytes = pad = PAD_WORD_LEN - pad;		char bytes[PAD_WORD_LEN];		while (pad_bytes > 0) {			rlen = read(session->socket_fd, &bytes, pad_bytes);			if (timedout) {				logmsg(AS_ERROR, "socket %d pad read timed out",				       session->socket_fd);				failed = 1;				goto done;			} else if (rlen == 0) {				LOG_CONN_CLOSED(session);				failed = 1;				goto done;			} else if ((rlen < 0 && errno != EAGAIN)) {				LOG_CONN_FAIL(session);				failed = 1;				goto done;			} else if (rlen > 0) {				debugmsg(4, "read %d pad bytes", rlen);				pad_bytes -= rlen;			}			if (iscsi_process_should_exit()) {				failed = 1;				goto done;			}		}	}	if (daemon_config.debug_level > 0) {		switch (pdu->opcode) {		case ISCSI_OP_TEXT_RSP:			debugmsg(4,				 "finished reading text PDU, %u hdr, %u "				 "ah, %u data, %u pad",				 h_bytes, ahs_bytes, d_bytes, pad);			iscsi_log_text(pdu, data);			break;		case ISCSI_OP_LOGIN_RSP:{				struct iscsi_login_rsp_hdr *login_rsp =				    (struct iscsi_login_rsp_hdr *) pdu;				debugmsg(4,					 "finished reading login PDU, %u hdr, "					 "%u ah, %u data, %u pad",					 h_bytes, ahs_bytes, d_bytes, pad);				debugmsg(4,					 "login current stage %d, next stage "					 "%d, transit 0x%x",					 ISCSI_LOGIN_CURRENT_STAGE(login_rsp->								   flags),					 ISCSI_LOGIN_NEXT_STAGE(login_rsp->								flags),					 login_rsp->					 flags & ISCSI_FLAG_LOGIN_TRANSIT);				iscsi_log_text(pdu, data);				break;			}		case ISCSI_OP_ASYNC_MSG:			/* FIXME: log the event info */			break;		default:			break;		}	}      done:	alarm(0);	sigaction(SIGALRM, &old, NULL);	if (timedout || failed) {		timedout = 0;		return 0;	} else {		return h_bytes + ahs_bytes + d_bytes;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -