Blame usr/iscsid_req.c

Packit Service 646995
/*
Packit Service 646995
 * iscsid communication helpers
Packit Service 646995
 *
Packit Service 646995
 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
Packit Service 646995
 * Copyright (C) 2006 - 2010 Mike Christie
Packit Service 646995
 * Copyright (C) 2006 - 2010 Red Hat, Inc. All rights reserved.
Packit Service 646995
 * maintained by open-iscsi@googlegroups.com
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 <stdio.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
#include <stdlib.h>
Packit Service 646995
#include <string.h>
Packit Service 646995
#include <errno.h>
Packit Service 646995
#include <fcntl.h>
Packit Service 646995
#include <sys/un.h>
Packit Service 646995
#include <poll.h>
Packit Service 646995
#include <sys/types.h>
Packit Service 646995
#include <sys/socket.h>
Packit Service 646995
Packit Service 646995
#include "initiator.h"
Packit Service 646995
#include "log.h"
Packit Service 646995
#include "mgmt_ipc.h"
Packit Service 646995
#include "iscsi_util.h"
Packit Service 646995
#include "config.h"
Packit Service 646995
#include "iscsi_err.h"
Packit Service 646995
#include "iscsid_req.h"
Packit Service 646995
#include "uip_mgmt_ipc.h"
Packit Service 646995
Packit Service 646995
static void iscsid_startup(void)
Packit Service 646995
{
Packit Service 646995
	char *startup_cmd;
Packit Service 646995
Packit Service 646995
	startup_cmd = cfg_get_string_param(CONFIG_FILE, "iscsid.startup");
Packit Service 646995
	if (!startup_cmd) {
Packit Service 646995
		log_error("iscsid is not running. Could not start it up "
Packit Service 646995
			  "automatically using the startup command in the "
Packit Service 646995
			  "/etc/iscsi/iscsid.conf iscsid.startup setting. "
Packit Service 646995
			  "Please check that the file exists or that your "
Packit Service 646995
			  "init scripts have started iscsid.");
Packit Service 646995
		return;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (system(startup_cmd) < 0)
Packit Service 646995
		log_error("Could not execute '%s' (err %d)",
Packit Service 646995
			  startup_cmd, errno);
Packit Service 646995
Packit Service 646995
	free(startup_cmd);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#define MAXSLEEP 128
Packit Service 646995
Packit Service 646995
static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid)
Packit Service 646995
{
Packit Service 646995
	int nsec, addr_len;
Packit Service 646995
	struct sockaddr_un addr;
Packit Service 646995
Packit Service 646995
	*fd = socket(AF_LOCAL, SOCK_STREAM, 0);
Packit Service 646995
	if (*fd < 0) {
Packit Service 646995
		log_error("can not create IPC socket (%d)!", errno);
Packit Service 646995
		return ISCSI_ERR_ISCSID_NOTCONN;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	addr_len = setup_abstract_addr(&addr, unix_sock_name);
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Trying to connect with exponential backoff
Packit Service 646995
	 */
Packit Service 646995
	for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
Packit Service 646995
		if (connect(*fd, (struct sockaddr *) &addr, addr_len) == 0)
Packit Service 646995
			/* Connection established */
Packit Service 646995
			return ISCSI_SUCCESS;
Packit Service 646995
Packit Service 646995
		/* If iscsid isn't there, there's no sense
Packit Service 646995
		 * in retrying. */
Packit Service 646995
		if (errno == ECONNREFUSED) {
Packit Service 646995
			if (start_iscsid && nsec == 1)
Packit Service 646995
				iscsid_startup();
Packit Service 646995
			else
Packit Service 646995
				break;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		/*
Packit Service 646995
		 * Delay before trying again
Packit Service 646995
		 */
Packit Service 646995
		if (nsec <= MAXSLEEP/2)
Packit Service 646995
			sleep(nsec);
Packit Service 646995
	}
Packit Service 646995
	close(*fd);
Packit Service 646995
	*fd = -1;
Packit Service 646995
	log_error("can not connect to iSCSI daemon (%d)!", errno);
Packit Service 646995
	return ISCSI_ERR_ISCSID_NOTCONN;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
char iscsid_namespace[64] = ISCSIADM_NAMESPACE;
Packit Service 646995
Packit Service 646995
void iscsid_set_namespace(pid_t pid) {
Packit Service 646995
	if (pid) {
Packit Service 646995
		snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE "-%d", pid);
Packit Service 646995
	} else {
Packit Service 646995
		snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE);
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int iscsid_connect(int *fd, int start_iscsid)
Packit Service 646995
{
Packit Service 646995
	return ipc_connect(fd, iscsid_namespace, start_iscsid);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
Packit Service 646995
{
Packit Service 646995
	int err;
Packit Service 646995
Packit Service 646995
	err = iscsid_connect(fd, start_iscsid);
Packit Service 646995
	if (err)
Packit Service 646995
		return err;
Packit Service 646995
Packit Service 646995
	if ((err = write(*fd, req, sizeof(*req))) != sizeof(*req)) {
Packit Service 646995
		log_error("got write error (%d/%d) on cmd %d, daemon died?",
Packit Service 646995
			err, errno, req->command);
Packit Service 646995
		close(*fd);
Packit Service 646995
		return ISCSI_ERR_ISCSID_COMM_ERR;
Packit Service 646995
	}
Packit Service 646995
	return ISCSI_SUCCESS;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp,
Packit Service 646995
		    int timeout)
Packit Service 646995
{
Packit Service 646995
	size_t len = sizeof(*rsp);
Packit Service 646995
	int iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
Packit Service 646995
	int err;
Packit Service 646995
	int poll_wait = 0;
Packit Service 646995
Packit Service 646995
	if (timeout == -1) {
Packit Service 646995
		timeout = ISCSID_REQ_TIMEOUT;
Packit Service 646995
		poll_wait = 1;
Packit Service 646995
	}
Packit Service 646995
	while (len) {
Packit Service 646995
		struct pollfd pfd;
Packit Service 646995
Packit Service 646995
		pfd.fd = fd;
Packit Service 646995
		pfd.events = POLLIN;
Packit Service 646995
		err = poll(&pfd, 1, timeout);
Packit Service 646995
		if (!err) {
Packit Service 646995
			if (poll_wait)
Packit Service 646995
				continue;
Packit Service 646995
			return ISCSI_ERR_ISCSID_NOTCONN;
Packit Service 646995
		} else if (err < 0) {
Packit Service 646995
			if (errno == EINTR)
Packit Service 646995
				continue;
Packit Service 646995
			log_error("got poll error (%d/%d), daemon died?",
Packit Service 646995
				  err, errno);
Packit Service 646995
			return ISCSI_ERR_ISCSID_COMM_ERR;
Packit Service 646995
		} else if (pfd.revents & POLLIN) {
Packit Service 646995
			err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL);
Packit Service 646995
			if (err < 0) {
Packit Service 646995
				log_error("read error (%d/%d), daemon died?",
Packit Service 646995
					  err, errno);
Packit Service 646995
				break;
Packit Service 646995
			}
Packit Service 646995
			len -= err;
Packit Service 646995
			iscsi_err = rsp->err;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
	close(fd);
Packit Service 646995
Packit Service 646995
	if (!iscsi_err && cmd != rsp->command)
Packit Service 646995
		iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
Packit Service 646995
	return iscsi_err;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_exec_req(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
Packit Service 646995
		    int start_iscsid, int tmo)
Packit Service 646995
{
Packit Service 646995
	int fd;
Packit Service 646995
	int err;
Packit Service 646995
Packit Service 646995
	err = iscsid_request(&fd, req, start_iscsid);
Packit Service 646995
	if (err)
Packit Service 646995
		return err;
Packit Service 646995
Packit Service 646995
	return iscsid_response(fd, req->command, rsp, tmo);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
Packit Service 646995
{
Packit Service 646995
	iscsiadm_rsp_t rsp;
Packit Service 646995
Packit Service 646995
	memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
Packit Service 646995
	return iscsid_response(fd, cmd, &rsp, -1);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
Packit Service 646995
{
Packit Service 646995
	iscsiadm_req_t req;
Packit Service 646995
Packit Service 646995
	memset(&req, 0, sizeof(iscsiadm_req_t));
Packit Service 646995
	req.command = cmd;
Packit Service 646995
	memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
Packit Service 646995
Packit Service 646995
	return iscsid_request(fd, &req, 1);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec)
Packit Service 646995
{
Packit Service 646995
	int err, fd;
Packit Service 646995
Packit Service 646995
	err = iscsid_req_by_rec_async(cmd, rec, &fd;;
Packit Service 646995
	if (err)
Packit Service 646995
		return err;
Packit Service 646995
	return iscsid_req_wait(cmd, fd);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd)
Packit Service 646995
{
Packit Service 646995
	iscsiadm_req_t req;
Packit Service 646995
Packit Service 646995
	memset(&req, 0, sizeof(iscsiadm_req_t));
Packit Service 646995
	req.command = cmd;
Packit Service 646995
	req.u.session.sid = sid;
Packit Service 646995
Packit Service 646995
	return iscsid_request(fd, &req, 1);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
Packit Service 646995
{
Packit Service 646995
	int err, fd;
Packit Service 646995
Packit Service 646995
	err = iscsid_req_by_sid_async(cmd, sid, &fd;;
Packit Service 646995
	if (err)
Packit Service 646995
		return err;
Packit Service 646995
	return iscsid_req_wait(cmd, fd);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int uip_connect(int *fd)
Packit Service 646995
{
Packit Service 646995
	return ipc_connect(fd, ISCSID_UIP_NAMESPACE, 0);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int uip_broadcast(void *buf, size_t buf_len, int fd_flags, uint32_t *status)
Packit Service 646995
{
Packit Service 646995
	int err;
Packit Service 646995
	int fd;
Packit Service 646995
	iscsid_uip_rsp_t rsp;
Packit Service 646995
	int flags;
Packit Service 646995
	int count;
Packit Service 646995
	size_t write_res;
Packit Service 646995
	
Packit Service 646995
	err = uip_connect(&fd;;
Packit Service 646995
	if (err) {
Packit Service 646995
		log_warning("uIP daemon is not up");
Packit Service 646995
		return err;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(3, "connected to uIP daemon");
Packit Service 646995
Packit Service 646995
	/*  Send the data to uIP */
Packit Service 646995
	write_res = write(fd, buf, buf_len);
Packit Service 646995
	if (write_res != buf_len) {
Packit Service 646995
		log_error("got write error (%d/%d), daemon died?",
Packit Service 646995
			  (int)write_res, errno);
Packit Service 646995
		close(fd);
Packit Service 646995
		return ISCSI_ERR_ISCSID_COMM_ERR;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(3, "send iface config to uIP daemon");
Packit Service 646995
Packit Service 646995
	/*  Set the socket to a non-blocking read, this way if there are
Packit Service 646995
	 *  problems waiting for uIP, iscsid can bailout early */
Packit Service 646995
	flags = fcntl(fd, F_GETFL, 0);
Packit Service 646995
	if (flags == -1)
Packit Service 646995
		flags = 0;
Packit Service 646995
Packit Service 646995
	if (fd_flags)
Packit Service 646995
		flags |= fd_flags;
Packit Service 646995
Packit Service 646995
	err = fcntl(fd, F_SETFL, flags);
Packit Service 646995
	if (err) {
Packit Service 646995
		log_error("could not set uip broadcast to non-blocking: %d",
Packit Service 646995
			  errno);
Packit Service 646995
		close(fd);
Packit Service 646995
		return ISCSI_ERR;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
#define MAX_UIP_BROADCAST_READ_TRIES 5
Packit Service 646995
	for (count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) {
Packit Service 646995
		/*  Wait for the response */
Packit Service 646995
		err = read(fd, &rsp, sizeof(rsp));
Packit Service 646995
		if (err == sizeof(rsp)) {
Packit Service 646995
			log_debug(3, "Broadcasted to uIP with length: %zu cmd: 0x%x rsp: 0x%x",
Packit Service 646995
				  buf_len, rsp.command, rsp.err);
Packit Service 646995
			err = 0;
Packit Service 646995
			break;
Packit Service 646995
		} else if ((err == -1) && (errno == EAGAIN)) {
Packit Service 646995
			usleep(1000000);
Packit Service 646995
			continue;
Packit Service 646995
		} else {
Packit Service 646995
			log_error("Could not read response (%d/%d), daemon "
Packit Service 646995
				  "died?", err, errno);
Packit Service 646995
			err = ISCSI_ERR;
Packit Service 646995
			break;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (count == MAX_UIP_BROADCAST_READ_TRIES) {
Packit Service 646995
		log_error("Could not broadcast to uIP after %d tries",
Packit Service 646995
			  count);
Packit Service 646995
		err = ISCSI_ERR_AGAIN;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (err)
Packit Service 646995
		goto done;
Packit Service 646995
Packit Service 646995
	switch (rsp.command) {
Packit Service 646995
	case ISCSID_UIP_IPC_GET_IFACE:
Packit Service 646995
		if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) {
Packit Service 646995
			log_debug(3, "Device is not ready\n");
Packit Service 646995
			err = ISCSI_ERR_AGAIN;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		break;
Packit Service 646995
	case ISCSID_UIP_IPC_PING:
Packit Service 646995
		*status = rsp.ping_sc;
Packit Service 646995
		if (rsp.err == ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING) {
Packit Service 646995
			log_debug(3, "Device is not ready\n");
Packit Service 646995
			err = ISCSI_ERR_AGAIN;
Packit Service 646995
		} else if (*status) {
Packit Service 646995
			err = ISCSI_ERR;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		break;
Packit Service 646995
	default:
Packit Service 646995
		err = ISCSI_ERR;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
done:
Packit Service 646995
	close(fd);
Packit Service 646995
	return err;
Packit Service 646995
}