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
114void *
115iscsi_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
124void           *
125iscsi_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
134void
135iscsi_free_atomic(void *ptr)
136{
137	(void) free(ptr);
138	iscsi_trace(TRACE_MEM, "iscsi_free_atomic(%p)\n", ptr);
139}
140
141void
142iscsi_free(void *ptr)
143{
144	(void) free(ptr);
145	iscsi_trace(TRACE_MEM, "iscsi_free(%p)\n", ptr);
146}
147
148/* debugging levels */
149void
150set_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 */
168int
169iscsi_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 */
185int
186iscsi_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
199void
200iscsi_queue_destroy(iscsi_queue_t * q)
201{
202	iscsi_free_atomic(q->elem);
203}
204
205int
206iscsi_queue_full(iscsi_queue_t * q)
207{
208	return (q->count == q->depth);
209}
210
211int
212iscsi_queue_depth(iscsi_queue_t * q)
213{
214	return q->count;
215}
216
217int
218iscsi_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
238void *
239iscsi_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
260void
261iscsi_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
276void
277iscsi_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
294void
295iscsi_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
311void
312iscsi_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
339int
340hash_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
358int
359hash_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
386struct initiator_cmd_t *
387hash_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
436int
437hash_destroy(hash_t * h)
438{
439	iscsi_free_atomic(h->bucket);
440	return 0;
441}
442
443/*
444 * Socket Functions
445 */
446
447int
448modify_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
521int
522iscsi_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
536int
537iscsi_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
550int
551iscsi_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
563int
564iscsi_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
582int
583iscsi_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
599int
600iscsi_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 */
670const char *
671iscsi_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 */
685int
686iscsi_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
749int
750iscsi_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
767int
768iscsi_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
778int
779iscsi_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
789int
790iscsi_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
801int
802iscsi_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
814int
815iscsi_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
894int
895iscsi_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
1038int
1039iscsi_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 */
1092int
1093iscsi_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
1106int
1107iscsi_spin_lock(iscsi_spin_t * lock)
1108{
1109	return pthread_mutex_lock(lock);
1110}
1111
1112int
1113iscsi_spin_unlock(iscsi_spin_t * lock)
1114{
1115	return pthread_mutex_unlock(lock);
1116}
1117
1118/* ARGSUSED1 */
1119int
1120iscsi_spin_lock_irqsave(iscsi_spin_t * lock, uint32_t *flags)
1121{
1122	return pthread_mutex_lock(lock);
1123}
1124
1125/* ARGSUSED1 */
1126int
1127iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock, uint32_t *flags)
1128{
1129	return pthread_mutex_unlock(lock);
1130}
1131
1132int
1133iscsi_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
1145int
1146iscsi_mutex_init(iscsi_mutex_t * m)
1147{
1148	return (pthread_mutex_init(m, NULL) != 0) ? -1 : 0;
1149}
1150
1151int
1152iscsi_mutex_lock(iscsi_mutex_t * m)
1153{
1154	return pthread_mutex_lock(m);
1155}
1156
1157int
1158iscsi_mutex_unlock(iscsi_mutex_t * m)
1159{
1160	return pthread_mutex_unlock(m);
1161}
1162
1163int
1164iscsi_mutex_destroy(iscsi_mutex_t * m)
1165{
1166	return pthread_mutex_destroy(m);
1167}
1168
1169/*
1170 * Condition Functions
1171 */
1172
1173int
1174iscsi_cond_init(iscsi_cond_t * c)
1175{
1176	return pthread_cond_init(c, NULL);
1177}
1178
1179int
1180iscsi_cond_wait(iscsi_cond_t * c, iscsi_mutex_t * m)
1181{
1182	return pthread_cond_wait(c, m);
1183}
1184
1185int
1186iscsi_cond_signal(iscsi_cond_t * c)
1187{
1188	return pthread_cond_signal(c);
1189}
1190
1191int
1192iscsi_cond_destroy(iscsi_cond_t * c)
1193{
1194	return pthread_cond_destroy(c);
1195}
1196
1197/*
1198 * Misc. Functions
1199 */
1200
1201uint32_t
1202iscsi_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
1212static const char HexString[] = "0123456789abcdef";
1213
1214/* get the hex value (subscript) of the character */
1215static int
1216HexStringIndex(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
1224int
1225HexDataToText(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
1267int
1268HexTextToData(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
1327void
1328GenRandomData(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