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