677 lines
17 KiB
C
677 lines
17 KiB
C
/* $NetBSD: iscsid_main.c,v 1.12 2019/02/04 08:21:12 mrg Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Wasabi Systems, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "iscsid_globals.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <syslog.h>
|
|
#include <util.h>
|
|
|
|
#define DEVICE "/dev/iscsi0"
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
list_head_t list[NUM_DAEMON_LISTS]; /* the lists this daemon keeps */
|
|
|
|
pthread_mutex_t sesslist_lock; /* session list lock */
|
|
pthread_t main_thread; /* main thread handle */
|
|
pthread_t event_thread; /* event thread handle */
|
|
|
|
int driver = -1; /* the driver's file desc */
|
|
int client_sock; /* the client communication socket */
|
|
|
|
int debug_level; /* How much info to display */
|
|
int debugging;
|
|
|
|
/*
|
|
To avoid memory fragmentation (and speed things up a bit), we use the
|
|
static bufs unless the request or response exceeds the buffer size
|
|
(which it normally shouldn't, assuming we don't have thousands
|
|
of list entries).
|
|
*/
|
|
static uint8_t req_buf[REQ_BUFFER_SIZE]; /* default buffer for requests */
|
|
static uint8_t rsp_buf[RSP_BUFFER_SIZE]; /* default buffer for responses */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
static void __dead
|
|
usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/*
|
|
* create_node_name:
|
|
* Create and set default node name.
|
|
*
|
|
* Returns 0 on success, else an error code.
|
|
*/
|
|
|
|
static int
|
|
create_node_name(void)
|
|
{
|
|
iscsi_set_node_name_parameters_t snp;
|
|
uint32_t hid = 0;
|
|
size_t siz;
|
|
int mib[2];
|
|
int total;
|
|
unsigned char *s;
|
|
|
|
(void) memset(&snp, 0x0, sizeof(snp));
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = KERN_HOSTID;
|
|
siz = sizeof(hid);
|
|
sysctl(mib, 2, &hid, &siz, NULL, 0);
|
|
mib[1] = KERN_HOSTNAME;
|
|
siz = ISCSI_STRING_LENGTH - 45;
|
|
sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0);
|
|
|
|
DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid));
|
|
if (!snp.InitiatorAlias[0]) {
|
|
printf("Warning: iSCSI Node Name not set (No Host Name)!\n");
|
|
return ISCSID_STATUS_NO_INITIATOR_NAME;
|
|
}
|
|
for (s = snp.InitiatorAlias; *s; s++)
|
|
if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':')
|
|
*s = '-';
|
|
total = snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
|
|
"iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
|
|
if ((size_t)total > sizeof(snp.InitiatorName)) {
|
|
printf("Warning: iSCSI Node InitiatorName too long to set InitiatorAlias!\n");
|
|
return ISCSID_STATUS_NO_INITIATOR_NAME;
|
|
}
|
|
|
|
ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
|
|
return snp.status;
|
|
}
|
|
|
|
|
|
/*
|
|
* init_daemon:
|
|
* Open driver, create communication socket.
|
|
*
|
|
* Returns: <0 on error
|
|
*/
|
|
|
|
static int
|
|
init_daemon(void)
|
|
{
|
|
int sock, i;
|
|
struct sockaddr_un name;
|
|
iscsid_request_t req;
|
|
|
|
if ((driver = open(DEVICE, O_RDONLY)) < 0) {
|
|
perror("opening " DEVICE);
|
|
return -1;
|
|
}
|
|
|
|
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
perror("opening datagram socket");
|
|
return -1;
|
|
}
|
|
|
|
name.sun_family = AF_UNIX;
|
|
strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
|
|
|
|
req.request = ISCSID_DAEMON_TEST;
|
|
req.parameter_length = 0;
|
|
|
|
i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
|
|
(socklen_t)sizeof(struct sockaddr_un));
|
|
if (i == sizeof(req)) {
|
|
printf("Daemon already loaded!\n");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
unlink(ISCSID_SOCK_NAME);
|
|
if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
|
|
perror("binding name to socket");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < NUM_DAEMON_LISTS; i++) {
|
|
TAILQ_INIT(&list[i].list);
|
|
list[i].num_entries = 0;
|
|
}
|
|
|
|
if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
|
|
printf("Mutex init failed (%d)\n", i);
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
if (!register_event_handler()) {
|
|
printf("Couldn't register event handler\n");
|
|
close(sock);
|
|
unlink(ISCSID_SOCK_NAME);
|
|
pthread_mutex_destroy(&sesslist_lock);
|
|
return -1;
|
|
}
|
|
|
|
create_node_name();
|
|
|
|
return sock;
|
|
}
|
|
|
|
|
|
/*
|
|
* make_rsp:
|
|
* Allocate a response buffer if the static buffer is insufficient, set
|
|
* the response parameter length.
|
|
*
|
|
* Parameter:
|
|
* len Response parameter size (not counting header)
|
|
* prsp Pointer to address of response buffer
|
|
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
|
|
* for static buffer.
|
|
*
|
|
* Returns: Pointer to response buffer, NULL if allocation failed.
|
|
*/
|
|
|
|
iscsid_response_t *
|
|
make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
|
|
{
|
|
iscsid_response_t *rsp;
|
|
|
|
if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
|
|
if ((rsp = calloc(1, len)) == NULL) {
|
|
(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
|
|
return NULL;
|
|
}
|
|
*prsp_temp = TRUE;
|
|
*prsp = rsp;
|
|
} else
|
|
rsp = *prsp;
|
|
|
|
memset (rsp, 0, len + sizeof(iscsid_response_t));
|
|
rsp->parameter_length = (uint32_t)len;
|
|
return rsp;
|
|
}
|
|
|
|
|
|
/*
|
|
* process_message:
|
|
* minimal parameter check and dispatch for the daemon functions.
|
|
*
|
|
* Parameter:
|
|
* req The request
|
|
* prsp Pointer to address of response buffer
|
|
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
|
|
* for static buffer.
|
|
*/
|
|
|
|
static void
|
|
process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
|
|
{
|
|
iscsid_response_t *rsp;
|
|
void *p = req->parameter;
|
|
|
|
*prsp_temp = FALSE;
|
|
*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
|
|
rsp->parameter_length = 0;
|
|
rsp->status = ISCSID_STATUS_SUCCESS;
|
|
|
|
switch (req->request) {
|
|
case ISCSID_ADD_TARGET:
|
|
if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_ADD_PORTAL:
|
|
if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_SET_TARGET_OPTIONS:
|
|
if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
|
|
break;
|
|
|
|
case ISCSID_GET_TARGET_OPTIONS:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = ISCSID_STATUS_NOTIMPL;
|
|
break;
|
|
|
|
case ISCSID_SET_TARGET_AUTHENTICATION:
|
|
if (req->parameter_length !=
|
|
sizeof(iscsid_set_target_authentication_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
|
|
break;
|
|
|
|
case ISCSID_SLP_FIND_TARGETS:
|
|
rsp->status = ISCSID_STATUS_NOTIMPL;
|
|
break;
|
|
|
|
case ISCSID_REFRESH_TARGETS:
|
|
if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
|
|
break;
|
|
|
|
case ISCSID_REMOVE_TARGET:
|
|
if (req->parameter_length != sizeof(iscsid_list_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = remove_target((iscsid_list_id_t *)p);
|
|
break;
|
|
|
|
case ISCSID_SEARCH_LIST:
|
|
if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_LIST:
|
|
if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_TARGET_INFO:
|
|
if (req->parameter_length != sizeof(iscsid_list_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_PORTAL_INFO:
|
|
if (req->parameter_length != sizeof(iscsid_list_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
#ifndef ISCSI_MINIMAL
|
|
case ISCSID_ADD_ISNS_SERVER:
|
|
if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
add_isns_server((iscsid_add_isns_server_req_t *)p,
|
|
prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_ISNS_SERVER:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_SLP_FIND_ISNS_SERVERS:
|
|
rsp->status = ISCSID_STATUS_NOTIMPL;
|
|
break;
|
|
|
|
case ISCSID_REMOVE_ISNS_SERVER:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
|
|
break;
|
|
#endif
|
|
|
|
case ISCSID_ADD_INITIATOR_PORTAL:
|
|
if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
add_initiator_portal((iscsid_add_initiator_req_t *)p,
|
|
prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_INITIATOR_PORTAL:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_REMOVE_INITIATOR_PORTAL:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
|
|
break;
|
|
|
|
case ISCSID_LOGIN:
|
|
if (req->parameter_length != sizeof(iscsid_login_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
log_in((iscsid_login_req_t *)p, rsp);
|
|
break;
|
|
|
|
case ISCSID_ADD_CONNECTION:
|
|
if (req->parameter_length != sizeof(iscsid_login_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
add_connection((iscsid_login_req_t *)p, rsp);
|
|
break;
|
|
|
|
case ISCSID_LOGOUT:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = log_out((iscsid_sym_id_t *)p);
|
|
break;
|
|
|
|
case ISCSID_REMOVE_CONNECTION:
|
|
if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
|
|
break;
|
|
|
|
case ISCSID_GET_SESSION_LIST:
|
|
get_session_list(prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_CONNECTION_LIST:
|
|
if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_GET_CONNECTION_INFO:
|
|
if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
get_connection_info((iscsid_get_connection_info_req_t *)p,
|
|
prsp, prsp_temp);
|
|
break;
|
|
|
|
case ISCSID_SET_NODE_NAME:
|
|
if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
|
|
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
|
|
break;
|
|
|
|
case ISCSID_GET_VERSION:
|
|
get_version(prsp, prsp_temp);
|
|
break;
|
|
|
|
default:
|
|
rsp->status = ISCSID_STATUS_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
iscsid_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsyslog(LOG_INFO, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/*
|
|
* exit_daemon:
|
|
* Deregister the event handler, deregister isns servers, then exit program.
|
|
*/
|
|
|
|
static void __dead
|
|
exit_daemon(void)
|
|
{
|
|
LOCK_SESSIONS;
|
|
deregister_event_handler();
|
|
|
|
#ifndef ISCSI_MINIMAL
|
|
dereg_all_isns_servers();
|
|
#endif
|
|
exit(0);
|
|
}
|
|
|
|
static void
|
|
handler_exit(void)
|
|
{
|
|
pthread_kill(main_thread, SIGINT);
|
|
}
|
|
|
|
static void
|
|
sighandler(int sig)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* main:
|
|
* init, go daemon, then loop reading requests, processing them,
|
|
* and sending responses.
|
|
* Stops on receiving a terminate message (no response to that one is sent),
|
|
* or when an error occurs reading or writing the socket.
|
|
*
|
|
* Parameter: argc, argv currently ignored.
|
|
*/
|
|
|
|
int
|
|
/*ARGSUSED*/
|
|
main(int argc, char **argv)
|
|
{
|
|
int req_temp, rsp_temp, c;
|
|
ssize_t ret;
|
|
size_t len;
|
|
struct sockaddr_un from;
|
|
socklen_t fromlen;
|
|
iscsid_request_t *req;
|
|
iscsid_response_t *rsp;
|
|
char *p;
|
|
struct sigaction sa;
|
|
|
|
while ((c = getopt(argc, argv, "Dd:")) != -1)
|
|
switch (c) {
|
|
case 'D':
|
|
debugging++;
|
|
break;
|
|
case 'd':
|
|
debug_level=(int)strtol(optarg, &p, 10);
|
|
if (*p)
|
|
errx(EXIT_FAILURE, "illegal log level -- %s",
|
|
optarg);
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON);
|
|
|
|
client_sock = init_daemon();
|
|
if (client_sock < 0)
|
|
exit(1);
|
|
|
|
DEBOUT(("iSCSI daemon loaded"));
|
|
|
|
if (!debugging) {
|
|
if (daemon(0, 1) < 0)
|
|
err(EXIT_FAILURE, "daemon() failed");
|
|
pidfile(NULL);
|
|
}
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
sa.sa_handler = sighandler;
|
|
sigaction(SIGINT, &sa, NULL);
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
|
|
main_thread = pthread_self();
|
|
ret = pthread_create(&event_thread, NULL, event_handler, handler_exit);
|
|
if (ret) {
|
|
printf("Thread creation failed (%zd)\n", ret);
|
|
close(client_sock);
|
|
unlink(ISCSID_SOCK_NAME);
|
|
deregister_event_handler();
|
|
pthread_mutex_destroy(&sesslist_lock);
|
|
return -1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
for (;;) {
|
|
|
|
/* First, get size of request */
|
|
req = (iscsid_request_t *)(void *)req_buf;
|
|
fromlen = sizeof(from);
|
|
len = sizeof(iscsid_request_t);
|
|
|
|
do {
|
|
ret = recvfrom(client_sock, req, len, MSG_PEEK |
|
|
MSG_WAITALL, (struct sockaddr *) &from,
|
|
&fromlen);
|
|
} while (ret == -1 && errno == EAGAIN);
|
|
|
|
if ((size_t)ret != len) {
|
|
DEBOUT(("Receiving from socket: %s",strerror(errno)));
|
|
break;
|
|
}
|
|
DEB(2, ("Request %d, parlen %d",
|
|
req->request, req->parameter_length));
|
|
|
|
len += req->parameter_length;
|
|
|
|
/* now that we know the size, get the buffer for it */
|
|
req_temp = (len > REQ_BUFFER_SIZE);
|
|
|
|
if (req_temp) {
|
|
req = malloc(len);
|
|
if (!req) {
|
|
printf("Can't alloc %zu bytes\n", len);
|
|
break;
|
|
}
|
|
}
|
|
/* read the complete request */
|
|
fromlen = sizeof(from);
|
|
ret = recvfrom(client_sock, req, len, MSG_WAITALL,
|
|
(struct sockaddr *)(void *)&from, &fromlen);
|
|
if ((size_t)ret != len) {
|
|
DEB(2, ("Error receiving from socket!"));
|
|
if (req_temp)
|
|
free(req);
|
|
continue;
|
|
}
|
|
/* terminate? then go die. */
|
|
if (req->request == ISCSID_DAEMON_TERMINATE)
|
|
break;
|
|
|
|
/* No reply required to test message */
|
|
if (req->request == ISCSID_DAEMON_TEST) {
|
|
if (req_temp)
|
|
free(req);
|
|
DEB(2, ("Test message!"));
|
|
continue;
|
|
}
|
|
/* no return path? then we can't send a reply, */
|
|
/* so don't process the command */
|
|
if (!from.sun_path[0]) {
|
|
if (req_temp)
|
|
free(req);
|
|
DEB(2, ("No Return Address!"));
|
|
continue;
|
|
}
|
|
/* process the request */
|
|
process_message(req, &rsp, &rsp_temp);
|
|
if (rsp == NULL) {
|
|
if (req_temp)
|
|
free(req);
|
|
DEB(2, ("Invalid message!"));
|
|
continue;
|
|
}
|
|
|
|
DEB(2, ("Sending reply: status %d, len %d",
|
|
rsp->status, rsp->parameter_length));
|
|
|
|
/* send the response */
|
|
len = sizeof(iscsid_response_t) + rsp->parameter_length;
|
|
ret = sendto(client_sock, rsp, len, 0,
|
|
(struct sockaddr *)(void *)&from, fromlen);
|
|
if (len != (size_t)ret) {
|
|
DEB(2, ("Error sending reply!"));
|
|
}
|
|
/* free temp buffers if we needed them */
|
|
if (req_temp)
|
|
free(req);
|
|
if (rsp_temp)
|
|
free(rsp);
|
|
}
|
|
|
|
pthread_join(event_thread, NULL);
|
|
|
|
DEBOUT(("Exiting daemon"));
|
|
|
|
exit_daemon();
|
|
|
|
/* we never get here */
|
|
return 0;
|
|
}
|