1: /*
2: * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24: * SUCH DAMAGE.
25: *
26: */
27:
28: #ifdef HAVE_CONFIG_H
29: #include "config.h"
30: #endif
31:
32: #include <inttypes.h>
33: #include <stdint.h>
34:
35: #include <errno.h>
36: #include <stdarg.h>
37: #include <stdio.h>
38: #include <stdlib.h>
39: #include <string.h>
40: #include <poll.h>
41: #include <pthread.h>
42: #ifdef HAVE_PTHREAD_NP_H
43: #include <pthread_np.h>
44: #endif
45: #include <fcntl.h>
46: #include <unistd.h>
47: #include <signal.h>
48:
49: #include <sys/types.h>
50: #include <sys/socket.h>
51: #include <netinet/in.h>
52:
53: #include "istgt.h"
54: #include "istgt_ver.h"
55: #include "istgt_log.h"
56: #include "istgt_conf.h"
57: #include "istgt_sock.h"
58: #include "istgt_misc.h"
59: #include "istgt_crc32c.h"
60: #include "istgt_iscsi.h"
61: #include "istgt_lu.h"
62: #include "istgt_proto.h"
63:
64: #ifdef ISTGT_USE_KQUEUE
65: #include <sys/types.h>
66: #include <sys/event.h>
67: #include <sys/time.h>
68: #endif
69:
70: #define POLLWAIT 3000
71: #define PORTNUMLEN 32
72:
73: ISTGT g_istgt;
74:
75: #if 0
76: void
77: fatal(const char *msg, ...)
78: {
79: va_list ap;
80: va_start(ap, msg);
81: vfprintf(stderr, msg, ap);
82: va_end(ap);
83: exit(EXIT_FAILURE);
84: }
85: #endif
86:
87: static int
88: istgt_parse_portal(const char *portal, char **host, char **port)
89: {
90: const char *p;
91: int n;
92:
93: if (portal == NULL) {
94: ISTGT_ERRLOG("portal error\n");
95: return -1;
96: }
97:
98: if (portal[0] == '[') {
99: /* IPv6 */
100: p = strchr(portal + 1, ']');
101: if (p == NULL) {
102: ISTGT_ERRLOG("portal error\n");
103: return -1;
104: }
105: #if 0
106: n = p - (portal + 1);
107: *host = xmalloc(n + 1);
108: memcpy(*host, portal + 1, n);
109: (*host)[n] = '\0';
110: p++;
111: #else
112: p++;
113: n = p - portal;
114: *host = xmalloc(n + 1);
115: memcpy(*host, portal, n);
116: (*host)[n] = '\0';
117: #endif
118: if (p[0] == '\0') {
119: *port = xmalloc(PORTNUMLEN);
120: snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
121: } else {
122: if (p[0] != ':') {
123: ISTGT_ERRLOG("portal error\n");
124: xfree(*host);
125: return -1;
126: }
127: *port = xstrdup(p + 1);
128: }
129: } else {
130: /* IPv4 */
131: p = strchr(portal, ':');
132: if (p == NULL) {
133: p = portal + strlen(portal);
134: }
135: n = p - portal;
136: *host = xmalloc(n + 1);
137: memcpy(*host, portal, n);
138: (*host)[n] = '\0';
139: if (p[0] == '\0') {
140: *port = xmalloc(PORTNUMLEN);
141: snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
142: } else {
143: if (p[0] != ':') {
144: ISTGT_ERRLOG("portal error\n");
145: xfree(*host);
146: return -1;
147: }
148: *port = xstrdup(p + 1);
149: }
150: }
151: return 0;
152: }
153:
154: static int
155: istgt_add_portal(ISTGT_Ptr istgt, CF_SECTION *sp, int idx1)
156: {
157: char *label, *portal, *host, *port;
158: int idx;
159: int rc;
160:
161: label = istgt_get_nmval(sp, "Portal", idx1, 0);
162: portal = istgt_get_nmval(sp, "Portal", idx1, 1);
163: if (label == NULL || portal == NULL) {
164: ISTGT_ERRLOG("portal error\n");
165: return -1;
166: }
167:
168: rc = istgt_parse_portal(portal, &host, &port);
169: if (rc < 0) {
170: ISTGT_ERRLOG("parse portal error\n");
171: return -1;
172: }
173:
174: idx = istgt->nportal;
175: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
176: "Index=%d, Host=%s, Port=%s, Tag=%d\n",
177: idx, host, port, sp->num);
178: if (idx < MAX_PORTAL) {
179: istgt->portal[idx].label = xstrdup(label);
180: istgt->portal[idx].host = host;
181: istgt->portal[idx].port = port;
182: istgt->portal[idx].idx = idx;
183: istgt->portal[idx].tag = sp->num;
184: istgt->portal[idx].sock = -1;
185: idx++;
186: istgt->nportal = idx;
187: } else {
188: ISTGT_ERRLOG("nportal(%d) >= MAX_PORTAL\n", idx);
189: xfree(host);
190: xfree(port);
191: return -1;
192: }
193: return 0;
194: }
195:
196: static int
197: istgt_build_portal_array(ISTGT_Ptr istgt)
198: {
199: CF_SECTION *sp;
200: const char *val;
201: int rc;
202: int i;
203:
204: sp = istgt->config->section;
205: while (sp != NULL) {
206: if (sp->type == ST_PORTALGROUP) {
207: if (sp->num == 0) {
208: ISTGT_ERRLOG("Group 0 is invalid\n");
209: return -1;
210: }
211: if (sp->num > ISTGT_PG_TAG_MAX) {
212: ISTGT_ERRLOG("tag %d is invalid\n", sp->num);
213: return -1;
214: }
215:
216: val = istgt_get_val(sp, "Comment");
217: if (val != NULL) {
218: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
219: "Comment %s\n", val);
220: }
221: for (i = 0; ; i++) {
222: val = istgt_get_nval(sp, "Portal", i);
223: if (val == NULL)
224: break;
225: rc = istgt_add_portal(istgt, sp, i);
226: if (rc < 0) {
227: ISTGT_ERRLOG("add_portal() failed\n");
228: return -1;
229: }
230: }
231: }
232: sp = sp->next;
233: }
234: return 0;
235: }
236:
237: static void
238: istgt_destroy_portal_array(ISTGT_Ptr istgt)
239: {
240: int i;
241:
242: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destroy_portal_array\n");
243: for (i = 0; i < istgt->nportal; i++) {
244: xfree(istgt->portal[i].label);
245: xfree(istgt->portal[i].host);
246: xfree(istgt->portal[i].port);
247:
248: istgt->portal[i].label = NULL;
249: istgt->portal[i].host = NULL;
250: istgt->portal[i].port = NULL;
251: istgt->portal[i].idx = i;
252: istgt->portal[i].tag = 0;
253: }
254: istgt->nportal = 0;
255: }
256:
257: static int
258: istgt_open_portal(ISTGT_Ptr istgt)
259: {
260: int port;
261: int sock;
262: int i;
263:
264: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_portal\n");
265: for (i = 0; i < istgt->nportal; i++) {
266: if (istgt->portal[i].sock < 0) {
267: ISTGT_TRACELOG(ISTGT_TRACE_NET,
268: "open host %s, port %s, tag %d\n",
269: istgt->portal[i].host, istgt->portal[i].port,
270: istgt->portal[i].tag);
271: port = (int)strtol(istgt->portal[i].port, NULL, 0);
272: sock = istgt_listen(istgt->portal[i].host, port);
273: if (sock < 0) {
274: ISTGT_ERRLOG("listen error %.64s:%d\n",
275: istgt->portal[i].host, port);
276: return -1;
277: }
278: istgt->portal[i].sock = sock;
279: }
280: }
281: return 0;
282: }
283:
284: static int
285: istgt_close_portal(ISTGT_Ptr istgt)
286: {
287: int i;
288:
289: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_portal\n");
290: for (i = 0; i < istgt->nportal; i++) {
291: if (istgt->portal[i].sock >= 0) {
292: ISTGT_TRACELOG(ISTGT_TRACE_NET,
293: "close host %s, port %s, tag %d\n",
294: istgt->portal[i].host, istgt->portal[i].port,
295: istgt->portal[i].tag);
296: close(istgt->portal[i].sock);
297: istgt->portal[i].sock = -1;
298: }
299: }
300: return 0;
301: }
302:
303: static int
304: istgt_add_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp)
305: {
306: const char *val;
307: int alloc_len;
308: int idx;
309: int names;
310: int masks;
311: int i;
312:
313: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add initiator group %d\n", sp->num);
314:
315: val = istgt_get_val(sp, "Comment");
316: if (val != NULL) {
317: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
318: }
319:
320: /* counts number of definition */
321: for (i = 0; ; i++) {
322: val = istgt_get_nval(sp, "InitiatorName", i);
323: if (val == NULL)
324: break;
325: }
326: names = i;
327: if (names > MAX_INITIATOR) {
328: ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names);
329: return -1;
330: }
331: for (i = 0; ; i++) {
332: val = istgt_get_nval(sp, "Netmask", i);
333: if (val == NULL)
334: break;
335: }
336: masks = i;
337: if (masks > MAX_NETMASK) {
338: ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
339: return -1;
340: }
341:
342: idx = istgt->ninitiator_group;
343: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
344: "Index=%d, Tag=%d, Names=%d, Masks=%d\n",
345: idx, sp->num, names, masks);
346: if (idx < MAX_INITIATOR_GROUP) {
347: istgt->initiator_group[idx].ninitiators = names;
348: alloc_len = sizeof (char *) * names;
349: istgt->initiator_group[idx].initiators = xmalloc(alloc_len);
350: istgt->initiator_group[idx].nnetmasks = masks;
351: alloc_len = sizeof (char *) * masks;
352: istgt->initiator_group[idx].netmasks = xmalloc(alloc_len);
353: istgt->initiator_group[idx].idx = idx;
354: istgt->initiator_group[idx].tag = sp->num;
355:
356: for (i = 0; i < names; i++) {
357: val = istgt_get_nval(sp, "InitiatorName", i);
358: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
359: "InitiatorName %s\n", val);
360: istgt->initiator_group[idx].initiators[i] = xstrdup(val);
361: }
362: for (i = 0; i < masks; i++) {
363: val = istgt_get_nval(sp, "Netmask", i);
364: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
365: istgt->initiator_group[idx].netmasks[i] = xstrdup(val);
366: }
367:
368: idx++;
369: istgt->ninitiator_group = idx;
370: } else {
371: ISTGT_ERRLOG("ninitiator_group(%d) >= MAX_INITIATOR_GROUP\n", idx);
372: return -1;
373: }
374: return 0;
375: }
376:
377: static int
378: istgt_build_initiator_group_array(ISTGT_Ptr istgt)
379: {
380: CF_SECTION *sp;
381: int rc;
382:
383: sp = istgt->config->section;
384: while (sp != NULL) {
385: if (sp->type == ST_INITIATORGROUP) {
386: if (sp->num == 0) {
387: ISTGT_ERRLOG("Group 0 is invalid\n");
388: return -1;
389: }
390: rc = istgt_add_initiator_group(istgt, sp);
391: if (rc < 0) {
392: ISTGT_ERRLOG("add_initiator_group() failed\n");
393: return -1;
394: }
395: }
396: sp = sp->next;
397: }
398: return 0;
399: }
400:
401: static void
402: istgt_destory_initiator_group_array(ISTGT_Ptr istgt)
403: {
404: int i, j;
405:
406: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_initiator_group_array\n");
407: for (i = 0; i < istgt->ninitiator_group; i++) {
408: for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) {
409: xfree(istgt->initiator_group[i].initiators[j]);
410: }
411: xfree(istgt->initiator_group[i].initiators);
412: for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) {
413: xfree(istgt->initiator_group[i].netmasks[j]);
414: }
415: xfree(istgt->initiator_group[i].netmasks);
416:
417: istgt->initiator_group[i].ninitiators = 0;
418: istgt->initiator_group[i].initiators = NULL;
419: istgt->initiator_group[i].nnetmasks = 0;
420: istgt->initiator_group[i].netmasks = NULL;
421: istgt->initiator_group[i].idx = i;
422: istgt->initiator_group[i].tag = 0;
423: }
424: istgt->ninitiator_group = 0;
425: }
426:
427: static int
428: istgt_build_uctl_portal(ISTGT_Ptr istgt)
429: {
430: CF_SECTION *sp;
431: const char *val;
432: char *label, *portal, *host, *port;
433: int tag;
434: int idx;
435: int rc;
436: int i;
437:
438: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_build_uctl_portal\n");
439:
440: sp = istgt_find_cf_section(istgt->config, "UnitControl");
441: if (sp == NULL) {
442: ISTGT_ERRLOG("find_cf_section failed()\n");
443: return -1;
444: }
445:
446: for (i = 0; ; i++) {
447: val = istgt_get_nval(sp, "Portal", i);
448: if (val == NULL)
449: break;
450:
451: label = istgt_get_nmval(sp, "Portal", i, 0);
452: portal = istgt_get_nmval(sp, "Portal", i, 1);
453: if (label == NULL || portal == NULL) {
454: ISTGT_ERRLOG("uctl portal error\n");
455: return -1;
456: }
457:
458: rc = istgt_parse_portal(portal, &host, &port);
459: if (rc < 0) {
460: ISTGT_ERRLOG("parse uctl portal error\n");
461: return -1;
462: }
463:
464: idx = istgt->nuctl_portal;
465: tag = ISTGT_UC_TAG;
466: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
467: "Index=%d, Host=%s, Port=%s, Tag=%d\n",
468: idx, host, port, tag);
469: if (idx < MAX_UCPORTAL) {
470: istgt->uctl_portal[idx].label = xstrdup(label);
471: istgt->uctl_portal[idx].host = host;
472: istgt->uctl_portal[idx].port = port;
473: istgt->uctl_portal[idx].idx = idx;
474: istgt->uctl_portal[idx].tag = tag;
475: istgt->uctl_portal[idx].sock = -1;
476: idx++;
477: istgt->nuctl_portal = idx;
478: } else {
479: ISTGT_ERRLOG("nportal(%d) >= MAX_UCPORTAL\n", idx);
480: xfree(host);
481: xfree(port);
482: return -1;
483: }
484: }
485:
486: return 0;
487: }
488:
489: static void
490: istgt_destroy_uctl_portal(ISTGT_Ptr istgt)
491: {
492: int i;
493:
494: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destroy_uctl_portal\n");
495: for (i = 0; i < istgt->nportal; i++) {
496: xfree(istgt->uctl_portal[i].label);
497: xfree(istgt->uctl_portal[i].host);
498: xfree(istgt->uctl_portal[i].port);
499:
500: istgt->uctl_portal[i].label = NULL;
501: istgt->uctl_portal[i].host = NULL;
502: istgt->uctl_portal[i].port = NULL;
503: istgt->uctl_portal[i].idx = i;
504: istgt->uctl_portal[i].tag = 0;
505: }
506: istgt->nuctl_portal = 0;
507: }
508:
509: static int
510: istgt_open_uctl_portal(ISTGT_Ptr istgt)
511: {
512: int port;
513: int sock;
514: int i;
515:
516: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_uctl_portal\n");
517: for (i = 0; i < istgt->nuctl_portal; i++) {
518: if (istgt->uctl_portal[i].sock < 0) {
519: ISTGT_TRACELOG(ISTGT_TRACE_NET,
520: "open host %s, port %s, tag %d\n",
521: istgt->uctl_portal[i].host,
522: istgt->uctl_portal[i].port,
523: istgt->uctl_portal[i].tag);
524: port = (int)strtol(istgt->uctl_portal[i].port, NULL, 0);
525: sock = istgt_listen(istgt->uctl_portal[i].host, port);
526: if (sock < 0) {
527: ISTGT_ERRLOG("listen error %.64s:%d\n",
528: istgt->uctl_portal[i].host, port);
529: return -1;
530: }
531: istgt->uctl_portal[i].sock = sock;
532: }
533: }
534: return 0;
535: }
536:
537: static int
538: istgt_close_uctl_portal(ISTGT_Ptr istgt)
539: {
540: int i;
541:
542: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_uctl_portal\n");
543: for (i = 0; i < istgt->nuctl_portal; i++) {
544: if (istgt->uctl_portal[i].sock >= 0) {
545: ISTGT_TRACELOG(ISTGT_TRACE_NET,
546: "close host %s, port %s, tag %d\n",
547: istgt->uctl_portal[i].host,
548: istgt->uctl_portal[i].port,
549: istgt->uctl_portal[i].tag);
550: close(istgt->uctl_portal[i].sock);
551: istgt->uctl_portal[i].sock = -1;
552: }
553: }
554: return 0;
555: }
556:
557: static int
558: istgt_write_pidfile(ISTGT_Ptr istgt)
559: {
560: FILE *fp;
561: pid_t pid;
562: int rc;
563:
564: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_write_pidfile\n");
565: rc = remove(istgt->pidfile);
566: if (rc != 0) {
567: if (errno != ENOENT) {
568: ISTGT_ERRLOG("pidfile remove error %d\n", errno);
569: return -1;
570: }
571: }
572: fp = fopen(istgt->pidfile, "w");
573: if (fp == NULL) {
574: ISTGT_ERRLOG("pidfile open error %d\n", errno);
575: return -1;
576: }
577: pid = getpid();
578: fprintf(fp, "%d\n", (int)pid);
579: fclose(fp);
580: return 0;
581: }
582:
583: static void
584: istgt_remove_pidfile(ISTGT_Ptr istgt)
585: {
586: int rc;
587:
588: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_remove_pidfile\n");
589: rc = remove(istgt->pidfile);
590: if (rc != 0) {
591: ISTGT_ERRLOG("pidfile remove error %d\n", errno);
592: /* ignore error */
593: }
594: }
595:
596: char *
597: istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2)
598: {
599: CF_ITEM *ip;
600: CF_VALUE *vp;
601: int i;
602:
603: ip = istgt_find_cf_nitem(sp, key, idx1);
604: if (ip == NULL)
605: return NULL;
606: vp = ip->val;
607: if (vp == NULL)
608: return NULL;
609: for (i = 0; vp != NULL; vp = vp->next) {
610: if (i == idx2)
611: return vp->value;
612: i++;
613: }
614: return NULL;
615: }
616:
617: char *
618: istgt_get_nval(CF_SECTION *sp, const char *key, int idx)
619: {
620: CF_ITEM *ip;
621: CF_VALUE *vp;
622:
623: ip = istgt_find_cf_nitem(sp, key, idx);
624: if (ip == NULL)
625: return NULL;
626: vp = ip->val;
627: if (vp == NULL)
628: return NULL;
629: return vp->value;
630: }
631:
632: char *
633: istgt_get_val(CF_SECTION *sp, const char *key)
634: {
635: return istgt_get_nval(sp, key, 0);
636: }
637:
638: int
639: istgt_get_nintval(CF_SECTION *sp, const char *key, int idx)
640: {
641: const char *v;
642: int value;
643:
644: v = istgt_get_nval(sp, key, idx);
645: if (v == NULL)
646: return -1;
647: value = (int)strtol(v, NULL, 10);
648: return value;
649: }
650:
651: int
652: istgt_get_intval(CF_SECTION *sp, const char *key)
653: {
654: return istgt_get_nintval(sp, key, 0);
655: }
656:
657: static const char *
658: istgt_get_log_facility(CONFIG *config)
659: {
660: CF_SECTION *sp;
661: const char *logfacility;
662:
663: sp = istgt_find_cf_section(config, "Global");
664: if (sp == NULL) {
665: return NULL;
666: }
667: logfacility = istgt_get_val(sp, "LogFacility");
668: if (logfacility == NULL) {
669: logfacility = DEFAULT_LOG_FACILITY;
670: }
671: #if 0
672: if (g_trace_flag & ISTGT_TRACE_DEBUG) {
673: fprintf(stderr, "LogFacility %s\n", logfacility);
674: }
675: #endif
676:
677: return logfacility;
678: }
679:
680: static int
681: istgt_init(ISTGT_Ptr istgt)
682: {
683: CF_SECTION *sp;
684: const char *ag_tag;
685: const char *val;
686: size_t stacksize;
687: int ag_tag_i;
688: int MaxSessions;
689: int MaxConnections;
690: int MaxOutstandingR2T;
691: int DefaultTime2Wait;
692: int DefaultTime2Retain;
693: int FirstBurstLength;
694: int MaxBurstLength;
695: int MaxRecvDataSegmentLength;
696: int InitialR2T;
697: int ImmediateData;
698: int DataPDUInOrder;
699: int DataSequenceInOrder;
700: int ErrorRecoveryLevel;
701: int timeout;
702: int nopininterval;
703: int maxr2t;
704: int rc;
705: int i;
706:
707: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init\n");
708: sp = istgt_find_cf_section(istgt->config, "Global");
709: if (sp == NULL) {
710: ISTGT_ERRLOG("find_cf_section failed()\n");
711: return -1;
712: }
713:
714: val = istgt_get_val(sp, "Comment");
715: if (val != NULL) {
716: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
717: }
718:
719: val = istgt_get_val(sp, "PidFile");
720: if (val == NULL) {
721: val = DEFAULT_PIDFILE;
722: }
723: istgt->pidfile = xstrdup(val);
724: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PidFile %s\n",
725: istgt->pidfile);
726:
727: val = istgt_get_val(sp, "AuthFile");
728: if (val == NULL) {
729: val = DEFAULT_AUTHFILE;
730: }
731: istgt->authfile = xstrdup(val);
732: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthFile %s\n",
733: istgt->authfile);
734:
735: #if 0
736: val = istgt_get_val(sp, "MediaFile");
737: if (val == NULL) {
738: val = DEFAULT_MEDIAFILE;
739: }
740: istgt->mediafile = xstrdup(val);
741: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaFile %s\n",
742: istgt->mediafile);
743: #endif
744:
745: #if 0
746: val = istgt_get_val(sp, "LiveFile");
747: if (val == NULL) {
748: val = DEFAULT_LIVEFILE;
749: }
750: istgt->livefile = xstrdup(val);
751: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LiveFile %s\n",
752: istgt->livefile);
753: #endif
754:
755: val = istgt_get_val(sp, "MediaDirectory");
756: if (val == NULL) {
757: val = DEFAULT_MEDIADIRECTORY;
758: }
759: istgt->mediadirectory = xstrdup(val);
760: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaDirectory %s\n",
761: istgt->mediadirectory);
762:
763: val = istgt_get_val(sp, "NodeBase");
764: if (val == NULL) {
765: val = DEFAULT_NODEBASE;
766: }
767: istgt->nodebase = xstrdup(val);
768: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NodeBase %s\n",
769: istgt->nodebase);
770:
771: MaxSessions = istgt_get_intval(sp, "MaxSessions");
772: if (MaxSessions < 1) {
773: MaxSessions = DEFAULT_MAX_SESSIONS;
774: }
775: istgt->MaxSessions = MaxSessions;
776: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxSessions %d\n",
777: istgt->MaxSessions);
778:
779: MaxConnections = istgt_get_intval(sp, "MaxConnections");
780: if (MaxConnections < 1) {
781: MaxConnections = DEFAULT_MAX_CONNECTIONS;
782: }
783: istgt->MaxConnections = MaxConnections;
784: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxConnections %d\n",
785: istgt->MaxConnections);
786:
787: /* limited to 16bits - RFC3720(12.2) */
788: if (MaxSessions > 0xffff) {
789: ISTGT_ERRLOG("over 65535 sessions are not supported\n");
790: return -1;
791: }
792: if (MaxConnections > 0xffff) {
793: ISTGT_ERRLOG("over 65535 connections are not supported\n");
794: return -1;
795: }
796:
797: MaxOutstandingR2T = istgt_get_intval(sp, "MaxOutstandingR2T");
798: if (MaxOutstandingR2T < 1) {
799: MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
800: }
801: istgt->MaxOutstandingR2T = MaxOutstandingR2T;
802: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n",
803: istgt->MaxOutstandingR2T);
804:
805: DefaultTime2Wait = istgt_get_intval(sp, "DefaultTime2Wait");
806: if (DefaultTime2Wait < 0) {
807: DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
808: }
809: istgt->DefaultTime2Wait = DefaultTime2Wait;
810: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n",
811: istgt->DefaultTime2Wait);
812:
813: DefaultTime2Retain = istgt_get_intval(sp, "DefaultTime2Retain");
814: if (DefaultTime2Retain < 0) {
815: DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
816: }
817: istgt->DefaultTime2Retain = DefaultTime2Retain;
818: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n",
819: istgt->DefaultTime2Retain);
820:
821: /* check size limit - RFC3720(12.15, 12.16, 12.17) */
822: if (istgt->MaxOutstandingR2T > 65535) {
823: ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n",
824: istgt->MaxOutstandingR2T);
825: return -1;
826: }
827: if (istgt->DefaultTime2Wait > 3600) {
828: ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n",
829: istgt->DefaultTime2Wait);
830: return -1;
831: }
832: if (istgt->DefaultTime2Retain > 3600) {
833: ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n",
834: istgt->DefaultTime2Retain);
835: return -1;
836: }
837:
838: FirstBurstLength = istgt_get_intval(sp, "FirstBurstLength");
839: if (FirstBurstLength < 0) {
840: FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
841: }
842: istgt->FirstBurstLength = FirstBurstLength;
843: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n",
844: istgt->FirstBurstLength);
845:
846: MaxBurstLength = istgt_get_intval(sp, "MaxBurstLength");
847: if (MaxBurstLength < 0) {
848: MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
849: }
850: istgt->MaxBurstLength = MaxBurstLength;
851: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n",
852: istgt->MaxBurstLength);
853:
854: MaxRecvDataSegmentLength
855: = istgt_get_intval(sp, "MaxRecvDataSegmentLength");
856: if (MaxRecvDataSegmentLength < 0) {
857: MaxRecvDataSegmentLength = DEFAULT_MAXRECVDATASEGMENTLENGTH;
858: }
859: istgt->MaxRecvDataSegmentLength = MaxRecvDataSegmentLength;
860: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
861: istgt->MaxRecvDataSegmentLength);
862:
863: /* check size limit (up to 24bits - RFC3720(12.12)) */
864: if (istgt->MaxBurstLength < 512) {
865: ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n",
866: istgt->MaxBurstLength);
867: return -1;
868: }
869: if (istgt->FirstBurstLength < 512) {
870: ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n",
871: istgt->FirstBurstLength);
872: return -1;
873: }
874: if (istgt->FirstBurstLength > istgt->MaxBurstLength) {
875: ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
876: istgt->FirstBurstLength, istgt->MaxBurstLength);
877: return -1;
878: }
879: if (istgt->MaxBurstLength > 0x00ffffff) {
880: ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
881: istgt->MaxBurstLength);
882: return -1;
883: }
884: if (istgt->MaxRecvDataSegmentLength < 512) {
885: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
886: istgt->MaxRecvDataSegmentLength);
887: return -1;
888: }
889: if (istgt->MaxRecvDataSegmentLength > 0x00ffffff) {
890: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
891: istgt->MaxRecvDataSegmentLength);
892: return -1;
893: }
894:
895: val = istgt_get_val(sp, "InitialR2T");
896: if (val == NULL) {
897: InitialR2T = DEFAULT_INITIALR2T;
898: } else if (strcasecmp(val, "Yes") == 0) {
899: InitialR2T = 1;
900: } else if (strcasecmp(val, "No") == 0) {
901: #if 0
902: InitialR2T = 0;
903: #else
904: ISTGT_ERRLOG("not supported value %s\n", val);
905: return -1;
906: #endif
907: } else {
908: ISTGT_ERRLOG("unknown value %s\n", val);
909: return -1;
910: }
911: istgt->InitialR2T = InitialR2T;
912: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n",
913: istgt->InitialR2T ? "Yes" : "No");
914:
915: val = istgt_get_val(sp, "ImmediateData");
916: if (val == NULL) {
917: ImmediateData = DEFAULT_IMMEDIATEDATA;
918: } else if (strcasecmp(val, "Yes") == 0) {
919: ImmediateData = 1;
920: } else if (strcasecmp(val, "No") == 0) {
921: ImmediateData = 0;
922: } else {
923: ISTGT_ERRLOG("unknown value %s\n", val);
924: return -1;
925: }
926: istgt->ImmediateData = ImmediateData;
927: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n",
928: istgt->ImmediateData ? "Yes" : "No");
929:
930: val = istgt_get_val(sp, "DataPDUInOrder");
931: if (val == NULL) {
932: DataPDUInOrder = DEFAULT_DATAPDUINORDER;
933: } else if (strcasecmp(val, "Yes") == 0) {
934: DataPDUInOrder = 1;
935: } else if (strcasecmp(val, "No") == 0) {
936: #if 0
937: DataPDUInOrder = 0;
938: #else
939: ISTGT_ERRLOG("not supported value %s\n", val);
940: return -1;
941: #endif
942: } else {
943: ISTGT_ERRLOG("unknown value %s\n", val);
944: return -1;
945: }
946: istgt->DataPDUInOrder = DataPDUInOrder;
947: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n",
948: istgt->DataPDUInOrder ? "Yes" : "No");
949:
950: val = istgt_get_val(sp, "DataSequenceInOrder");
951: if (val == NULL) {
952: DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
953: } else if (strcasecmp(val, "Yes") == 0) {
954: DataSequenceInOrder = 1;
955: } else if (strcasecmp(val, "No") == 0) {
956: #if 0
957: DataSequenceInOrder = 0;
958: #else
959: ISTGT_ERRLOG("not supported value %s\n", val);
960: return -1;
961: #endif
962: } else {
963: ISTGT_ERRLOG("unknown value %s\n", val);
964: return -1;
965: }
966: istgt->DataSequenceInOrder = DataSequenceInOrder;
967: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n",
968: istgt->DataSequenceInOrder ? "Yes" : "No");
969:
970: ErrorRecoveryLevel = istgt_get_intval(sp, "ErrorRecoveryLevel");
971: if (ErrorRecoveryLevel < 0) {
972: ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
973: } else if (ErrorRecoveryLevel == 0) {
974: ErrorRecoveryLevel = 0;
975: } else if (ErrorRecoveryLevel == 1) {
976: #if 0
977: ErrorRecoveryLevel = 1;
978: #else
979: ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
980: return -1;
981: #endif
982: } else if (ErrorRecoveryLevel == 2) {
983: #if 0
984: ErrorRecoveryLevel = 2;
985: #else
986: ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
987: return -1;
988: #endif
989: } else {
990: ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
991: return -1;
992: }
993: istgt->ErrorRecoveryLevel = ErrorRecoveryLevel;
994: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
995: istgt->ErrorRecoveryLevel);
996:
997: timeout = istgt_get_intval(sp, "Timeout");
998: if (timeout < 0) {
999: timeout = DEFAULT_TIMEOUT;
1000: }
1001: istgt->timeout = timeout;
1002: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Timeout %d\n",
1003: istgt->timeout);
1004:
1005: nopininterval = istgt_get_intval(sp, "NopInInterval");
1006: if (nopininterval < 0) {
1007: nopininterval = DEFAULT_NOPININTERVAL;
1008: }
1009: istgt->nopininterval = nopininterval;
1010: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NopInInterval %d\n",
1011: istgt->nopininterval);
1012:
1013: maxr2t = istgt_get_intval(sp, "MaxR2T");
1014: if (maxr2t < 0) {
1015: maxr2t = DEFAULT_MAXR2T;
1016: }
1017: if (maxr2t > MAX_R2T) {
1018: ISTGT_ERRLOG("MaxR2T(%d) > %d\n",
1019: maxr2t, MAX_R2T);
1020: return -1;
1021: }
1022: istgt->maxr2t = maxr2t;
1023: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxR2T %d\n",
1024: istgt->maxr2t);
1025:
1026: val = istgt_get_val(sp, "DiscoveryAuthMethod");
1027: if (val == NULL) {
1028: istgt->no_discovery_auth = 0;
1029: istgt->req_discovery_auth = 0;
1030: istgt->req_discovery_auth_mutual = 0;
1031: } else {
1032: istgt->no_discovery_auth = 0;
1033: for (i = 0; ; i++) {
1034: val = istgt_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
1035: if (val == NULL)
1036: break;
1037: if (strcasecmp(val, "CHAP") == 0) {
1038: istgt->req_discovery_auth = 1;
1039: } else if (strcasecmp(val, "Mutual") == 0) {
1040: istgt->req_discovery_auth_mutual = 1;
1041: } else if (strcasecmp(val, "Auto") == 0) {
1042: istgt->req_discovery_auth = 0;
1043: istgt->req_discovery_auth_mutual = 0;
1044: } else if (strcasecmp(val, "None") == 0) {
1045: istgt->no_discovery_auth = 1;
1046: istgt->req_discovery_auth = 0;
1047: istgt->req_discovery_auth_mutual = 0;
1048: } else {
1049: ISTGT_ERRLOG("unknown auth\n");
1050: return -1;
1051: }
1052: }
1053: if (istgt->req_discovery_auth_mutual && !istgt->req_discovery_auth) {
1054: ISTGT_ERRLOG("Mutual but not CHAP\n");
1055: return -1;
1056: }
1057: }
1058: if (istgt->no_discovery_auth != 0) {
1059: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1060: "DiscoveryAuthMethod None\n");
1061: } else if (istgt->req_discovery_auth == 0) {
1062: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1063: "DiscoveryAuthMethod Auto\n");
1064: } else {
1065: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1066: "DiscoveryAuthMethod %s %s\n",
1067: istgt->req_discovery_auth ? "CHAP" : "",
1068: istgt->req_discovery_auth_mutual ? "Mutual" : "");
1069: }
1070:
1071: val = istgt_get_val(sp, "DiscoveryAuthGroup");
1072: if (val == NULL) {
1073: istgt->discovery_auth_group = 0;
1074: } else {
1075: ag_tag = val;
1076: if (strcasecmp(ag_tag, "None") == 0) {
1077: ag_tag_i = 0;
1078: } else {
1079: if (strncasecmp(ag_tag, "AuthGroup",
1080: strlen("AuthGroup")) != 0
1081: || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
1082: ISTGT_ERRLOG("auth group error\n");
1083: return -1;
1084: }
1085: if (ag_tag_i == 0) {
1086: ISTGT_ERRLOG("invalid auth group %d\n",
1087: ag_tag_i);
1088: return -1;
1089: }
1090: }
1091: istgt->discovery_auth_group = ag_tag_i;
1092: }
1093: if (istgt->discovery_auth_group == 0) {
1094: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1095: "DiscoveryAuthGroup None\n");
1096: } else {
1097: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1098: "DiscoveryAuthGroup AuthGroup%d\n",
1099: istgt->discovery_auth_group);
1100: }
1101:
1102: rc = istgt_init_uctl(istgt);
1103: if (rc < 0) {
1104: ISTGT_ERRLOG("istgt_init_uctl() failed\n");
1105: return -1;
1106: }
1107: rc = istgt_build_uctl_portal(istgt);
1108: if (rc < 0) {
1109: ISTGT_ERRLOG("istgt_build_uctl_portal() failed\n");
1110: return -1;
1111: }
1112: rc = istgt_build_portal_array(istgt);
1113: if (rc < 0) {
1114: ISTGT_ERRLOG("istgt_build_portal_array() failed\n");
1115: return -1;
1116: }
1117: rc = istgt_build_initiator_group_array(istgt);
1118: if (rc < 0) {
1119: ISTGT_ERRLOG("build_initiator_group_array() failed\n");
1120: return -1;
1121: }
1122:
1123: rc = pthread_attr_init(&istgt->attr);
1124: if (rc != 0) {
1125: ISTGT_ERRLOG("pthread_attr_init() failed\n");
1126: return -1;
1127: }
1128: rc = pthread_attr_getstacksize(&istgt->attr, &stacksize);
1129: if (rc != 0) {
1130: ISTGT_ERRLOG("pthread_attr_getstacksize() failed\n");
1131: return -1;
1132: }
1133: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "current thread stack = %zd\n", stacksize);
1134: if (stacksize < ISTGT_STACKSIZE) {
1135: stacksize = ISTGT_STACKSIZE;
1136: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "new thread stack = %zd\n", stacksize);
1137: rc = pthread_attr_setstacksize(&istgt->attr, stacksize);
1138: if (rc != 0) {
1139: ISTGT_ERRLOG("pthread_attr_setstacksize() failed\n");
1140: return -1;
1141: }
1142: }
1143:
1144: rc = pthread_mutex_init(&istgt->mutex, NULL);
1145: if (rc != 0) {
1146: ISTGT_ERRLOG("mutex_init() failed\n");
1147: return -1;
1148: }
1149:
1150: /* XXX TODO: add initializer */
1151:
1152: istgt_set_state(istgt, ISTGT_STATE_INITIALIZED);
1153:
1154: return 0;
1155: }
1156:
1157: #ifdef SIGINFO
1158: static void
1159: istgt_siginfo(int signo)
1160: {
1161: /* nothing */
1162: }
1163: #endif
1164:
1165: static void
1166: istgt_sigwakeup(int signo)
1167: {
1168: }
1169:
1170: #ifdef SIGIO
1171: static void
1172: istgt_sigio(int signo)
1173: {
1174: }
1175: #endif
1176:
1177: static void *
1178: istgt_sighandler(void *arg)
1179: {
1180: ISTGT_Ptr istgt = (ISTGT_Ptr) arg;
1181: sigset_t signew;
1182: int signo;
1183:
1184: sigemptyset(&signew);
1185: sigaddset(&signew, SIGINT);
1186: sigaddset(&signew, SIGTERM);
1187: sigaddset(&signew, SIGQUIT);
1188: sigaddset(&signew, SIGHUP);
1189: #ifdef SIGINFO
1190: sigaddset(&signew, SIGINFO);
1191: #endif
1192: sigaddset(&signew, SIGUSR1);
1193: sigaddset(&signew, SIGUSR2);
1194: #ifdef SIGIO
1195: sigaddset(&signew, SIGIO);
1196: #endif
1197:
1198: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
1199: while (1) {
1200: if (istgt_get_state(istgt) == ISTGT_STATE_EXITING
1201: || istgt_get_state(istgt) == ISTGT_STATE_SHUTDOWN) {
1202: break;
1203: }
1204: sigwait(&signew, &signo);
1205: switch (signo) {
1206: case SIGINT:
1207: printf("SIGINT catch\n");
1208: istgt_set_state(istgt, ISTGT_STATE_EXITING);
1209: istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
1210: break;
1211: case SIGTERM:
1212: printf("SIGTERM catch\n");
1213: istgt_set_state(istgt, ISTGT_STATE_EXITING);
1214: istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
1215: break;
1216: case SIGQUIT:
1217: printf("SIGQUIT catch\n");
1218: exit(EXIT_SUCCESS);
1219: break;
1220: case SIGHUP:
1221: printf("SIGHUP catch\n");
1222: break;
1223: #ifdef SIGINFO
1224: case SIGINFO:
1225: printf("SIGINFO catch\n");
1226: istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
1227: break;
1228: #endif
1229: case SIGUSR1:
1230: printf("SIGUSR1 catch\n");
1231: istgt_set_trace_flag(ISTGT_TRACE_NONE);
1232: break;
1233: case SIGUSR2:
1234: printf("SIGUSR2 catch\n");
1235: //istgt_set_trace_flag(ISTGT_TRACE_SCSI);
1236: istgt_set_trace_flag(ISTGT_TRACE_ALL);
1237: break;
1238: #ifdef SIGIO
1239: case SIGIO:
1240: //printf("SIGIO catch\n");
1241: break;
1242: #endif
1243: default:
1244: break;
1245: }
1246: }
1247: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
1248:
1249: return NULL;
1250: }
1251:
1252: static int
1253: istgt_acceptor(ISTGT_Ptr istgt)
1254: {
1255: #ifdef ISTGT_USE_KQUEUE
1256: int kq;
1257: struct kevent kev;
1258: struct timespec kev_timeout;
1259: #else
1260: struct pollfd fds[MAX_PORTAL + MAX_UCPORTAL];
1261: #endif /* ISTGT_USE_KQUEUE */
1262: struct sockaddr_storage sa;
1263: socklen_t salen;
1264: int sock;
1265: int rc, n;
1266: int ucidx;
1267: int nidx;
1268: int i;
1269:
1270: if (istgt_get_state(istgt) != ISTGT_STATE_INITIALIZED) {
1271: ISTGT_ERRLOG("not initialized\n");
1272: return -1;
1273: }
1274: /* now running main thread */
1275: istgt_set_state(istgt, ISTGT_STATE_RUNNING);
1276:
1277: #ifdef ISTGT_USE_KQUEUE
1278: kq = kqueue();
1279: if (kq == -1) {
1280: ISTGT_ERRLOG("kqueue() failed\n");
1281: return -1;
1282: }
1283: for (i = 0; i < istgt->nportal; i++) {
1284: EV_SET(&kev, istgt->portal[i].sock,
1285: EVFILT_READ, EV_ADD, 0, 0, NULL);
1286: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
1287: if (rc == -1) {
1288: ISTGT_ERRLOG("kevent() failed\n");
1289: close(kq);
1290: return -1;
1291: }
1292: }
1293: ucidx = istgt->nportal;
1294: for (i = 0; i < istgt->nuctl_portal; i++) {
1295: EV_SET(&kev, istgt->uctl_portal[i].sock,
1296: EVFILT_READ, EV_ADD, 0, 0, NULL);
1297: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
1298: if (rc == -1) {
1299: ISTGT_ERRLOG("kevent() failed\n");
1300: close(kq);
1301: return -1;
1302: }
1303: }
1304: nidx = istgt->nportal + istgt->nuctl_portal;
1305:
1306: EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1307: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
1308: if (rc == -1) {
1309: ISTGT_ERRLOG("kevent() failed\n");
1310: close(kq);
1311: return -1;
1312: }
1313: EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1314: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
1315: if (rc == -1) {
1316: ISTGT_ERRLOG("kevent() failed\n");
1317: close(kq);
1318: return -1;
1319: }
1320: #else
1321: memset(&fds, 0, sizeof fds);
1322: for (i = 0; i < istgt->nportal; i++) {
1323: fds[i].fd = istgt->portal[i].sock;
1324: fds[i].events = POLLIN;
1325: }
1326: ucidx = istgt->nportal;
1327: for (i = 0; i < istgt->nuctl_portal; i++) {
1328: fds[ucidx + i].fd = istgt->uctl_portal[i].sock;
1329: fds[ucidx + i].events = POLLIN;
1330: }
1331: nidx = istgt->nportal + istgt->nuctl_portal;
1332: #endif /* ISTGT_USE_KQUEUE */
1333:
1334: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
1335: while (1) {
1336: if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
1337: break;
1338: }
1339: #ifdef ISTGT_USE_KQUEUE
1340: //ISTGT_TRACELOG(ISTGT_TRACE_NET, "kevent %d\n", nidx);
1341: kev_timeout.tv_sec = 10;
1342: kev_timeout.tv_nsec = 0;
1343: rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
1344: if (rc == -1 && errno == EINTR) {
1345: continue;
1346: }
1347: if (rc == -1) {
1348: ISTGT_ERRLOG("kevent() failed\n");
1349: break;
1350: }
1351: if (rc == 0) {
1352: /* idle timeout */
1353: continue;
1354: }
1355: if (kev.filter == EVFILT_SIGNAL) {
1356: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n");
1357: if (kev.ident == SIGINT || kev.ident == SIGTERM) {
1358: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1359: "kevent SIGNAL SIGINT/SIGTERM\n");
1360: break;
1361: }
1362: continue;
1363: }
1364: #else
1365: //ISTGT_TRACELOG(ISTGT_TRACE_NET, "poll %d\n", nidx);
1366: rc = poll(fds, nidx, POLLWAIT);
1367: if (rc == -1 && errno == EINTR) {
1368: continue;
1369: }
1370: if (rc == -1) {
1371: ISTGT_ERRLOG("poll() failed\n");
1372: break;
1373: }
1374: if (rc == 0) {
1375: /* no fds */
1376: continue;
1377: }
1378: #endif /* ISTGT_USE_KQUEUE */
1379:
1380: n = rc;
1381: for (i = 0; n != 0 && i < istgt->nportal; i++) {
1382: #ifdef ISTGT_USE_KQUEUE
1383: if (kev.ident == istgt->portal[i].sock) {
1384: if (kev.flags) {
1385: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1386: "flags %x\n",
1387: kev.flags);
1388: }
1389: #else
1390: if (fds[i].revents) {
1391: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1392: "events %x\n",
1393: fds[i].revents);
1394: }
1395: if (fds[i].revents & POLLIN) {
1396: #endif /* ISTGT_USE_KQUEUE */
1397: n--;
1398: memset(&sa, 0, sizeof(sa));
1399: salen = sizeof(sa);
1400: #ifdef ISTGT_USE_KQUEUE
1401: ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %d\n",
1402: kev.ident);
1403: rc = accept(kev.ident, (struct sockaddr *) &sa, &salen);
1404: #else
1405: ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %d\n",
1406: fds[i].fd);
1407: rc = accept(fds[i].fd, (struct sockaddr *) &sa, &salen);
1408: #endif /* ISTGT_USE_KQUEUE */
1409: if (rc < 0) {
1410: ISTGT_ERRLOG("accept error: %d\n", rc);
1411: continue;
1412: }
1413: sock = rc;
1414: #if 0
1415: rc = fcntl(sock, F_GETFL, 0);
1416: if (rc == -1) {
1417: ISTGT_ERRLOG("fcntl() failed\n");
1418: continue;
1419: }
1420: rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
1421: if (rc == -1) {
1422: ISTGT_ERRLOG("fcntl() failed\n");
1423: continue;
1424: }
1425: #endif
1426: rc = istgt_create_conn(istgt,
1427: &istgt->portal[i], sock,
1428: (struct sockaddr *) &sa, salen);
1429: if (rc < 0) {
1430: close(sock);
1431: ISTGT_ERRLOG("istgt_create_conn() failed\n");
1432: continue;
1433: }
1434: }
1435: }
1436:
1437: /* check for control */
1438: for (i = 0; n != 0 && i < istgt->nuctl_portal; i++) {
1439: #ifdef ISTGT_USE_KQUEUE
1440: if (kev.ident == istgt->uctl_portal[i].sock) {
1441: if (kev.flags) {
1442: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1443: "flags %x\n",
1444: kev.flags);
1445: }
1446: #else
1447: if (fds[ucidx + i].revents) {
1448: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1449: "events %x\n",
1450: fds[ucidx + i].revents);
1451: }
1452: if (fds[ucidx + i].revents & POLLIN) {
1453: #endif /* ISTGT_USE_KQUEUE */
1454: n--;
1455: memset(&sa, 0, sizeof(sa));
1456: salen = sizeof(sa);
1457: #ifdef ISTGT_USE_KQUEUE
1458: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1459: "accept %d\n", kev.ident);
1460: rc = accept(kev.ident,
1461: (struct sockaddr *) &sa, &salen);
1462: #else
1463: ISTGT_TRACELOG(ISTGT_TRACE_NET,
1464: "accept %d\n", fds[ucidx + i].fd);
1465: rc = accept(fds[ucidx + i].fd,
1466: (struct sockaddr *) &sa, &salen);
1467: #endif /* ISTGT_USE_KQUEUE */
1468: if (rc < 0) {
1469: ISTGT_ERRLOG("accept error: %d\n", rc);
1470: continue;
1471: }
1472: sock = rc;
1473: rc = istgt_create_uctl(istgt,
1474: &istgt->uctl_portal[i], sock,
1475: (struct sockaddr *) &sa, salen);
1476: if (rc < 0) {
1477: close(sock);
1478: ISTGT_ERRLOG("istgt_create_uctl() failed\n");
1479: continue;
1480: }
1481: }
1482: }
1483: }
1484: #ifdef ISTGT_USE_KQUEUE
1485: close(kq);
1486: #endif /* ISTGT_USE_KQUEUE */
1487: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
1488: istgt_set_state(istgt, ISTGT_STATE_EXITING);
1489:
1490: return 0;
1491: }
1492:
1493: static void
1494: usage(void)
1495: {
1496: printf("istgt [options]\n");
1497: printf("options:\n");
1498: printf(" -c config config file (default %s)\n", DEFAULT_CONFIG);
1499: printf(" -p pidfile use specific file\n");
1500: printf(" -l facility use specific syslog facility (default %s)\n",
1501: DEFAULT_LOG_FACILITY);
1502: printf(" -m mode operational mode (default %d, 0=traditional, "
1503: "1=normal, 2=experimental)\n", DEFAULT_ISTGT_SWMODE);
1504: printf(" -t flag trace flag (all, net, iscsi, scsi, lu)\n");
1505: printf(" -q quiet warnings\n");
1506: printf(" -D don't detach from tty\n");
1507: printf(" -H show this usage\n");
1508: printf(" -V show version\n");
1509: }
1510:
1511: int
1512: main(int argc, char **argv)
1513: {
1514: ISTGT_Ptr istgt;
1515: const char *config_file = DEFAULT_CONFIG;
1516: const char *pidfile = NULL;
1517: const char *logfacility = NULL;
1518: const char *logpriority = NULL;
1519: CONFIG *config;
1520: pthread_t sigthread;
1521: struct sigaction sigact, sigoldact_pipe, sigoldact_info;
1522: struct sigaction sigoldact_wakeup, sigoldact_io;
1523: sigset_t signew, sigold;
1524: int retry = 10;
1525: int detach = 1;
1526: int swmode;
1527: int ch;
1528: int rc;
1529:
1530: if (sizeof (ISCSI_BHS) != ISCSI_BHS_LEN) {
1531: fprintf(stderr, "Internal Error\n");
1532: exit(EXIT_FAILURE);
1533: }
1534:
1535: memset(&g_istgt, 0, sizeof g_istgt);
1536: istgt = &g_istgt;
1537: istgt_set_state(istgt, ISTGT_STATE_INVALID);
1538: istgt->swmode = DEFAULT_ISTGT_SWMODE;
1539:
1540: while ((ch = getopt(argc, argv, "c:p:l:m:t:qDHV")) != -1) {
1541: switch (ch) {
1542: case 'c':
1543: config_file = optarg;
1544: break;
1545: case 'p':
1546: pidfile = optarg;
1547: break;
1548: case 'l':
1549: logfacility = optarg;
1550: break;
1551: case 'm':
1552: swmode = strtol(optarg, NULL, 10);
1553: if (swmode == ISTGT_SWMODE_TRADITIONAL
1554: || swmode == ISTGT_SWMODE_NORMAL
1555: || swmode == ISTGT_SWMODE_EXPERIMENTAL) {
1556: istgt->swmode = swmode;
1557: } else {
1558: fprintf(stderr, "unknown mode %x\n", swmode);
1559: usage();
1560: exit(EXIT_FAILURE);
1561: }
1562: break;
1563: case 't':
1564: if (strcasecmp(optarg, "NET") == 0) {
1565: istgt_set_trace_flag(ISTGT_TRACE_NET);
1566: } else if (strcasecmp(optarg, "ISCSI") == 0) {
1567: istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
1568: } else if (strcasecmp(optarg, "SCSI") == 0) {
1569: istgt_set_trace_flag(ISTGT_TRACE_SCSI);
1570: } else if (strcasecmp(optarg, "LU") == 0) {
1571: istgt_set_trace_flag(ISTGT_TRACE_LU);
1572: } else if (strcasecmp(optarg, "ALL") == 0) {
1573: istgt_set_trace_flag(ISTGT_TRACE_ALL);
1574: } else if (strcasecmp(optarg, "NONE") == 0) {
1575: istgt_set_trace_flag(ISTGT_TRACE_NONE);
1576: } else {
1577: fprintf(stderr, "unknown flag\n");
1578: usage();
1579: exit(EXIT_FAILURE);
1580: }
1581: break;
1582: case 'q':
1583: g_warn_flag = 0;
1584: break;
1585: case 'D':
1586: detach = 0;
1587: break;
1588: case 'V':
1589: printf("istgt version %s\n", ISTGT_VERSION);
1590: printf("istgt extra version %s\n", ISTGT_EXTRA_VERSION);
1591: exit(EXIT_SUCCESS);
1592: case 'H':
1593: default:
1594: usage();
1595: exit(EXIT_SUCCESS);
1596: }
1597: }
1598:
1599: /* read config files */
1600: config = istgt_allocate_config();
1601: rc = istgt_read_config(config, config_file);
1602: if (rc < 0) {
1603: fprintf(stderr, "config error\n");
1604: exit(EXIT_FAILURE);
1605: }
1606: if (config->section == NULL) {
1607: fprintf(stderr, "empty config\n");
1608: istgt_free_config(config);
1609: exit(EXIT_FAILURE);
1610: }
1611: istgt->config = config;
1612: //istgt_print_config(config);
1613:
1614: /* open log files */
1615: if (logfacility == NULL) {
1616: logfacility = istgt_get_log_facility(config);
1617: }
1618: rc = istgt_set_log_facility(logfacility);
1619: if (rc < 0) {
1620: fprintf(stderr, "log facility error\n");
1621: istgt_free_config(config);
1622: exit(EXIT_FAILURE);
1623: }
1624: if (logpriority == NULL) {
1625: logpriority = DEFAULT_LOG_PRIORITY;
1626: }
1627: rc = istgt_set_log_priority(logpriority);
1628: if (rc < 0) {
1629: fprintf(stderr, "log priority error\n");
1630: istgt_free_config(config);
1631: exit(EXIT_FAILURE);
1632: }
1633: istgt_open_log();
1634:
1635: ISTGT_NOTICELOG("istgt version %s (%s)\n", ISTGT_VERSION,
1636: ISTGT_EXTRA_VERSION);
1637: switch (istgt->swmode) {
1638: case ISTGT_SWMODE_TRADITIONAL:
1639: ISTGT_NOTICELOG("traditional mode\n");
1640: break;
1641: case ISTGT_SWMODE_NORMAL:
1642: ISTGT_NOTICELOG("normal mode\n");
1643: break;
1644: case ISTGT_SWMODE_EXPERIMENTAL:
1645: ISTGT_NOTICELOG("experimental mode\n");
1646: break;
1647: default:
1648: break;
1649: }
1650:
1651: #ifdef ISTGT_USE_CRC32C_TABLE
1652: /* build crc32c table */
1653: istgt_init_crc32c_table();
1654: #endif /* ISTGT_USE_CRC32C_TABLE */
1655:
1656: /* initialize sub modules */
1657: rc = istgt_init(istgt);
1658: if (rc < 0) {
1659: ISTGT_ERRLOG("istgt_init() failed\n");
1660: initialize_error:
1661: istgt_close_log();
1662: istgt_free_config(config);
1663: exit(EXIT_FAILURE);
1664: }
1665: rc = istgt_lu_init(istgt);
1666: if (rc < 0) {
1667: ISTGT_ERRLOG("istgt_lu_init() failed\n");
1668: goto initialize_error;
1669: }
1670: rc = istgt_iscsi_init(istgt);
1671: if (rc < 0) {
1672: ISTGT_ERRLOG("istgt_iscsi_init() failed\n");
1673: goto initialize_error;
1674: }
1675:
1676: /* override by command line */
1677: if (pidfile != NULL) {
1678: xfree(istgt->pidfile);
1679: istgt->pidfile = xstrdup(pidfile);
1680: }
1681:
1682: /* detach from tty and run background */
1683: fflush(stdout);
1684: if (detach) {
1685: rc = daemon(0, 0);
1686: if (rc < 0) {
1687: ISTGT_ERRLOG("daemon() failed\n");
1688: goto initialize_error;
1689: }
1690: }
1691:
1692: /* setup signal handler thread */
1693: memset(&sigact, 0, sizeof sigact);
1694: memset(&sigoldact_pipe, 0, sizeof sigoldact_pipe);
1695: memset(&sigoldact_info, 0, sizeof sigoldact_info);
1696: memset(&sigoldact_wakeup, 0, sizeof sigoldact_wakeup);
1697: memset(&sigoldact_io, 0, sizeof sigoldact_io);
1698: sigact.sa_handler = SIG_IGN;
1699: sigemptyset(&sigact.sa_mask);
1700: rc = sigaction(SIGPIPE, &sigact, &sigoldact_pipe);
1701: if (rc < 0) {
1702: ISTGT_ERRLOG("sigaction(SIGPIPE) failed\n");
1703: goto initialize_error;
1704: }
1705: #ifdef SIGINFO
1706: sigact.sa_handler = istgt_siginfo;
1707: sigemptyset(&sigact.sa_mask);
1708: rc = sigaction(SIGINFO, &sigact, &sigoldact_info);
1709: if (rc < 0) {
1710: ISTGT_ERRLOG("sigaction(SIGINFO) failed\n");
1711: goto initialize_error;
1712: }
1713: #endif
1714: #ifdef ISTGT_USE_SIGRT
1715: if (ISTGT_SIGWAKEUP < SIGRTMIN
1716: || ISTGT_SIGWAKEUP > SIGRTMAX) {
1717: ISTGT_ERRLOG("SIGRT error\n");
1718: goto initialize_error;
1719: }
1720: #endif /* ISTGT_USE_SIGRT */
1721: sigact.sa_handler = istgt_sigwakeup;
1722: sigemptyset(&sigact.sa_mask);
1723: rc = sigaction(ISTGT_SIGWAKEUP, &sigact, &sigoldact_wakeup);
1724: if (rc < 0) {
1725: ISTGT_ERRLOG("sigaction(ISTGT_SIGWAKEUP) failed\n");
1726: goto initialize_error;
1727: }
1728: #ifdef SIGIO
1729: sigact.sa_handler = istgt_sigio;
1730: sigemptyset(&sigact.sa_mask);
1731: rc = sigaction(SIGIO, &sigact, &sigoldact_io);
1732: if (rc < 0) {
1733: ISTGT_ERRLOG("sigaction(SIGIO) failed\n");
1734: goto initialize_error;
1735: }
1736: #endif
1737: pthread_sigmask(SIG_SETMASK, NULL, &signew);
1738: sigaddset(&signew, SIGINT);
1739: sigaddset(&signew, SIGTERM);
1740: sigaddset(&signew, SIGQUIT);
1741: sigaddset(&signew, SIGHUP);
1742: #ifdef SIGINFO
1743: sigaddset(&signew, SIGINFO);
1744: #endif
1745: sigaddset(&signew, SIGUSR1);
1746: sigaddset(&signew, SIGUSR2);
1747: #ifdef SIGIO
1748: sigaddset(&signew, SIGIO);
1749: #endif
1750: sigaddset(&signew, ISTGT_SIGWAKEUP);
1751: pthread_sigmask(SIG_SETMASK, &signew, &sigold);
1752: #ifdef ISTGT_STACKSIZE
1753: rc = pthread_create(&sigthread, &istgt->attr, &istgt_sighandler,
1754: #else
1755: rc = pthread_create(&sigthread, NULL, &istgt_sighandler,
1756: #endif
1757: (void *) istgt);
1758: if (rc != 0) {
1759: ISTGT_ERRLOG("pthread_create() failed\n");
1760: goto initialize_error;
1761: }
1762: #if 0
1763: rc = pthread_detach(sigthread);
1764: if (rc != 0) {
1765: ISTGT_ERRLOG("pthread_detach() failed\n");
1766: goto initialize_error;
1767: }
1768: #endif
1769: #ifdef HAVE_PTHREAD_SET_NAME_NP
1770: pthread_set_name_np(sigthread, "sigthread");
1771: pthread_set_name_np(pthread_self(), "mainthread");
1772: #endif
1773:
1774: /* create LUN threads for command queuing */
1775: rc = istgt_lu_create_threads(istgt);
1776: if (rc < 0) {
1777: ISTGT_ERRLOG("lu_create_threads() failed\n");
1778: goto initialize_error;
1779: }
1780: rc = istgt_lu_set_all_state(istgt, ISTGT_STATE_RUNNING);
1781: if (rc < 0) {
1782: ISTGT_ERRLOG("lu_set_all_state() failed\n");
1783: goto initialize_error;
1784: }
1785:
1786: /* open portals */
1787: rc = istgt_open_uctl_portal(istgt);
1788: if (rc < 0) {
1789: ISTGT_ERRLOG("istgt_open_uctl_portal() failed\n");
1790: goto initialize_error;
1791: }
1792: rc = istgt_open_portal(istgt);
1793: if (rc < 0) {
1794: ISTGT_ERRLOG("istgt_open_portal() failed\n");
1795: goto initialize_error;
1796: }
1797:
1798: /* write pid */
1799: rc = istgt_write_pidfile(istgt);
1800: if (rc < 0) {
1801: ISTGT_ERRLOG("istgt_write_pid() failed\n");
1802: goto initialize_error;
1803: }
1804:
1805: /* accept loop */
1806: rc = istgt_acceptor(istgt);
1807: if (rc < 0) {
1808: ISTGT_ERRLOG("istgt_acceptor() failed\n");
1809: istgt_close_portal(istgt);
1810: istgt_close_uctl_portal(istgt);
1811: istgt_iscsi_shutdown(istgt);
1812: istgt_lu_shutdown(istgt);
1813: istgt_destory_initiator_group_array(istgt);
1814: istgt_destroy_portal_array(istgt);
1815: istgt_destroy_uctl_portal(istgt);
1816: istgt_remove_pidfile(istgt);
1817: istgt_close_log();
1818: istgt->config = NULL;
1819: istgt_free_config(config);
1820: exit(EXIT_FAILURE);
1821: }
1822:
1823: /* wait threads */
1824: while (retry > 0) {
1825: if (istgt_get_active_conns() == 0) {
1826: break;
1827: }
1828: sleep(1);
1829: retry--;
1830: }
1831: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "retry=%d\n", retry);
1832:
1833: ISTGT_NOTICELOG("istgt version %s (%s) exiting\n", ISTGT_VERSION,
1834: ISTGT_EXTRA_VERSION);
1835:
1836: /* cleanup */
1837: istgt_close_portal(istgt);
1838: istgt_close_uctl_portal(istgt);
1839: istgt_iscsi_shutdown(istgt);
1840: istgt_lu_shutdown(istgt);
1841: istgt_destory_initiator_group_array(istgt);
1842: istgt_destroy_portal_array(istgt);
1843: istgt_destroy_uctl_portal(istgt);
1844: istgt_remove_pidfile(istgt);
1845: istgt_close_log();
1846: istgt->config = NULL;
1847: istgt_free_config(config);
1848: istgt_set_state(istgt, ISTGT_STATE_SHUTDOWN);
1849:
1850: /* stop signal thread */
1851: rc = pthread_join(sigthread, NULL);
1852: if (rc != 0) {
1853: ISTGT_ERRLOG("pthread_join() failed\n");
1854: exit (EXIT_FAILURE);
1855: }
1856:
1857: return 0;
1858: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>