2
* Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com>
4
* Released under the terms of the GNU GPL v2.0.
19
#include <sys/socket.h>
21
#include <sys/types.h>
24
#include <netinet/in.h>
25
#include <netinet/tcp.h>
26
#include <netinet/ip.h>
27
#include <arpa/inet.h>
32
static char* server_address;
33
uint16_t server_port = ISCSI_LISTEN_PORT;
35
struct pollfd poll_array[POLL_MAX];
36
static struct connection *incoming[INCOMING_MAX];
37
static int incoming_cnt;
38
int ctrl_fd, ipc_fd, nl_fd;
40
static char program_name[] = "iscsid";
42
static struct option const long_options[] =
44
{"config", required_argument, 0, 'c'},
45
{"foreground", no_argument, 0, 'f'},
46
{"debug", required_argument, 0, 'd'},
47
{"uid", required_argument, 0, 'u'},
48
{"gid", required_argument, 0, 'g'},
49
{"address", required_argument, 0, 'a'},
50
{"port", required_argument, 0, 'p'},
51
{"version", no_argument, 0, 'v'},
52
{"help", no_argument, 0, 'h'},
56
/* This will be configurable by command line options */
57
extern struct config_operations plain_ops;
58
struct config_operations *cops = &plain_ops;
60
static void usage(int status)
63
fprintf(stderr, "Try `%s --help' for more information.\n", program_name);
65
printf("Usage: %s [OPTION]\n", program_name);
67
iSCSI target daemon.\n\
68
-c, --config=[path] Execute in the config file.\n");
70
-f, --foreground make the program run in the foreground\n\
71
-d, --debug debuglevel print debugging information\n\
72
-u, --uid=uid run as uid, default is current user\n\
73
-g, --gid=gid run as gid, default is current user group\n\
74
-a, --address=address listen on specified local address instead of all\n\
75
-p, --port=port listen on specified port instead of 3260\n\
76
-h, --help display this help and exit\n\
82
static int check_version(void)
84
struct module_info info;
87
memset(&info, 0x0, sizeof(info));
89
err = ki->module_info(&info);
93
return !strncmp(info.version, IET_VERSION_STRING, sizeof(info.version));
96
static void set_non_blocking(int fd)
98
int res = fcntl(fd, F_GETFL);
101
res = fcntl(fd, F_SETFL, res | O_NONBLOCK);
103
log_warning("unable to set fd flags (%s)!", strerror(errno));
105
log_warning("unable to get fd flags (%s)!", strerror(errno));
108
static void create_listen_socket(struct pollfd *array)
110
struct addrinfo hints, *res, *res0;
114
memset(servname, 0, sizeof(servname));
115
snprintf(servname, sizeof(servname), "%d", server_port);
117
memset(&hints, 0, sizeof(hints));
118
hints.ai_socktype = SOCK_STREAM;
119
hints.ai_flags = AI_PASSIVE;
121
if (getaddrinfo(server_address, servname, &hints, &res0)) {
122
log_error("unable to get address info (%s)!",
123
(errno == EAI_SYSTEM) ? strerror(errno) :
124
gai_strerror(errno));
128
for (i = 0, res = res0; res && i < LISTEN_MAX; i++, res = res->ai_next) {
129
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
131
log_error("unable to create server socket (%s) %d %d %d!",
132
strerror(errno), res->ai_family,
133
res->ai_socktype, res->ai_protocol);
138
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt)))
139
log_warning("unable to set SO_KEEPALIVE on server socket (%s)!",
143
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
144
log_warning("unable to set SO_REUSEADDR on server socket (%s)!",
148
if (res->ai_family == AF_INET6 &&
149
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)))
152
if (bind(sock, res->ai_addr, res->ai_addrlen)) {
153
log_error("unable to bind server socket (%s)!", strerror(errno));
157
if (listen(sock, INCOMING_MAX)) {
158
log_error("unable to listen to server socket (%s)!", strerror(errno));
162
set_non_blocking(sock);
165
array[i].events = POLLIN;
171
static void accept_connection(int listen)
173
struct sockaddr_storage from;
175
struct pollfd *pollfd;
176
struct connection *conn;
179
namesize = sizeof(from);
180
if ((fd = accept(listen, (struct sockaddr *) &from, &namesize)) < 0) {
181
if (errno != EINTR && errno != EAGAIN) {
182
perror("accept(incoming_socket)");
188
for (i = 0; i < INCOMING_MAX; i++) {
192
if (i >= INCOMING_MAX) {
193
log_error("unable to find incoming slot? %d\n", i);
197
if (!(conn = conn_alloc())) {
198
log_error("fail to allocate %s", "conn\n");
205
set_non_blocking(fd);
206
pollfd = &poll_array[POLL_INCOMING + i];
208
pollfd->events = POLLIN;
212
if (incoming_cnt >= INCOMING_MAX)
213
poll_array[POLL_LISTEN].events = 0;
216
static void __set_fd(int idx, int fd)
218
poll_array[idx].fd = fd;
219
poll_array[idx].events = fd ? POLLIN : 0;
222
void isns_set_fd(int isns, int scn_listen, int scn)
224
__set_fd(POLL_ISNS, isns);
225
__set_fd(POLL_SCN_LISTEN, scn_listen);
226
__set_fd(POLL_SCN, scn);
229
void event_loop(int timeout)
232
struct connection *conn;
233
struct pollfd *pollfd;
235
create_listen_socket(poll_array + POLL_LISTEN);
237
poll_array[POLL_IPC].fd = ipc_fd;
238
poll_array[POLL_IPC].events = POLLIN;
239
poll_array[POLL_NL].fd = nl_fd;
240
poll_array[POLL_NL].events = POLLIN;
242
for (i = 0; i < INCOMING_MAX; i++) {
243
poll_array[POLL_INCOMING + i].fd = -1;
244
poll_array[POLL_INCOMING + i].events = 0;
249
res = poll(poll_array, POLL_MAX, timeout);
251
isns_handle(1, &timeout);
253
} else if (res < 0) {
254
if (res < 0 && errno != EINTR) {
261
for (i = 0; i < LISTEN_MAX; i++) {
262
if (poll_array[POLL_LISTEN + i].revents
263
&& incoming_cnt < INCOMING_MAX)
264
accept_connection(poll_array[POLL_LISTEN + i].fd);
267
if (poll_array[POLL_NL].revents)
268
handle_iscsi_events(nl_fd);
270
if (poll_array[POLL_IPC].revents)
271
ietadm_request_handle(ipc_fd);
273
if (poll_array[POLL_ISNS].revents)
274
isns_handle(0, &timeout);
276
if (poll_array[POLL_SCN_LISTEN].revents)
279
if (poll_array[POLL_SCN].revents)
282
for (i = 0; i < INCOMING_MAX; i++) {
284
pollfd = &poll_array[POLL_INCOMING + i];
285
if (!conn || !pollfd->revents)
290
switch (conn->iostate) {
291
case IOSTATE_READ_BHS:
292
case IOSTATE_READ_AHS_DATA:
294
res = read(pollfd->fd, conn->buffer, conn->rwsize);
296
if (res == 0 || (errno != EINTR && errno != EAGAIN))
297
conn->state = STATE_CLOSE;
298
else if (errno == EINTR)
307
switch (conn->iostate) {
308
case IOSTATE_READ_BHS:
309
conn->iostate = IOSTATE_READ_AHS_DATA;
310
conn->req.ahssize = conn->req.bhs.ahslength * 4;
311
conn->req.datasize = ((conn->req.bhs.datalength[0] << 16) +
312
(conn->req.bhs.datalength[1] << 8) +
313
conn->req.bhs.datalength[2]);
314
conn->rwsize = (conn->req.ahssize + conn->req.datasize + 3) & -4;
315
if (conn->rwsize > INCOMING_BUFSIZE) {
316
log_warning("Recv PDU with "
321
conn->state = STATE_CLOSE;
325
if (!conn->req_buffer) {
326
conn->req_buffer = malloc(INCOMING_BUFSIZE);
327
if (!conn->req_buffer) {
328
log_error("Failed to alloc recv buffer");
329
conn->state = STATE_CLOSE;
333
conn->buffer = conn->req_buffer;
334
conn->req.ahs = conn->buffer;
335
conn->req.data = conn->buffer + conn->req.ahssize;
339
case IOSTATE_READ_AHS_DATA:
340
conn_write_pdu(conn);
341
pollfd->events = POLLOUT;
343
log_pdu(2, &conn->req);
344
if (!cmnd_execute(conn))
345
conn->state = STATE_CLOSE;
350
case IOSTATE_WRITE_BHS:
351
case IOSTATE_WRITE_AHS:
352
case IOSTATE_WRITE_DATA:
355
setsockopt(pollfd->fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
356
res = write(pollfd->fd, conn->buffer, conn->rwsize);
358
if (errno != EINTR && errno != EAGAIN)
359
conn->state = STATE_CLOSE;
360
else if (errno == EINTR)
370
switch (conn->iostate) {
371
case IOSTATE_WRITE_BHS:
372
if (conn->rsp.ahssize) {
373
conn->iostate = IOSTATE_WRITE_AHS;
374
conn->buffer = conn->rsp.ahs;
375
conn->rwsize = conn->rsp.ahssize;
378
case IOSTATE_WRITE_AHS:
379
if (conn->rsp.datasize) {
382
conn->iostate = IOSTATE_WRITE_DATA;
383
conn->buffer = conn->rsp.data;
384
conn->rwsize = conn->rsp.datasize;
385
o = conn->rwsize & 3;
387
for (o = 4 - o; o; o--)
388
*((u8 *)conn->buffer + conn->rwsize++) = 0;
392
case IOSTATE_WRITE_DATA:
394
setsockopt(pollfd->fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
397
switch (conn->state) {
399
conn_take_fd(conn, pollfd->fd);
400
conn->state = STATE_CLOSE;
407
pollfd->events = POLLIN;
415
log_error("illegal iostate %d for port %d!\n", conn->iostate, i);
420
if (conn->state == STATE_CLOSE) {
421
struct session *session = conn->session;
422
log_debug(1, "connection closed");
429
if (session && session->conn_cnt <= 0)
430
session_remove(session);
436
int main(int argc, char **argv)
438
int ch, longindex, timeout = -1;
439
char *config = NULL, pid_buf[64];
443
int isns_ac = 0, pid_fd;
445
/* otherwise we would die in some later write() during the event_loop
446
* instead of getting EPIPE! */
447
signal(SIGPIPE, SIG_IGN);
449
while ((ch = getopt_long(argc, argv, "c:fd:s:u:g:a:p:vh", long_options, &longindex)) >= 0) {
458
log_level = atoi(optarg);
461
uid = strtoul(optarg, NULL, 10);
464
gid = strtoul(optarg, NULL, 10);
467
server_address = strdup(optarg);
470
server_port = (uint16_t)strtoul(optarg, NULL, 10);
473
printf("%s version %s\n", program_name, IET_VERSION_STRING);
492
log_error("error starting daemon: %m");
498
open("/dev/null", O_RDWR);
504
if (chdir("/") < 0) {
505
log_error("failed to set working dir to /: %m");
510
pid_fd = open("/var/run/ietd.pid", O_WRONLY|O_CREAT, 0644);
512
log_error("unable to create pid file: %m");
516
if (lockf(pid_fd, F_TLOCK, 0) < 0) {
517
log_error("unable to lock pid file: %m");
521
if (ftruncate(pid_fd, 0) < 0) {
522
log_error("failed to ftruncate the PID file: %m");
526
sprintf(pid_buf, "%d\n", getpid());
527
if (write(pid_fd, pid_buf, strlen(pid_buf)) < strlen(pid_buf)) {
528
log_error("failed to write PID to PID file: %m");
532
if ((ipc_fd = ietadm_request_listen()) < 0) {
533
log_error("unable to open ipc fd: %m");
537
if ((ctrl_fd = ki->ctldev_open()) < 0) {
538
log_error("unable to open ctldev fd: %m");
542
if (!check_version()) {
543
log_error("kernel module version mismatch!");
547
if ((nl_fd = nl_open()) < 0) {
548
log_error("unable to open netlink fd: %m");
552
cops->init(config, &isns, &isns_ac);
554
timeout = isns_init(isns, isns_ac);
556
if (gid && setgid(gid) < 0) {
557
log_error("unable to setgid: %m");
561
if (uid && setuid(uid) < 0) {
562
log_error("unable to setuid: %m");