xref: /netbsd-src/external/bsd/iscsi/dist/src/lib/util.c (revision 690d5174455c318c8bdc5818b004c24dd4e992d5)
1 /*
2  * IMPORTANT:  READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3  * By downloading, copying, installing or using the software you agree
4  * to this license.  If you do not agree to this license, do not
5  * download, install, copy or use the software.
6  *
7  * Intel License Agreement
8  *
9  * Copyright (c) 2000, Intel Corporation
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * -Redistributions of source code must retain the above copyright
17  *  notice, this list of conditions and the following disclaimer.
18  *
19  * -Redistributions in binary form must reproduce the above copyright
20  *  notice, this list of conditions and the following disclaimer in the
21  *  documentation and/or other materials provided with the
22  *  distribution.
23  *
24  * -The name of Intel Corporation may not be used to endorse or
25  *  promote products derived from this software without specific prior
26  *  written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL INTEL
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41 #include "config.h"
42 
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
49 
50 #ifdef HAVE_SYS_UIO_H
51 #include <sys/uio.h>
52 #endif
53 
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
57 
58 #ifdef HAVE_NETINET_IN_H
59 #include <netinet/in.h>
60 #endif
61 
62 #ifdef HAVE_NETINET_TCP_H
63 #include <netinet/tcp.h>
64 #endif
65 
66 #ifdef HAVE_NETDB_H
67 #include <netdb.h>
68 #endif
69 
70 #ifdef HAVE_CTYPE_H
71 #include <ctype.h>
72 #endif
73 
74 #ifdef HAVE_ERRNO_H
75 #include <errno.h>
76 #endif
77 
78 #ifdef HAVE_PTHREAD_H
79 #include <pthread.h>
80 #endif
81 
82 #ifdef HAVE_STDARG_H
83 #include <stdarg.h>
84 #endif
85 
86 #ifdef HAVE_SYS_SELECT_H
87 #include <sys/select.h>
88 #endif
89 
90 #ifdef HAVE_POLL_H
91 #include <poll.h>
92 #endif
93 
94 #include <stdio.h>
95 #include <stdlib.h>
96 
97 #ifdef HAVE_STRING_H
98 #include <string.h>
99 #endif
100 
101 #include <unistd.h>
102 
103 #include "compat.h"
104 
105 #define EXTERN
106 #include "iscsiutil.h"
107 
108 
109 
110 /*
111  * Memory Allocation
112  */
113 
114 void *
iscsi_malloc_atomic(unsigned n)115 iscsi_malloc_atomic(unsigned n)
116 {
117 	void           *ptr;
118 
119 	ptr = malloc(n);
120 	iscsi_trace(TRACE_MEM, "iscsi_malloc_atomic(%u) = %p\n", n, ptr);
121 	return ptr;
122 }
123 
124 void           *
iscsi_malloc(unsigned n)125 iscsi_malloc(unsigned n)
126 {
127 	void           *ptr;
128 
129 	ptr = malloc(n);
130 	iscsi_trace(TRACE_MEM, "iscsi_malloc(%u) = %p\n", n, ptr);
131 	return ptr;
132 }
133 
134 void
iscsi_free_atomic(void * ptr)135 iscsi_free_atomic(void *ptr)
136 {
137 	iscsi_trace(TRACE_MEM, "iscsi_free_atomic(%p)\n", ptr);
138 	(void) free(ptr);
139 }
140 
141 void
iscsi_free(void * ptr)142 iscsi_free(void *ptr)
143 {
144 	iscsi_trace(TRACE_MEM, "iscsi_free(%p)\n", ptr);
145 	(void) free(ptr);
146 }
147 
148 /* debugging levels */
149 void
set_debug(const char * level)150 set_debug(const char *level)
151 {
152 	if (strcmp(level, "net") == 0) {
153 		iscsi_debug_level |= TRACE_NET_ALL;
154 	} else if (strcmp(level, "iscsi") == 0) {
155 		iscsi_debug_level |= TRACE_ISCSI_ALL;
156 	} else if (strcmp(level, "scsi") == 0) {
157 		iscsi_debug_level |= TRACE_SCSI_ALL;
158 	} else if (strcmp(level, "osd") == 0) {
159 		iscsi_debug_level |= TRACE_OSD;
160 	} else if (strcmp(level, "all") == 0) {
161 		iscsi_debug_level |= TRACE_ALL;
162 	}
163 }
164 
165 /*
166  * Threading Routines
167  */
168 int
iscsi_thread_create(iscsi_thread_t * thread,void * (* proc)(void *),void * arg)169 iscsi_thread_create(iscsi_thread_t * thread, void *(*proc) (void *), void *arg)
170 {
171 	if (pthread_create(&thread->pthread, NULL, proc, arg) != 0) {
172 		iscsi_err(__FILE__, __LINE__, "pthread_create() failed\n");
173 		return -1;
174 	}
175 	if (pthread_detach(thread->pthread) != 0) {
176 		iscsi_err(__FILE__, __LINE__, "pthread_detach() failed\n");
177 		return -1;
178 	}
179 	return 0;
180 }
181 
182 /*
183  * Queuing Functions
184  */
185 int
iscsi_queue_init(iscsi_queue_t * q,int depth)186 iscsi_queue_init(iscsi_queue_t * q, int depth)
187 {
188 	q->head = q->tail = q->count = 0;
189 	q->depth = depth;
190 	q->elem = iscsi_malloc_atomic((unsigned)(depth * sizeof(void *)));
191 	if (q->elem == NULL) {
192 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
193 		return -1;
194 	}
195 	iscsi_spin_init(&q->lock);
196 	return 0;
197 }
198 
199 void
iscsi_queue_destroy(iscsi_queue_t * q)200 iscsi_queue_destroy(iscsi_queue_t * q)
201 {
202 	iscsi_free_atomic(q->elem);
203 }
204 
205 int
iscsi_queue_full(iscsi_queue_t * q)206 iscsi_queue_full(iscsi_queue_t * q)
207 {
208 	return (q->count == q->depth);
209 }
210 
211 int
iscsi_queue_depth(iscsi_queue_t * q)212 iscsi_queue_depth(iscsi_queue_t * q)
213 {
214 	return q->count;
215 }
216 
217 int
iscsi_queue_insert(iscsi_queue_t * q,void * ptr)218 iscsi_queue_insert(iscsi_queue_t * q, void *ptr)
219 {
220 	uint32_t   flags;
221 
222 	iscsi_spin_lock_irqsave(&q->lock, &flags);
223 	if (iscsi_queue_full(q)) {
224 		iscsi_err(__FILE__, __LINE__, "QUEUE FULL\n");
225 		iscsi_spin_unlock_irqrestore(&q->lock, &flags);
226 		return -1;
227 	}
228 	q->elem[q->tail] = ptr;
229 	q->tail++;
230 	if (q->tail == q->depth) {
231 		q->tail = 0;
232 	}
233 	q->count++;
234 	iscsi_spin_unlock_irqrestore(&q->lock, &flags);
235 	return 0;
236 }
237 
238 void *
iscsi_queue_remove(iscsi_queue_t * q)239 iscsi_queue_remove(iscsi_queue_t *q)
240 {
241 	uint32_t	flags = 0;
242 	void           *ptr;
243 
244 	iscsi_spin_lock_irqsave(&q->lock, &flags);
245 	if (!iscsi_queue_depth(q)) {
246 		iscsi_trace(TRACE_QUEUE, "QUEUE EMPTY\n");
247 		iscsi_spin_unlock_irqrestore(&q->lock, &flags);
248 		return NULL;
249 	}
250 	q->count--;
251 	ptr = q->elem[q->head];
252 	q->head++;
253 	if (q->head == q->depth) {
254 		q->head = 0;
255 	}
256 	iscsi_spin_unlock_irqrestore(&q->lock, &flags);
257 	return ptr;
258 }
259 
260 void
iscsi_trace(const int trace,const char * fmt,...)261 iscsi_trace(const int trace, const char *fmt, ...)
262 {
263 #ifdef CONFIG_ISCSI_DEBUG
264 	va_list	vp;
265 	char	buf[8192];
266 
267 	if (iscsi_debug_level & trace) {
268 		va_start(vp, fmt);
269 		(void) vsnprintf(buf, sizeof(buf), fmt, vp);
270 		printf("pid %d: %s", (int) getpid(), buf);
271 		va_end(vp);
272 	}
273 #endif
274 }
275 
276 void
iscsi_warn(const char * f,const int line,const char * fmt,...)277 iscsi_warn(const char *f, const int line, const char *fmt, ...)
278 {
279 #ifdef CONFIG_ISCSI_DEBUG
280 	va_list	vp;
281 	char	buf[8192];
282 
283 	if (iscsi_debug_level & TRACE_WARN) {
284 		va_start(vp, fmt);
285 		(void) vsnprintf(buf, sizeof(buf), fmt, vp);
286 		printf("pid %d:%s:%d: ***WARNING*** %s",
287 			(int) getpid(), f, line,
288 			buf);
289 		va_end(vp);
290 	}
291 #endif
292 }
293 
294 void
iscsi_err(const char * f,const int line,const char * fmt,...)295 iscsi_err(const char *f, const int line, const char *fmt, ...)
296 {
297 #ifdef CONFIG_ISCSI_DEBUG
298 	va_list	vp;
299 	char	buf[8192];
300 
301 	va_start(vp, fmt);
302 	(void) vsnprintf(buf, sizeof(buf), fmt, vp);
303 	va_end(vp);
304 	printf("pid %d:%s:%d: ***ERROR*** %s", (int) getpid(), f, line, buf);
305 #  ifdef HAVE_SYSLOG
306 	syslog(LOG_ERR, "pid %d:%s:%d: ***ERROR*** %s", getpid(), f, line, buf);
307 #  endif /* HAVE_SYSLOG */
308 #endif
309 }
310 
311 void
iscsi_print_buffer(const char * buf,const size_t len)312 iscsi_print_buffer(const char *buf, const size_t len)
313 {
314 #ifdef CONFIG_ISCSI_DEBUG
315 	size_t	i;
316 
317 	if (iscsi_debug_level & TRACE_NET_BUFF) {
318 		for (i=0 ; i < len; i++) {
319 			if (i % 4 == 0) {
320 				if (i) {
321 					printf("\n");
322 				}
323 				printf("%4zu:", i);
324 			}
325 			printf("%2x ", (uint8_t) (buf)[i]);
326 		}
327 		if ((len + 1) % 32) {
328 			printf("\n");
329 		}
330 	}
331 #endif
332 }
333 
334 /*
335  * Hashing Functions
336  */
337 #include "initiator.h"
338 
339 int
hash_init(hash_t * h,int n)340 hash_init(hash_t * h, int n)
341 {
342 	int	i;
343 
344 	iscsi_spin_init(&h->lock);
345 	h->n = n;
346 	h->insertions = 0;
347 	h->collisions = 0;
348 	h->bucket = iscsi_malloc_atomic(n * sizeof(initiator_cmd_t *));
349 	if (h->bucket == NULL) {
350 		iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
351 		return -1;
352 	}
353 	for (i = 0; i < n; i++)
354 		h->bucket[i] = NULL;
355 	return 0;
356 }
357 
358 int
hash_insert(hash_t * h,initiator_cmd_t * cmd,unsigned key)359 hash_insert(hash_t * h, initiator_cmd_t * cmd, unsigned key)
360 {
361 	int	i;
362 
363 	iscsi_spin_lock(&h->lock);
364 	cmd->hash_next = NULL;
365 	cmd->key = key;
366 
367 	i = key % (h->n);
368 	if (h->bucket[i] == NULL) {
369 		iscsi_trace(TRACE_HASH,
370 			"inserting key %u (val 0x%p) into bucket[%d]\n",
371 			key, cmd, i);
372 		h->bucket[i] = cmd;
373 	} else {
374 		cmd->hash_next = h->bucket[i];
375 		h->bucket[i] = cmd;
376 		h->collisions++;
377 		iscsi_trace(TRACE_HASH,
378 			"inserting key %u (val 0x%p) into bucket[%d] "
379 			"(collision)\n", key, cmd, i);
380 	}
381 	h->insertions++;
382 	iscsi_spin_unlock(&h->lock);
383 	return 0;
384 }
385 
386 struct initiator_cmd_t *
hash_remove(hash_t * h,unsigned key)387 hash_remove(hash_t * h, unsigned key)
388 {
389 	initiator_cmd_t	*prev;
390 	initiator_cmd_t	*curr;
391 	int		 i;
392 
393 	iscsi_spin_lock(&h->lock);
394 	i = key % (h->n);
395 	if (h->bucket[i] == NULL) {
396 		iscsi_err(__FILE__, __LINE__, "bucket emtpy\n");
397 		curr = NULL;
398 	} else {
399 		prev = NULL;
400 		curr = h->bucket[i];
401 		while ((curr->key != key) && (curr->hash_next != NULL)) {
402 			prev = curr;
403 			curr = curr->hash_next;
404 		}
405 		if (curr->key != key) {
406 			iscsi_err(__FILE__, __LINE__,
407 				"key %u (%#x) not found in bucket[%d]\n",
408 				key, key, i);
409 			curr = NULL;
410 		} else {
411 			if (prev == NULL) {
412 				h->bucket[i] = h->bucket[i]->hash_next;
413 				iscsi_trace(TRACE_HASH,
414 					"removed key %u (val 0x%p) from head "
415 					"of bucket\n", key, curr);
416 			} else {
417 				prev->hash_next = curr->hash_next;
418 				if (prev->hash_next == NULL) {
419 					iscsi_trace(TRACE_HASH,
420 						"removed key %u (val 0x%p) "
421 						"from end of bucket\n", key,
422 						curr);
423 				} else {
424 					iscsi_trace(TRACE_HASH,
425 						"removed key %u (val 0x%p) "
426 						"from middle of bucket\n",
427 						key, curr);
428 				}
429 			}
430 		}
431 	}
432 	iscsi_spin_unlock(&h->lock);
433 	return curr;
434 }
435 
436 int
hash_destroy(hash_t * h)437 hash_destroy(hash_t * h)
438 {
439 	iscsi_free_atomic(h->bucket);
440 	return 0;
441 }
442 
443 /*
444  * Socket Functions
445  */
446 
447 int
modify_iov(struct iovec ** iov_ptr,int * iovc,uint32_t offset,uint32_t length)448 modify_iov(struct iovec ** iov_ptr, int *iovc, uint32_t offset, uint32_t length)
449 {
450 	size_t		len;
451 	int             disp = offset;
452 	int             i;
453 	struct iovec   *iov = *iov_ptr;
454 	char		*basep;
455 
456 	/* Given <offset>, find beginning iovec and modify its base
457 	* and length */
458 	len = 0;
459 	for (i = 0; i < *iovc; i++) {
460 		len += iov[i].iov_len;
461 		if (len > offset) {
462 			iscsi_trace(TRACE_NET_IOV,
463 				"found offset %u in iov[%d]\n", offset, i);
464 			break;
465 		}
466 		disp -= iov[i].iov_len;
467 	}
468 	if (i == *iovc) {
469 		iscsi_err(__FILE__, __LINE__,
470 			"sum of iov lens (%zu) < offset (%u)\n", len, offset);
471 		return -1;
472 	}
473 	iov[i].iov_len -= disp;
474 	basep = iov[i].iov_base;
475 	basep += disp;
476 	iov[i].iov_base = basep;
477 	*iovc -= i;
478 	*iov_ptr = &(iov[i]);
479 	iov = *iov_ptr;
480 
481 	/*
482 	 * Given <length>, find ending iovec and modify its length (base does
483 	 * not change)
484 	 */
485 	len = 0;		/* we should re-use len and i here... */
486 	for (i = 0; i < *iovc; i++) {
487 		len += iov[i].iov_len;
488 		if (len >= length) {
489 			iscsi_trace(TRACE_NET_IOV,
490 				"length %u ends in iovec[%d]\n", length, i);
491 			break;
492 		}
493 	}
494 	if (i == *iovc) {
495 		iscsi_err(__FILE__, __LINE__,
496 			"sum of iovec lens (%zu) < length (%u)\n", len, length);
497 		for (i = 0; i < *iovc; i++) {
498 			iscsi_err(__FILE__, __LINE__,
499 				"iov[%d].iov_base = %p (len %u)\n",
500 				i, iov[i].iov_base, (unsigned)iov[i].iov_len);
501 		}
502 		return -1;
503 	}
504 	iov[i].iov_len -= (len - length);
505 	*iovc = i + 1;
506 
507 #ifdef CONFIG_ISCSI_DEBUG
508 	iscsi_trace(TRACE_NET_IOV, "new iov:\n");
509 	len = 0;
510 	for (i = 0; i < *iovc; i++) {
511 		iscsi_trace(TRACE_NET_IOV, "iov[%d].iov_base = %p (len %u)\n",
512 			i, iov[i].iov_base, (unsigned)iov[i].iov_len);
513 		len += iov[i].iov_len;
514 	}
515 	iscsi_trace(TRACE_NET_IOV, "new iov length: %zu bytes\n", len);
516 #endif
517 
518 	return 0;
519 }
520 
521 int
iscsi_sock_setsockopt(int * sock,int level,int optname,void * optval,unsigned optlen)522 iscsi_sock_setsockopt(int * sock, int level, int optname, void *optval,
523 	unsigned  optlen)
524 {
525 	int             rc;
526 
527 	if ((rc = setsockopt(*sock, level, optname, optval, optlen)) != 0) {
528 		iscsi_err(__FILE__, __LINE__,
529 			"sock->ops->setsockopt() failed: rc %d errno %d\n",
530 			rc, errno);
531 		return 0;
532 	}
533 	return 1;
534 }
535 
536 int
iscsi_sock_getsockopt(int * sock,int level,int optname,void * optval,unsigned * optlen)537 iscsi_sock_getsockopt(int * sock, int level, int optname, void *optval, unsigned *optlen)
538 {
539 	int             rc;
540 
541 	if ((rc = getsockopt(*sock, level, optname, optval, optlen)) != 0) {
542 		iscsi_err(__FILE__, __LINE__,
543 			"sock->ops->getsockopt() failed: rc %d errno %d\n",
544 			rc, errno);
545 		return 0;
546 	}
547 	return 1;
548 }
549 
550 int
iscsi_sock_create(int * sock)551 iscsi_sock_create(int * sock)
552 {
553 	int             rc;
554 
555 	if ((*sock = rc = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
556 		iscsi_err(__FILE__, __LINE__,
557 			"socket() failed: rc %d errno %d\n", rc, errno);
558 		return 0;
559 	}
560 	return 1;
561 }
562 
563 int
iscsi_sock_bind(int sock,int port)564 iscsi_sock_bind(int sock, int port)
565 {
566 	struct sockaddr_in	laddr;
567 	int			rc;
568 
569 	(void) memset(&laddr, 0x0, sizeof(laddr));
570 	laddr.sin_family = AF_INET;
571 	laddr.sin_addr.s_addr = INADDR_ANY;
572 	laddr.sin_port = ISCSI_HTONS(port);
573 	rc = bind(sock, (struct sockaddr *) (void *) &laddr, sizeof(laddr));
574 	if (rc < 0) {
575 		iscsi_err(__FILE__, __LINE__,
576 			"bind() failed: rc %d errno %d\n", rc, errno);
577 		return 0;
578 	}
579 	return 1;
580 }
581 
582 int
iscsi_sock_listen(int sock)583 iscsi_sock_listen(int sock)
584 {
585 	int             rc;
586 
587 	if ((rc = listen(sock, 32)) < 0) {
588 		iscsi_err(__FILE__, __LINE__,
589 			"listen() failed: rc %d errno %d\n", rc, errno);
590 		return 0;
591 	}
592 	return 1;
593 }
594 
595 #ifndef ISCSI_MAXSOCK
596 #define ISCSI_MAXSOCK	8
597 #endif
598 
599 int
iscsi_socks_establish(int * sockv,int * famv,int * sockc,char * family,int port)600 iscsi_socks_establish(int *sockv, int *famv, int *sockc, char *family, int port)
601 {
602 	struct addrinfo		hints;
603 	struct addrinfo		*res;
604 	struct addrinfo		*res0;
605 	const char		*cause = NULL;
606 	char			 portnum[31];
607 	int			one = 1;
608 	int			error;
609 
610 	(void) memset(&hints, 0x0, sizeof(hints));
611 	hints.ai_family = (strcmp(family, "unspec") == 0) ? PF_UNSPEC :
612 				(strcmp(family, "4") == 0) ? AF_INET : AF_INET6;
613 	hints.ai_socktype = SOCK_STREAM;
614 	hints.ai_flags = AI_PASSIVE;
615 #ifdef AI_NUMERICSERV
616 	hints.ai_flags |= AI_NUMERICSERV;
617 #endif
618 	(void) snprintf(portnum, sizeof(portnum), "%d", port);
619 	if ((error = getaddrinfo(NULL, portnum, &hints, &res0)) != 0) {
620 		hints.ai_flags = AI_PASSIVE;
621 		if ((error = getaddrinfo(NULL, "iscsi-target", &hints,
622 					&res0)) != 0 ||
623 		    (error = getaddrinfo(NULL, "iscsi", &hints, &res0)) != 0) {
624 			iscsi_err(__FILE__, __LINE__, "getaddrinfo: %s",
625 				gai_strerror(error));
626 			return 0;
627 		}
628 	}
629 	*sockc = 0;
630 	for (res = res0; res && *sockc < ISCSI_MAXSOCK; res = res->ai_next) {
631 		sockv[*sockc] = socket(res->ai_family, res->ai_socktype,
632 					res->ai_protocol);
633 		if (sockv[*sockc] < 0) {
634 			cause = "socket";
635 			continue;
636 		}
637 		famv[*sockc] = res->ai_family;
638 		if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_SOCKET,
639 				SO_REUSEADDR, &one, sizeof(one))) {
640 			iscsi_err(__FILE__, __LINE__,
641 				"iscsi_sock_setsockopt() failed\n");
642 			continue;
643 		}
644 		if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_TCP,
645 				TCP_NODELAY, &one, sizeof(one))) {
646 			iscsi_err(__FILE__, __LINE__,
647 				"iscsi_sock_setsockopt() failed\n");
648 			continue;
649 		}
650 
651 		if (bind(sockv[*sockc], res->ai_addr, res->ai_addrlen) < 0) {
652 			cause = "bind";
653 			close(sockv[*sockc]);
654 			continue;
655 		}
656 		(void) listen(sockv[*sockc], 32);
657 		*sockc += 1;
658 	}
659 	if (*sockc == 0) {
660 		iscsi_err(__FILE__, __LINE__,
661 			"iscsi_sock_establish: no sockets found: %s", cause);
662 		freeaddrinfo(res0);
663 		return 0;
664 	}
665 	freeaddrinfo(res0);
666 	return 1;
667 }
668 
669 /* return the address family for the socket */
670 const char *
iscsi_address_family(int fam)671 iscsi_address_family(int fam)
672 {
673 	switch(fam) {
674 	case 4:
675 		return "IPv4";
676 	case 6:
677 		return "IPv6";
678 	default:
679 		return "[unknown type]";
680 	}
681 }
682 
683 /* wait for a connection to come in on a socket */
684 /* ARGSUSED2 */
685 int
iscsi_waitfor_connection(int * sockv,int sockc,const char * cf,int * sock)686 iscsi_waitfor_connection(int *sockv, int sockc, const char *cf, int *sock)
687 {
688 #ifdef HAVE_POLL
689 	struct pollfd	socks[ISCSI_MAXSOCK];
690 	int		i;
691 
692 	for (;;) {
693 		for (i = 0 ; i < sockc ; i++) {
694 			socks[i].fd = sockv[i];
695 			socks[i].events = POLLIN;
696 			socks[i].revents = 0;
697 		}
698 		switch(poll(socks, (unsigned)sockc, INFTIM)) {
699 		case -1:
700 			/* interrupted system call */
701 			continue;
702 		case 0:
703 			/* timeout */
704 			continue;
705 		default:
706 			for (i = 0 ; i < sockc ; i++) {
707 				if (socks[i].revents & POLLIN) {
708 					iscsi_trace(TRACE_NET_DEBUG,
709 						"connection %d selected\n",
710 						sockv[i]);
711 					*sock = sockv[i];
712 					return i;
713 				}
714 			}
715 		}
716 	}
717 #else
718 	fd_set		infds;
719 	int		i;
720 
721 	for (;;) {
722 		FD_ZERO(&infds);
723 		for (i = 0 ; i < sockc ; i++) {
724 			FD_SET(sockv[i], &infds);
725 		}
726 		iscsi_trace(TRACE_NET_DEBUG, "waiting for connection\n");
727 		switch (select(32, &infds, NULL, NULL, NULL)) {
728 		case -1:
729 			/* interrupted system call */
730 			continue;
731 		case 0:
732 			/* timeout */
733 			continue;
734 		default:
735 			for (i = 0 ; i < sockc ; i++) {
736 				if (FD_ISSET(sockv[i], &infds)) {
737 					iscsi_trace(TRACE_NET_DEBUG,
738 						"connection %d selected\n",
739 						sockv[i]);
740 					*sock = sockv[i];
741 					return i;
742 				}
743 			}
744 		}
745 	}
746 #endif
747 }
748 
749 int
iscsi_sock_accept(int sock,int * conn)750 iscsi_sock_accept(int sock, int *conn)
751 {
752 	struct sockaddr_in peer;
753 	socklen_t	peerlen;
754 
755 	peerlen = sizeof(peer);
756 	(void) memset(&peer, 0, sizeof(peer));
757 	*conn = accept(sock, (struct sockaddr *)(void *)&peer, &peerlen);
758 	if (*conn < 0) {
759 		iscsi_trace(TRACE_NET_DEBUG,
760 			"accept() failed: rc %d errno %d\n", *conn, errno);
761 		return 0;
762 	}
763 
764 	return 1;
765 }
766 
767 int
iscsi_sock_getsockname(int sock,struct sockaddr * name,unsigned * namelen)768 iscsi_sock_getsockname(int sock, struct sockaddr * name, unsigned *namelen)
769 {
770 	if (getsockname(sock, name, namelen) != 0) {
771 		iscsi_err(__FILE__, __LINE__,
772 			"getsockame() failed (errno %d)\n", errno);
773 		return 0;
774 	}
775 	return 1;
776 }
777 
778 int
iscsi_sock_getpeername(int sock,struct sockaddr * name,unsigned * namelen)779 iscsi_sock_getpeername(int sock, struct sockaddr * name, unsigned *namelen)
780 {
781 	if (getpeername(sock, name, namelen) != 0) {
782 		iscsi_err(__FILE__, __LINE__,
783 			"getpeername() failed (errno %d)\n", errno);
784 		return 0;
785 	}
786 	return 1;
787 }
788 
789 int
iscsi_sock_shutdown(int sock,int how)790 iscsi_sock_shutdown(int sock, int how)
791 {
792 	int             rc;
793 
794 	if ((rc = shutdown(sock, how)) != 0) {
795 		iscsi_trace(TRACE_NET_DEBUG,
796 			"shutdown() failed: rc %d, errno %d\n", rc, errno);
797 	}
798 	return 0;
799 }
800 
801 int
iscsi_sock_close(int sock)802 iscsi_sock_close(int sock)
803 {
804 	int             rc;
805 
806 	if ((rc = close(sock)) != 0) {
807 		iscsi_err(__FILE__, __LINE__,
808 			"close() failed: rc %d errno %d\n", rc, errno);
809 		return -1;
810 	}
811 	return 0;
812 }
813 
814 int
iscsi_sock_connect(int sock,char * hostname,int port)815 iscsi_sock_connect(int sock, char *hostname, int port)
816 {
817 	struct addrinfo	hints;
818 	struct addrinfo	*res;
819 	char		portstr[32];
820 	int             rc = 0;
821 	int             i;
822 
823 	(void) memset(&hints, 0, sizeof(hints));
824 	hints.ai_family = AF_INET;
825 	hints.ai_socktype = SOCK_STREAM;
826 	(void) snprintf(portstr, sizeof(portstr), "%d", port);
827 
828 	for (i = 0; i < ISCSI_SOCK_CONNECT_TIMEOUT; i++) {
829 		/* Attempt connection */
830 #ifdef AI_NUMERICSERV
831 		hints.ai_flags = AI_NUMERICSERV;
832 #endif
833 		if ((rc = getaddrinfo(hostname, portstr, &hints, &res)) != 0) {
834 			hints.ai_flags = 0;
835 			if ((rc = getaddrinfo(hostname, "iscsi-target", &hints,
836 						&res)) != 0 ||
837 			    (rc = getaddrinfo(hostname, "iscsi", &hints,
838 			    			&res)) != 0) {
839 				iscsi_err(__FILE__, __LINE__,
840 					"getaddrinfo: %s", gai_strerror(rc));
841 				return 0;
842 			    }
843 		}
844 
845 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1
846 		if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
847 			iscsi_err(__FILE__, __LINE__,
848 					"fcntl O_NONBLOCK failed");
849 			freeaddrinfo(res);
850 			return -1;
851 		}
852 #endif
853 		rc = connect(sock, res->ai_addr, res->ai_addrlen);
854 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1
855 		if (fcntl(sock, F_SETFL, O_SYNC) != 0) {
856 			iscsi_err(__FILE__, __LINE__, "fcntl O_SYNC failed\n");
857 			freeaddrinfo(res);
858 			return -1;
859 		}
860 #endif
861 
862 		/* Check errno */
863 		if (errno == EISCONN) {
864 			rc = 0;
865 			break;
866 		}
867 		if (errno == EAGAIN ||
868 		    errno == EINPROGRESS ||
869 		    errno == EALREADY) {
870 			if (i != ISCSI_SOCK_CONNECT_TIMEOUT - 1) {
871 				printf("***SLEEPING***\n");
872 				sleep(1);
873 			}
874 		} else {
875 			break;
876 		}
877 	}
878 	freeaddrinfo(res);
879 	if (rc < 0) {
880 		iscsi_err(__FILE__, __LINE__,
881 			"connect() to %s:%d failed (errno %d)\n", hostname,
882 			port, errno);
883 	}
884 	return rc;
885 }
886 
887 /*
888  * NOTE:  iscsi_sock_msg() alters *sg when socket sends and recvs
889  * return having only transfered a portion of the iovec.  When this
890  * happens, the iovec is modified and resent with the appropriate
891  * offsets.
892  */
893 
894 int
iscsi_sock_msg(int sock,int xmit,unsigned len,void * data,int iovc)895 iscsi_sock_msg(int sock, int xmit, unsigned len, void *data, int iovc)
896 {
897 	struct iovec    singleton;
898 	struct iovec   *iov;
899 	struct iovec   *iov_padding = NULL;
900 	unsigned	n = 0;
901 	uint32_t        remainder;
902 	uint32_t        padding_len = 0;
903 	uint8_t		padding[ISCSI_SOCK_MSG_BYTE_ALIGN];
904 	size_t		total_len = 0;
905 	int		rc;
906 	int             i;
907 
908 	iscsi_trace(TRACE_NET_DEBUG, "%s %d bytes on sock\n",
909 			xmit ? "sending" : "receiving", len);
910 	if (iovc == 0) {
911 		iscsi_trace(TRACE_NET_DEBUG,
912 			"building singleton iovec (data %p, len %u)\n",
913 			data, len);
914 		singleton.iov_base = data;
915 		singleton.iov_len = len;
916 		iov = &singleton;
917 		iovc = 1;
918 	} else {
919 		iov = (struct iovec *) data;
920 	}
921 
922 	/* Add padding */
923 
924 	if ((remainder = len % ISCSI_SOCK_MSG_BYTE_ALIGN) != 0) {
925 		iov_padding = iscsi_malloc_atomic((iovc + 1) *
926 					sizeof(struct iovec));
927 		if (iov_padding == NULL) {
928 			iscsi_err(__FILE__, __LINE__,
929 				"iscsi_malloc_atomic() failed\n");
930 			return -1;
931 		}
932 		memcpy(iov_padding, iov, iovc * sizeof(struct iovec));
933 		iov_padding[iovc].iov_base = padding;
934 		padding_len = ISCSI_SOCK_MSG_BYTE_ALIGN - remainder;
935 		iov_padding[iovc].iov_len = padding_len;
936 		iov = iov_padding;
937 		iovc++;
938 		memset(padding, 0, padding_len);
939 		len += padding_len;
940 		iscsi_trace(TRACE_NET_DEBUG,
941 			"Added iovec for padding (len %u)\n", padding_len);
942 	}
943 
944 	/*
945 	 * We make copy of iovec if we're in debugging mode, as we'll
946 	 * print out the iovec and the buffer contents at the end of
947 	 * this subroutine and
948 	 */
949 	do {
950 		/* Check iovec */
951 
952 		total_len = 0;
953 		iscsi_trace(TRACE_NET_DEBUG, "%s %d buffers\n",
954 			xmit ? "gathering from" : "scattering into", iovc);
955 		for (i = 0; i < iovc; i++) {
956 			iscsi_trace(TRACE_NET_IOV,
957 				"iov[%d].iov_base = %p, len %u\n",
958 				i, iov[i].iov_base, (unsigned)iov[i].iov_len);
959 			total_len += iov[i].iov_len;
960 		}
961 		if (total_len != len - n) {
962 			iscsi_err(__FILE__, __LINE__,
963 				"iovcs sum to %zu != total len of %u\n",
964 				total_len, len - n);
965 			iscsi_err(__FILE__, __LINE__, "iov = %p\n", iov);
966 			for (i = 0; i < iovc; i++) {
967 				iscsi_err(__FILE__, __LINE__,
968 					"iov[%d].iov_base = %p, len %u\n",
969 					i, iov[i].iov_base,
970 					(unsigned)iov[i].iov_len);
971 			}
972 			return -1;
973 		}
974 		if ((rc = (xmit) ? writev(sock, iov, iovc) :
975 				   readv(sock, iov, iovc)) == 0) {
976 			iscsi_trace(TRACE_NET_DEBUG,
977 				"%s() failed: rc %d errno %d\n",
978 				(xmit) ? "writev" : "readv", rc, errno);
979 			break;
980 		} else if (rc < 0) {
981 			/* Temp FIXME */
982 			iscsi_err(__FILE__, __LINE__,
983 				"%s() failed: rc %d errno %d\n",
984 				(xmit) ? "writev" : "readv", rc, errno);
985 			break;
986 		}
987 		n += rc;
988 		if (n < len) {
989 			iscsi_trace(TRACE_NET_DEBUG,
990 				"Got partial %s: %d bytes of %u\n",
991 				(xmit) ? "send" : "recv", rc, len - n + rc);
992 			total_len = 0;
993 			for (i = 0; i < iovc; i++) {
994 				total_len += iov[i].iov_len;
995 			}
996 			iscsi_trace(TRACE_NET_IOV,
997 				"before modify_iov: %s %d buffers, "
998 				"total_len = %zu, n = %u, rc = %u\n",
999 				xmit ? "gathering from" : "scattering into",
1000 				iovc, total_len, n, rc);
1001 			if (modify_iov(&iov, &iovc, (unsigned) rc, len - n)
1002 						!= 0) {
1003 				iscsi_err(__FILE__, __LINE__,
1004 					"modify_iov() failed\n");
1005 				break;
1006 			}
1007 			total_len = 0;
1008 			for (i = 0; i < iovc; i++) {
1009 				total_len += iov[i].iov_len;
1010 			}
1011 			iscsi_trace(TRACE_NET_IOV,
1012 				"after modify_iov: %s %d buffers, "
1013 				"total_len = %zu, n = %u, rc = %u\n\n",
1014 				xmit ? "gathering from" : "scattering into",
1015 				iovc, total_len, n, rc);
1016 		}
1017 	} while (n < len);
1018 
1019 	if (remainder) {
1020 		iscsi_free_atomic(iov_padding);
1021 	}
1022 	iscsi_trace(TRACE_NET_DEBUG,
1023 		"successfully %s %u bytes on sock (%u bytes padding)\n",
1024 		xmit ? "sent" : "received", n, padding_len);
1025 	return n - padding_len;
1026 }
1027 
1028 /*
1029  * Temporary Hack:
1030  *
1031  * TCP's Nagle algorithm and delayed-ack lead to poor performance when we send
1032  * two small messages back to back (i.e., header+data). The TCP_NODELAY option
1033  * is supposed to turn off Nagle, but it doesn't seem to work on Linux 2.4.
1034  * Because of this, if our data payload is small, we'll combine the header and
1035  * data, else send as two separate messages.
1036  */
1037 
1038 int
iscsi_sock_send_header_and_data(int sock,void * header,unsigned header_len,const void * data,unsigned data_len,int iovc)1039 iscsi_sock_send_header_and_data(int sock,
1040 				void *header, unsigned header_len,
1041 				const void *data, unsigned data_len, int iovc)
1042 {
1043 	struct iovec	iov[ISCSI_MAX_IOVECS];
1044 
1045 	if (data_len && data_len <= ISCSI_SOCK_HACK_CROSSOVER) {
1046 		/* combine header and data into one iovec */
1047 		if (iovc >= ISCSI_MAX_IOVECS) {
1048 			iscsi_err(__FILE__, __LINE__,
1049 				"iscsi_sock_msg() failed\n");
1050 			return -1;
1051 		}
1052 		if (iovc == 0) {
1053 			iov[0].iov_base = header;
1054 			iov[0].iov_len = header_len;
1055 			iov[1].iov_base = __UNCONST((const char *)data);
1056 			iov[1].iov_len = data_len;
1057 			iovc = 2;
1058 		} else {
1059 			iov[0].iov_base = header;
1060 			iov[0].iov_len = header_len;
1061 			(void) memcpy(&iov[1], data, sizeof(struct iovec) *
1062 					iovc);
1063 			iovc += 1;
1064 		}
1065 		if ((unsigned)iscsi_sock_msg(sock, Transmit,
1066 			header_len + data_len, iov, iovc) !=
1067 				header_len + data_len) {
1068 			iscsi_err(__FILE__, __LINE__,
1069 					"iscsi_sock_msg() failed\n");
1070 			return -1;
1071 		}
1072 	} else {
1073 		if ((unsigned)iscsi_sock_msg(sock, Transmit, header_len,
1074 					header, 0) != header_len) {
1075 			iscsi_err(__FILE__, __LINE__,
1076 				"iscsi_sock_msg() failed\n");
1077 			return -1;
1078 		}
1079 		if (data_len != 0 &&
1080 		    (unsigned)iscsi_sock_msg(sock, Transmit, data_len,
1081 		    	__UNCONST((const char *) data), iovc) != data_len) {
1082 			iscsi_err(__FILE__, __LINE__,
1083 					"iscsi_sock_msg() failed\n");
1084 			return -1;
1085 		}
1086 	}
1087 	return header_len + data_len;
1088 }
1089 
1090 
1091 /* spin lock functions */
1092 int
iscsi_spin_init(iscsi_spin_t * lock)1093 iscsi_spin_init(iscsi_spin_t * lock)
1094 {
1095 	pthread_mutexattr_t mattr;
1096 
1097 	pthread_mutexattr_init(&mattr);
1098 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP
1099 	pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
1100 #endif
1101 	if (pthread_mutex_init(lock, &mattr) != 0)
1102 		return -1;
1103 	return 0;
1104 }
1105 
1106 int
iscsi_spin_lock(iscsi_spin_t * lock)1107 iscsi_spin_lock(iscsi_spin_t * lock)
1108 {
1109 	return pthread_mutex_lock(lock);
1110 }
1111 
1112 int
iscsi_spin_unlock(iscsi_spin_t * lock)1113 iscsi_spin_unlock(iscsi_spin_t * lock)
1114 {
1115 	return pthread_mutex_unlock(lock);
1116 }
1117 
1118 /* ARGSUSED1 */
1119 int
iscsi_spin_lock_irqsave(iscsi_spin_t * lock,uint32_t * flags)1120 iscsi_spin_lock_irqsave(iscsi_spin_t * lock, uint32_t *flags)
1121 {
1122 	return pthread_mutex_lock(lock);
1123 }
1124 
1125 /* ARGSUSED1 */
1126 int
iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock,uint32_t * flags)1127 iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock, uint32_t *flags)
1128 {
1129 	return pthread_mutex_unlock(lock);
1130 }
1131 
1132 int
iscsi_spin_destroy(iscsi_spin_t * lock)1133 iscsi_spin_destroy(iscsi_spin_t * lock)
1134 {
1135 	return pthread_mutex_destroy(lock);
1136 }
1137 
1138 
1139 /*
1140  * Mutex Functions, kernel module doesn't require mutex for locking.
1141  * For thread sync, 'down' & 'up' have been wrapped into condition
1142  * varibles, which is kernel semaphores in kernel module.
1143  */
1144 
1145 int
iscsi_mutex_init(iscsi_mutex_t * m)1146 iscsi_mutex_init(iscsi_mutex_t * m)
1147 {
1148 	return (pthread_mutex_init(m, NULL) != 0) ? -1 : 0;
1149 }
1150 
1151 int
iscsi_mutex_lock(iscsi_mutex_t * m)1152 iscsi_mutex_lock(iscsi_mutex_t * m)
1153 {
1154 	return pthread_mutex_lock(m);
1155 }
1156 
1157 int
iscsi_mutex_unlock(iscsi_mutex_t * m)1158 iscsi_mutex_unlock(iscsi_mutex_t * m)
1159 {
1160 	return pthread_mutex_unlock(m);
1161 }
1162 
1163 int
iscsi_mutex_destroy(iscsi_mutex_t * m)1164 iscsi_mutex_destroy(iscsi_mutex_t * m)
1165 {
1166 	return pthread_mutex_destroy(m);
1167 }
1168 
1169 /*
1170  * Condition Functions
1171  */
1172 
1173 int
iscsi_cond_init(iscsi_cond_t * c)1174 iscsi_cond_init(iscsi_cond_t * c)
1175 {
1176 	return pthread_cond_init(c, NULL);
1177 }
1178 
1179 int
iscsi_cond_wait(iscsi_cond_t * c,iscsi_mutex_t * m)1180 iscsi_cond_wait(iscsi_cond_t * c, iscsi_mutex_t * m)
1181 {
1182 	return pthread_cond_wait(c, m);
1183 }
1184 
1185 int
iscsi_cond_signal(iscsi_cond_t * c)1186 iscsi_cond_signal(iscsi_cond_t * c)
1187 {
1188 	return pthread_cond_signal(c);
1189 }
1190 
1191 int
iscsi_cond_destroy(iscsi_cond_t * c)1192 iscsi_cond_destroy(iscsi_cond_t * c)
1193 {
1194 	return pthread_cond_destroy(c);
1195 }
1196 
1197 /*
1198  * Misc. Functions
1199  */
1200 
1201 uint32_t
iscsi_atoi(char * value)1202 iscsi_atoi(char *value)
1203 {
1204 	if (value == NULL) {
1205 		iscsi_err(__FILE__, __LINE__,
1206 			"iscsi_atoi() called with NULL value\n");
1207 		return 0;
1208 	}
1209 	return atoi(value);
1210 }
1211 
1212 static const char HexString[] = "0123456789abcdef";
1213 
1214 /* get the hex value (subscript) of the character */
1215 static int
HexStringIndex(const char * s,int c)1216 HexStringIndex(const char *s, int c)
1217 {
1218 	const char	*cp;
1219 
1220 	return (c == '0') ? 0 :
1221 		((cp = strchr(s, tolower(c))) == NULL) ? -1 : (int)(cp - s);
1222 }
1223 
1224 int
HexDataToText(uint8_t * data,uint32_t dataLength,char * text,uint32_t textLength)1225 HexDataToText(uint8_t *data, uint32_t dataLength,
1226 	      char *text, uint32_t textLength)
1227 {
1228 	uint32_t   n;
1229 
1230 	if (!text || textLength == 0) {
1231 		return -1;
1232 	}
1233 	if (!data || dataLength == 0) {
1234 		*text = 0x0;
1235 		return -1;
1236 	}
1237 	if (textLength < 3) {
1238 		*text = 0x0;
1239 		return -1;
1240 	}
1241 	*text++ = '0';
1242 	*text++ = 'x';
1243 
1244 	textLength -= 2;
1245 
1246 	while (dataLength > 0) {
1247 
1248 		if (textLength < 3) {
1249 			*text = 0x0;
1250 			return -1;
1251 		}
1252 		n = *data++;
1253 		dataLength--;
1254 
1255 		*text++ = HexString[(n >> 4) & 0xf];
1256 		*text++ = HexString[n & 0xf];
1257 
1258 		textLength -= 2;
1259 	}
1260 
1261 	*text = 0x0;
1262 
1263 	return 0;
1264 }
1265 
1266 
1267 int
HexTextToData(const char * text,uint32_t textLength,uint8_t * data,uint32_t dataLength)1268 HexTextToData(const char *text, uint32_t textLength,
1269 	      uint8_t *data, uint32_t dataLength)
1270 {
1271 	int             i;
1272 	uint32_t    n1;
1273 	uint32_t    n2;
1274 	uint32_t    len = 0;
1275 
1276 	if ((text[0] == '0') && (text[1] == 'x' || text[1] == 'X')) {
1277 		/* skip prefix */
1278 		text += 2;
1279 		textLength -= 2;
1280 	}
1281 	if ((textLength % 2) == 1) {
1282 
1283 		i = HexStringIndex(HexString, *text++);
1284 		if (i < 0)
1285 			return -1;	/* error, bad character */
1286 
1287 		n2 = i;
1288 
1289 		if (dataLength < 1) {
1290 			return -1;	/* error, too much data */
1291 		}
1292 		*data++ = n2;
1293 		len++;
1294 	}
1295 	while (*text != 0x0) {
1296 
1297 		if ((i = HexStringIndex(HexString, *text++)) < 0) {
1298 			/* error, bad character */
1299 			return -1;
1300 		}
1301 
1302 		n1 = i;
1303 
1304 		if (*text == 0x0) {
1305 			/* error, odd string length */
1306 			return -1;
1307 		}
1308 
1309 		if ((i = HexStringIndex(HexString, *text++)) < 0) {
1310 			/* error, bad character */
1311 			return -1;
1312 		}
1313 
1314 		n2 = i;
1315 
1316 		if (len >= dataLength) {
1317 			/* error, too much data */
1318 			return len;
1319 		}
1320 		*data++ = (n1 << 4) | n2;
1321 		len++;
1322 	}
1323 
1324 	return (len == 0) ? -1 : 0;
1325 }
1326 
1327 void
GenRandomData(uint8_t * data,uint32_t length)1328 GenRandomData(uint8_t *data, uint32_t length)
1329 {
1330 	uint32_t	n;
1331 	size_t		i;
1332 
1333 	for (i = 0 ; i < length ; i += sizeof(n)) {
1334 		n = random();
1335 		(void) memcpy(&data[i], &n, MIN(length - i, sizeof(n)));
1336 	}
1337 }
1338