Blame usr/iscsid_req.c

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