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

📄 iscsi-discovery.c

📁 ISCSI user client software.Client would be used to access the IPSAN server.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * iSCSI connection daemon * 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-discovery.c,v 1.21 2005/01/21 13:10:21 krishmnc Exp $ * */#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include <netdb.h>#include <stdint.h>#include <sys/poll.h>#include <sys/time.h>#include "iscsi-sfnet.h"#include "iscsi-protocol.h"#include "iscsi-login.h"#include "iscsi-hooks.h"#include "string-buffer.h"#include "iscsi-session.h"#ifdef SLP_ENABLE#include "iscsi-slp-discovery.h"#endif#define DISCOVERY_NEED_RECONNECT 0xdead0001static int rediscover = 0;static int record_begin;static voidsighup_handler(int unused){	rediscover = 1;}static intsend_nop_reply(struct iscsi_session *session, struct iscsi_nop_in_hdr *nop,	       char *data, int timeout){	struct iscsi_nop_out_hdr out;	memset(&out, 0, sizeof (out));	out.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;	out.flags = ISCSI_FLAG_FINAL;	memcpy(out.lun, nop->lun, sizeof (out.lun));	out.itt = nop->itt;	out.ttt = nop->ttt;	memcpy(out.dlength, nop->dlength, sizeof (out.dlength));	out.cmdsn = htonl(session->cmd_sn);	/* don't increment after 						 * immediate cmds 						 */	out.expstatsn = htonl(session->exp_stat_sn);	debugmsg(4, "sending nop reply for ttt %u, cmdsn %u, dlength %d",		 ntohl(out.ttt), ntohl(out.cmdsn), ntoh24(out.dlength));	return iscsi_send_pdu(session, (struct iscsi_hdr *) &out,			ISCSI_DIGEST_NONE, data, ISCSI_DIGEST_NONE, timeout);}static intiscsi_make_text_pdu(struct iscsi_session *session, struct iscsi_hdr *pdu,		    char *data, int max_data_length){	struct iscsi_txt_hdr *text_pdu = (struct iscsi_txt_hdr *)pdu;	/* initialize the PDU header */	memset(text_pdu, 0, sizeof (*text_pdu));	text_pdu->opcode = ISCSI_OP_TEXT_CMD;	text_pdu->itt = htonl(session->itt);	text_pdu->ttt = ISCSI_RSVD_TASK_TAG;	text_pdu->cmdsn = htonl(session->cmd_sn++);	text_pdu->expstatsn = htonl(session->exp_stat_sn);	return 1;}static intrequest_targets(struct iscsi_session *session){	char data[64];	struct iscsi_txt_hdr text;	struct iscsi_hdr *pdu = (struct iscsi_hdr *) &text;	memset(&text, 0, sizeof (text));	memset(data, 0, sizeof (data));	/* make a text PDU with SendTargets=All */	if (!iscsi_make_text_pdu(session, pdu, data, sizeof (data))) {		logmsg(AS_ERROR, "failed to make a SendTargets PDU");		return 0;	}	if (!iscsi_add_text	    (session, pdu, data, sizeof (data), "SendTargets", "All")) {		logmsg(AS_ERROR, "failed to add SendTargets text key");		exit(1);	}	text.ttt = ISCSI_RSVD_TASK_TAG;	text.flags = ISCSI_FLAG_FINAL;	if (++session->itt == ISCSI_RSVD_TASK_TAG)		session->itt = 1;	if (!iscsi_send_pdu(session, pdu, ISCSI_DIGEST_NONE, data,			    ISCSI_DIGEST_NONE, session->active_timeout)) {		logmsg(AS_ERROR, "failed to send SendTargets PDU");		return 0;	}	return 1;}static intiterate_targets(struct iscsi_session *session, uint32_t ttt){	char data[64];	struct iscsi_txt_hdr text;	struct iscsi_hdr *pdu = (struct iscsi_hdr *) &text;	memset(&text, 0, sizeof (text));	memset(data, 0, sizeof (data));	/* make an empty text PDU */	if (!iscsi_make_text_pdu(session, pdu, data, sizeof (data))) {		logmsg(AS_ERROR, "failed to make an empty text PDU");		return 0;	}	text.ttt = ttt;	text.flags = ISCSI_FLAG_FINAL;	if (++session->itt == ISCSI_RSVD_TASK_TAG)		session->itt = 1;	if (!iscsi_send_pdu(session, pdu, ISCSI_DIGEST_NONE, data,			    ISCSI_DIGEST_NONE, session->active_timeout)) {		logmsg(AS_ERROR, "failed to send empty text PDU");		return 0;	}	return 1;}/* try to reset the session's IP address and port, based on the TargetAddress  * provided  */intiscsi_update_address(struct iscsi_session *session, char *address){	char *port;	char *tag;	struct hostent *hostn = NULL;	if ((tag = strrchr(address, ','))) {		*tag = '\0';		tag++;	}	if ((port = strrchr(address, ':'))) {		*port = '\0';		port++;	}	do {		hostn = gethostbyname(address);		if (hostn == NULL) {			errormsg("cannot resolve host name %s", address);			sleep(1);		}		if (iscsi_process_should_exit())			return 0;	} while (!hostn);	memcpy(session->ip_address, hostn->h_addr,	       MIN(sizeof (session->ip_address), hostn->h_length));	session->ip_length = hostn->h_length;	if (port) {		session->port = atoi(port);	} else {		session->port = ISCSI_LISTEN_PORT;	}	return 1;}intadd_portal(struct string_buffer *info, char *address, char *port, char *tag){	struct hostent *hostn = NULL;	/* resolve the address, in case it was a DNS name */	do {		hostn = gethostbyname(address);		if (!hostn) {			errormsg("cannot resolve %s", address);			sleep(1);		}		if (iscsi_process_should_exit())			return 0;	} while (!hostn);	/* convert the resolved name to text */	if (hostn->h_length == 4) {		struct in_addr addr;		memcpy(&addr, hostn->h_addr, sizeof (addr));		if (tag && *tag) {			if (!append_sprintf(info, "TT=%s\n", tag)) {				logmsg(AS_ERROR, "couldn't add portal tag %s",				       tag);				return 0;			}		}		if (port && *port) {			if (!append_sprintf(info, "TP=%s\n", port)) {				logmsg(AS_ERROR, "couldn't add port %s", port);				return 0;			}		}		if (strcmp(inet_ntoa(addr), address)) {			/* if the resolved name doesn't match the original, 			 * send an RA line as well as a TA line 			 */			return append_sprintf(info, "RA=%s\nTA=%s\n",					      inet_ntoa(addr), address);		} else {			/* don't need the RA line */			return append_sprintf(info, "TA=%s\n", address);		}	} else {		/* FIXME: IPv6 */		logmsg(AS_ERROR, "can't handle network address %s", address);		return 0;	}}intadd_target_record(struct string_buffer *info, char *name, char *end,		  int lun_inventory_changed, char *default_address,		  char *default_port, int fd){	char *text = NULL;	char *nul = name;	size_t length;	size_t original = data_length(info);	/* address = IPv4	 * address = [IPv6]	 * address = DNSname	 * address = IPv4:port	 * address = [IPv6]:port	 * address = DNSname:port	 * address = IPv4,tag	 * address = [IPv6],tag	 * address = DNSname,tag	 * address = IPv4:port,tag	 * address = [IPv6]:port,tag	 * address = DNSname:port,tag	 */	debugmsg(7, "adding target record %p, end %p", name, end);	/* find the end of the name */	while ((nul < end) && (*nul != '\0'))		nul++;	length = nul - name;	if (length > TARGET_NAME_MAXLEN) {		logmsg(AS_ERROR, "TargetName %s too long, ignoring", name);		return 0;	}	if (!record_begin) {		if (!append_sprintf		    (info, lun_inventory_changed ? "DLC=%s\n" : "DTN=%s\n",		     name)) {			logmsg(AS_ERROR, "couldn't report target %s", name);			truncate_buffer(info, original);			return 0;		}		record_begin = 1;	} else {		if (!append_sprintf		    (info, lun_inventory_changed ? "LC=%s\n" : "TN=%s\n",		     name)) {			logmsg(AS_ERROR, "couldn't report target %s", name);			truncate_buffer(info, original);			return 0;		}	}	text = name + length;	/* skip NULs after the name */	while ((text < end) && (*text == '\0'))		text++;	/* if no address is provided, use the default */	if (text >= end) {		if (default_address == NULL) {			logmsg(AS_ERROR,			       "no default address known for target %s", name);			truncate_buffer(info, original);			return 0;		} else		    if (!add_portal(info, default_address, default_port, NULL))		{			logmsg(AS_ERROR,			       "failed to add default portal, ignoring "			       "target %s", name);			truncate_buffer(info, original);			return 0;		} else if (!append_string(info, ";\n")) {			logmsg(AS_ERROR,			       "failed to terminate target record, "			       "ignoring target %s", name);			truncate_buffer(info, original);			return 0;		}		/* finished adding the default */		return 1;	}	/* process TargetAddresses */	while (text < end) {		char *next = text + strlen(text) + 1;		debugmsg(7, "text %p, next %p, end %p, %s", text, next, end,			 text);		if (strncmp(text, "TargetAddress=", 14) == 0) {			char *port = NULL;			char *tag = NULL;			char *address = text + 14;			/* FIXME: handle IPv6 */			if (address[0] == '[') {				/* This is an IPv6 numeric address; skip it */				text = next;				continue;			}			if ((tag = strrchr(text, ','))) {				*tag = '\0';				tag++;			}			if ((port = strrchr(text, ':'))) {				*port = '\0';				port++;			}			if (!add_portal(info, address, port, tag)) {				logmsg(AS_ERROR,				       "failed to add default portal, "				       "ignoring target %s", name);				truncate_buffer(info, original);				return 0;			}		} else {			logmsg(AS_ERROR, "unexpected SendTargets data: %s",			       text);		}		text = next;	}	/* indicate the end of the target record */	if (!append_string(info, ";\n")) {		logmsg(AS_ERROR,		       "failed to terminate target record, ignoring target %s",		       name);		truncate_buffer(info, original);		return 0;	}	return 1;}static intprocess_sendtargets_response(struct string_buffer *sendtargets,			     struct string_buffer *info, int final,			     int lun_inventory_changed, char *default_address,			     char *default_port, int fd){	char *start = buffer_data(sendtargets);	char *text = start;	char *end = text + data_length(sendtargets);	char *nul = end - 1;	char *record = NULL;	int num_targets = 0;	size_t valid_info = 0;	if (start == end) {		/* no SendTargets data */		goto done;	}	/* scan backwards to find the last NUL in the data, to ensure we	 * don't walk off the end.  Since key=value pairs can span PDU	 * boundaries, we're not guaranteed that the end of the data has a	 * NUL.	 */	while ((nul > start) && *nul)		nul--;	if (nul == start) {		/* couldn't find anything we can process now, 		 * it's one big partial string 		 */		goto done;	}	/* find the boundaries between target records (TargetName or final PDU) 	 */	for (;;) {		/* skip NULs */		while ((text < nul) && (*text == '\0'))			text++;		if (text == nul)			break;		debugmsg(7,			 "processing sendtargets record %p, text %p, line %s",			 record, text, text);		/* look for the start of a new target record */		if (strncmp(text, "TargetName=", 11) == 0) {			if (record) {				/* send the last record, which we just found 				 * the end of. don't bother passing the 				 * "TargetName=" prefix.				 */				if (!add_target_record				    (info, record + 11, text,				     lun_inventory_changed, default_address,				     default_port, fd)) {					logmsg(AS_ERROR,					       "failed to add target record");					truncate_buffer(sendtargets, 0);					truncate_buffer(info, valid_info);					goto done;				}				num_targets++;				valid_info = data_length(info);			}			record = text;		}		/* everything up til the next NUL must be part of the 

⌨️ 快捷键说明

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