/* called when an inotify event is received */
static void process_inotify(int fd)
{
	int bytes;
	/* union to avoid strict-aliasing problems */
	union {
		char buffer[256];  /* a tad large */
		struct inotify_event event;
	} eventbuf;

	bytes = read(fd, &eventbuf.buffer, sizeof(eventbuf.buffer));

	acpid_log(LOG_DEBUG, "inotify read bytes: %d", bytes);

	/* eof is not expected */	
	if (bytes == 0) {
		acpid_log(LOG_WARNING, "inotify fd eof encountered");
		return;
	}
	else if (bytes < 0) {
		/* EINVAL means buffer wasn't big enough.  See inotify(7). */
		acpid_log(LOG_ERR, "inotify read error: %s (%d)",
			strerror(errno), errno);
		acpid_log(LOG_ERR, "disconnecting from inotify");
		delete_connection(fd);
		return;
	}

	acpid_log(LOG_DEBUG, "inotify name len: %d", eventbuf.event.len);

	const int dnsize = 256;
	char devname[dnsize];

	/* if a name is included */
	if (eventbuf.event.len > 0) {
		/* devname = ACPID_INPUTLAYERDIR + "/" + pevent -> name */
		strcpy(devname, ACPID_INPUTLAYERDIR);
		strcat(devname, "/");
		strncat(devname, eventbuf.event.name, dnsize - strlen(devname) - 1);
	}
		
	/* if this is a create */
	if (eventbuf.event.mask & IN_CREATE) {
		acpid_log(LOG_DEBUG, "inotify about to open: %s", devname);

		open_inputfile(devname);
	}

	/* if this is a delete */
	if (eventbuf.event.mask & IN_DELETE) {
		/* struct connection *c; */
		
		acpid_log(LOG_DEBUG, "inotify received a delete for: %s", devname);

#if 0
/* Switching back to the original ENODEV detection scheme.  See 
   process_input() in input_layer.c. */
/* keeping this for future reference */
		/* search for the event file in the connection list */
		/* ??? Or should we just have a delete_connection_name()? */
		c = find_connection_name(devname);
		
		/* close that connection if found */
		if (c)
			delete_connection(c->fd);
#endif
	}
}
Beispiel #2
0
static connection_t *
make_connection(session_t * sess, iscsid_login_req_t * req,
				iscsid_response_t * res, uint32_t * stid)
{
	connection_t *conn;
	iscsi_login_parameters_t loginp;
	int sock;
	int ret;
	int yes = 1;
	target_t *target;
	portal_t *portal = NULL;
	iscsi_portal_address_t *addr;
	struct sockaddr_in serverAddress;
	struct hostent *host;
	initiator_t *init;

	DEB(9, ("Make Connection sess=%p, req=%p, res=%p, stid=%p\n",
			 sess, req, res, stid));
	(void) memset(&loginp, 0x0, sizeof(loginp));
	(void) memset(&serverAddress, 0x0, sizeof(serverAddress));

	/* find the target portal */
	if (stid != NULL) {
		send_target_t *starget;

		if ((starget = find_send_target_id(*stid)) == NULL) {
			res->status = ISCSID_STATUS_INVALID_TARGET_ID;
			return NULL;
		}
		addr = &starget->addr;
		target = (target_t *)(void *)starget;
	} else {
		if (NO_ID(&req->portal_id)
			|| (portal = find_portal(&req->portal_id)) == NULL) {
			portal_group_t *group;

			/* if no ID was specified, use target from existing session */
			if (NO_ID(&req->portal_id)) {
				if (!sess->num_connections ||
					((target = find_target_id(TARGET_LIST,
					sess->target.sid.id)) == NULL)) {
					res->status = ISCSID_STATUS_INVALID_PORTAL_ID;
					return NULL;
				}
			}
			/* if a target was given instead, use it */
			else if ((target =
							  find_target(TARGET_LIST, &req->portal_id)) == NULL) {
				res->status = ISCSID_STATUS_INVALID_PORTAL_ID;
				return NULL;
			}
			/* now get from target to portal - if this is the first connection, */
			/* just use the first portal group. */
			if (!sess->num_connections) {
				group = TAILQ_FIRST(&target->group_list);
			}
			/* if it's a second connection, use an available portal in the same */
			/* portal group */
			else {
				conn = (connection_t *)(void *)
				    TAILQ_FIRST(&sess->connections);

				if (conn == NULL ||
					(portal = find_portal_id(conn->portal.sid.id)) == NULL) {
					res->status = ISCSID_STATUS_INVALID_PORTAL_ID;
					return NULL;
				}
				group = portal->group;
			}

			if ((portal = find_free_portal(group)) == NULL) {
				res->status = ISCSID_STATUS_INVALID_PORTAL_ID;
				return NULL;
			}
			DEB(1, ("find_free_portal returns pid=%d\n", portal->entry.sid.id));
		} else
			target = portal->target;

		addr = &portal->addr;

		/* symbolic name for connection? check for duplicates */
		if (req->sym_name[0]) {
			void *p;

			if (sess->num_connections)
				p = find_connection_name(sess, req->sym_name);
			else
				p = find_session_name(req->sym_name);
			if (p) {
				res->status = ISCSID_STATUS_DUPLICATE_NAME;
				return NULL;
			}
		}
	}

	if (req != NULL && !NO_ID(&req->initiator_id)) {
		if ((init = find_initiator(&req->initiator_id)) == NULL) {
			res->status = ISCSID_STATUS_INVALID_INITIATOR_ID;
			return NULL;
		}
	} else
		init = select_initiator();

	/* translate target address */
	DEB(8, ("Connecting to <%s>, port %d\n", addr->address, addr->port));

	host = gethostbyname((char *)addr->address);
	if (host == NULL) {
		switch (h_errno) {
		case HOST_NOT_FOUND:
			res->status = ISCSID_STATUS_HOST_NOT_FOUND;
			break;
		case TRY_AGAIN:
			res->status = ISCSID_STATUS_HOST_TRY_AGAIN;
			break;
		default:
			res->status = ISCSID_STATUS_HOST_ERROR;
			break;
		}
		return NULL;
	}
	if (host->h_length > (int)sizeof(serverAddress.sin_addr)) {
		res->status = ISCSID_STATUS_HOST_ERROR;
		return NULL;
	}
	DEB(8, ("Gethostbyname OK, addrtype %d, len %d, addr %x\n",
			host->h_addrtype, host->h_length, *((int *) host->h_addr_list[0])));
	serverAddress.sin_family = host->h_addrtype;
	serverAddress.sin_port = htons((addr->port)
		? addr->port : ISCSI_DEFAULT_PORT);
	serverAddress.sin_len = host->h_length;
	memcpy(&serverAddress.sin_addr, host->h_addr_list[0], host->h_length);

	/* alloc the connection structure */
	conn = calloc(1, sizeof(*conn));
	if (conn == NULL) {
		res->status = ISCSID_STATUS_NO_RESOURCES;
		return NULL;
	}
	/* create and connect the socket */
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		free(conn);
		res->status = ISCSID_STATUS_SOCKET_ERROR;
		return NULL;
	}

	if (init) {
		if (!bind_socket(sock, init->address)) {
			close(sock);
			free(conn);
			res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR;
			return NULL;
		}
	}

	DEB(8, ("Connecting socket\n"));
	if (connect(sock, (struct sockaddr *)(void *)&serverAddress,
		(socklen_t)sizeof(serverAddress)) < 0) {
		close(sock);
		free(conn);
		res->status = ISCSID_STATUS_CONNECT_ERROR;
		DEB(1, ("Connecting to socket failed (error %d), returning %d\n",
				errno, res->status));
		return NULL;
	}
	/* speed up socket processing */
	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes));

	/* setup login parameter structure */
	loginp.socket = sock;
	if (target->TargetName[0]) {
		loginp.is_present.TargetName = 1;
		loginp.TargetName = target->TargetName;
	}
	if (target->options.is_present.MaxConnections) {
		loginp.is_present.MaxConnections = 1;
		loginp.MaxConnections = target->options.MaxConnections;
	}
	if (target->options.is_present.DataDigest) {
		loginp.is_present.DataDigest = 1;
		loginp.DataDigest = target->options.DataDigest;
	}
	if (target->options.is_present.HeaderDigest) {
		loginp.is_present.HeaderDigest = 1;
		loginp.HeaderDigest = target->options.HeaderDigest;
	}
	if (target->options.is_present.DefaultTime2Retain) {
		loginp.is_present.DefaultTime2Retain = 1;
		loginp.DefaultTime2Retain = target->options.DefaultTime2Retain;
	}
	if (target->options.is_present.DefaultTime2Wait) {
		loginp.is_present.DefaultTime2Wait = 1;
		loginp.DefaultTime2Wait = target->options.DefaultTime2Wait;
	}
	if (target->options.is_present.ErrorRecoveryLevel) {
		loginp.is_present.ErrorRecoveryLevel = 1;
		loginp.ErrorRecoveryLevel = target->options.ErrorRecoveryLevel;
	}
	if (target->options.is_present.MaxRecvDataSegmentLength) {
		loginp.is_present.MaxRecvDataSegmentLength = 1;
		loginp.MaxRecvDataSegmentLength =
			target->options.MaxRecvDataSegmentLength;
	}
	if (target->auth.auth_info.auth_number) {
		loginp.is_present.auth_info = 1;
		loginp.auth_info = target->auth.auth_info;
		if (target->auth.password[0]) {
			loginp.is_present.password = 1;
			loginp.password = target->auth.password;
		}
		if (target->auth.target_password[0]) {
			loginp.is_present.target_password = 1;
			loginp.target_password = target->auth.target_password;
		}
		if (target->auth.user_name[0]) {
			loginp.is_present.user_name = 1;
			loginp.user_name = target->auth.user_name;
		}
	}
	loginp.is_present.TargetAlias = 1;
	loginp.TargetAlias = target->TargetAlias;

	if (portal != NULL) {
		/* override general target options with portal options (if specified) */
		if (portal->options.is_present.DataDigest) {
			loginp.is_present.DataDigest = 1;
			loginp.DataDigest = portal->options.DataDigest;
		}
		if (portal->options.is_present.HeaderDigest) {
			loginp.is_present.HeaderDigest = 1;
			loginp.HeaderDigest = portal->options.HeaderDigest;
		}
		if (portal->options.is_present.MaxRecvDataSegmentLength) {
			loginp.is_present.MaxRecvDataSegmentLength = 1;
			loginp.MaxRecvDataSegmentLength =
				portal->options.MaxRecvDataSegmentLength;
		}
	}

	if (req != NULL) {
		loginp.session_id = get_id(&list[SESSION_LIST].list, &req->session_id);
		loginp.login_type = req->login_type;
	} else
		loginp.login_type = ISCSI_LOGINTYPE_DISCOVERY;

	DEB(5, ("Calling Login...\n"));

	ret = ioctl(driver, (sess != NULL && sess->num_connections)
				? ISCSI_ADD_CONNECTION : ISCSI_LOGIN, &loginp);

	res->status = loginp.status;

	if (ret)
		close(sock);

	if (ret || loginp.status) {
		free(conn);
		if (!res->status)
			res->status = ISCSID_STATUS_GENERAL_ERROR;
		return NULL;
	}
	/* connection established! link connection into session and return IDs */

	conn->loginp = loginp;
	conn->entry.sid.id = loginp.connection_id;
	if (req != NULL) {
		strlcpy((char *)conn->entry.sid.name, (char *)req->sym_name,
			sizeof(conn->entry.sid.name));
	}

	/*
	   Copy important target information
	 */
	conn->target.sid = target->entry.sid;
	strlcpy((char *)conn->target.TargetName, (char *)target->TargetName,
		sizeof(conn->target.TargetName));
	strlcpy((char *)conn->target.TargetAlias, (char *)target->TargetAlias,
		sizeof(conn->target.TargetAlias));
	conn->target.options = target->options;
	conn->target.auth = target->auth;
	conn->portal.addr = *addr;

	conn->session = sess;

	if (stid == NULL) {
		iscsid_login_rsp_t *rsp = (iscsid_login_rsp_t *)(void *)
		    res->parameter;

		sess->entry.sid.id = loginp.session_id;
		TAILQ_INSERT_TAIL(&sess->connections, &conn->entry, link);
		sess->num_connections++;

		res->parameter_length = sizeof(*rsp);
		rsp->connection_id = conn->entry.sid;
		rsp->session_id = sess->entry.sid;

		if (init != NULL) {
			conn->initiator_id = init->entry.sid.id;
			init->active_connections++;
		}
	} else
		*stid = loginp.session_id;

	/*
	   Copy important portal information
	 */
	if (portal != NULL) {
		conn->portal.sid = portal->entry.sid;
		portal->active_connections++;
	}

	return conn;
}