iscsi tools: fix iscsiadm return value on failed login
[open-iscsi.git] / usr / io.c
blob4a1c145f88630c70798189058782e25576dd6ad7
1 /*
2 * iSCSI I/O Library
4 * Copyright (C) 2002 Cisco Systems, Inc.
5 * maintained by linux-iscsi-devel@lists.sourceforge.net
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * See the file COPYING included with this distribution for more details.
19 #include <string.h>
20 #include <stdint.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/poll.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <ifaddrs.h>
31 #include <netinet/tcp.h>
32 #include <arpa/inet.h>
34 #include "types.h"
35 #include "iscsi_proto.h"
36 #include "iscsi_settings.h"
37 #include "initiator.h"
38 #include "iscsi_ipc.h"
39 #include "log.h"
40 #include "transport.h"
41 #include "idbm.h"
42 #include "iface.h"
43 #include "sysdeps.h"
44 #include "dcb_app.h"
46 #define LOG_CONN_CLOSED(conn) \
47 do { \
48 getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
49 conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
50 log_error("Connection to Discovery Address %s closed", conn->host); \
51 } while (0)
53 #define LOG_CONN_FAIL(conn) \
54 do { \
55 getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
56 conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
57 log_error("Connection to Discovery Address %s failed", conn->host); \
58 } while (0)
60 union sockaddr_u {
61 struct sockaddr_storage ss;
62 struct sockaddr sa;
63 struct sockaddr_in si;
64 struct sockaddr_in6 si6;
67 static int timedout;
69 static void
70 sigalarm_handler(int unused)
72 timedout = 1;
75 static void
76 set_non_blocking(int fd)
78 int res = fcntl(fd, F_GETFL);
80 if (res != -1) {
81 res = fcntl(fd, F_SETFL, res | O_NONBLOCK);
82 if (res)
83 log_warning("unable to set fd flags (%s)!",
84 strerror(errno));
85 } else
86 log_warning("unable to get fd flags (%s)!", strerror(errno));
90 static int select_priority(struct iscsi_conn *conn, int pri_mask)
92 int msk;
94 if (!pri_mask)
95 return 0;
98 * TODO: Configure priority selection from the mask
99 * For now, just always take the highest
102 /* Find highest bit set */
103 while ((msk = pri_mask & (pri_mask - 1)))
104 pri_mask = msk;
106 return ffs(pri_mask) - 1;
109 static int
110 inet_cmp_addr(const union sockaddr_u *s1, const union sockaddr_u *s2)
112 const struct sockaddr_in *si1 = &s1->si;
113 const struct sockaddr_in *si2 = &s2->si;
115 return si1->sin_addr.s_addr != si2->sin_addr.s_addr;
118 static int
119 inet6_cmp_addr(const union sockaddr_u *s1, const union sockaddr_u *s2)
121 const struct sockaddr_in6 *si1 = &s1->si6;
122 const struct sockaddr_in6 *si2 = &s2->si6;
124 return memcmp(&si1->sin6_addr, &si2->sin6_addr, sizeof(si1->sin6_addr));
127 static char *
128 find_ifname(const struct ifaddrs *ifa, const union sockaddr_u *ss)
130 for (; ifa; ifa = ifa->ifa_next) {
131 if (!ifa->ifa_addr)
132 continue;
134 if (ss->ss.ss_family != ifa->ifa_addr->sa_family)
135 continue;
136 switch (ss->ss.ss_family) {
137 case AF_INET:
138 if (inet_cmp_addr(ss, (union sockaddr_u *)ifa->ifa_addr) == 0)
139 return ifa->ifa_name;
140 break;
141 case AF_INET6:
142 if (inet6_cmp_addr(ss, (union sockaddr_u *)ifa->ifa_addr) == 0)
143 return ifa->ifa_name;
144 break;
148 return NULL;
151 static void set_dcb_priority(struct iscsi_conn *conn, const char *devname)
153 int pri_mask = 0;
155 pri_mask = get_dcb_app_pri_by_stream_port(devname, ISCSI_DEFAULT_PORT);
156 if (pri_mask < 0)
157 log_debug(2, "Getting priority for %s returned %d",
158 devname, pri_mask);
159 else if (pri_mask == 0)
160 log_debug(2, "No priority for %s", devname);
161 else {
162 int pri = select_priority(conn, pri_mask);
163 int rc;
165 log_debug(1, "Setting socket %d priority to %d",
166 conn->socket_fd, pri);
167 rc = setsockopt(conn->socket_fd, SOL_SOCKET,
168 SO_PRIORITY, &pri, sizeof(pri));
169 if (rc < 0) {
170 log_warning("Setting socket %d priority to %d failed "
171 "with errno %d", conn->socket_fd,
172 pri, errno);
177 #if 0
178 /* not used by anyone */
179 static int get_hwaddress_from_netdev(char *netdev, char *hwaddress)
181 struct ifaddrs *ifap, *ifa;
182 struct sockaddr_in *s4;
183 struct sockaddr_in6 *s6;
184 struct ifreq if_hwaddr;
185 int found = 0, sockfd;
186 unsigned char *hwaddr;
187 char buf[INET6_ADDRSTRLEN];
189 if (getifaddrs(&ifap)) {
190 log_error("Could not match hwaddress %s to netdev. "
191 "getifaddrs failed %d", hwaddress, errno);
192 return 0;
195 /* Open a basic socket. */
196 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
197 if (sockfd < 0) {
198 log_error("Could not open socket for ioctl.");
199 goto free_ifap;
202 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
203 if (!ifa->ifa_addr)
204 continue;
206 switch (ifa->ifa_addr->sa_family) {
207 case AF_INET:
208 s4 = (struct sockaddr_in *)(ifa->ifa_addr);
209 if (!inet_ntop(ifa->ifa_addr->sa_family,
210 (void *)&(s4->sin_addr), buf,
211 INET_ADDRSTRLEN))
212 continue;
213 log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
214 break;
215 case AF_INET6:
216 s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
217 if (!inet_ntop(ifa->ifa_addr->sa_family,
218 (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN))
219 continue;
220 log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
221 break;
222 default:
223 continue;
226 if (strcmp(ifa->ifa_name, netdev))
227 continue;
229 strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ);
230 if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
231 log_error("Could not match %s to netdevice.",
232 hwaddress);
233 continue;
236 /* check for ARPHRD_ETHER (ethernet) */
237 if (if_hwaddr.ifr_hwaddr.sa_family != 1)
238 continue;
239 hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
241 memset(hwaddress, 0, ISCSI_MAX_IFACE_LEN);
242 /* TODO should look and covert so we do not need tmp buf */
243 sprintf(hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
244 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
245 hwaddr[4], hwaddr[5]);
246 log_debug(4, "Found hardware address %s", hwaddress);
247 found = 1;
248 break;
251 close(sockfd);
252 free_ifap:
253 freeifaddrs(ifap);
254 return found;
256 #endif
259 #if 0
261 This is not supported for now, because it is not exactly what we want.
262 It also turns out that targets will send packets to other interfaces
263 causing all types of weird things to happen.
266 static int bind_src_by_address(int sockfd, char *address)
268 int rc = 0;
269 char port[NI_MAXSERV];
270 struct sockaddr_storage saddr;
272 memset(&saddr, 0, sizeof(struct sockaddr_storage));
273 if (resolve_address(address, port, &saddr)) {
274 log_error("Could not bind %s to conn.", address);
275 return -1;
278 switch (saddr.ss_family) {
279 case AF_INET:
280 rc = bind(sockfd, (struct sockaddr *)&saddr,
281 sizeof(struct sockaddr_in));
282 break;
283 case AF_INET6:
284 rc = bind(sockfd, (struct sockaddr *)&saddr,
285 sizeof(struct sockaddr_in6));
286 break;
287 default:
288 rc = -1;
290 if (rc)
291 log_error("Could not bind %s to %d.", address, sockfd);
292 else
293 log_debug(4, "Bound %s to socket fd %d", address, sockfd);
294 return rc;
296 #endif
298 static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface)
300 struct iscsi_session *session = conn->session;
302 if (strcmp(iface->transport_name, DEFAULT_TRANSPORT))
303 return 0;
305 memset(session->netdev, 0, IFNAMSIZ);
306 if (iface_is_bound_by_hwaddr(iface)) {
307 if (net_get_netdev_from_hwaddress(iface->hwaddress,
308 session->netdev)) {
309 log_error("Cannot match %s to net/scsi interface.",
310 iface->hwaddress);
311 return -1;
313 } else if (iface_is_bound_by_netdev(iface)) {
314 strcpy(session->netdev, iface->netdev);
315 } else if (iface_is_bound_by_ipaddr(iface)) {
317 * we never supported this but now with offload having to
318 * set the ip address in the iface, useris may forget to
319 * set the offload's transport type and we end up here by
320 * accident.
322 log_error("Cannot bind %s to net/scsi interface. This is not "
323 "supported with software iSCSI (iscsi_tcp).",
324 iface->ipaddress);
325 return -1;
328 if (strlen(session->netdev)) {
329 struct ifreq ifr;
331 log_debug(4, "Binding session %d to %s", session->id,
332 session->netdev);
333 memset(&ifr, 0, sizeof(ifr));
334 strlcpy(ifr.ifr_name, session->netdev, IFNAMSIZ);
336 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
337 session->netdev,
338 strlen(session->netdev) + 1) < 0) {
339 log_error("Could not bind connection %d to %s\n",
340 conn->id, session->netdev);
341 return -1;
345 return 0;
349 iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
351 int rc, onearg;
352 struct sockaddr_storage *ss = &conn->saddr;
353 char serv[NI_MAXSERV];
355 /* create a socket */
356 conn->socket_fd = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
358 /* the trasport ep handle is used to bind with */
359 conn->transport_ep_handle = conn->socket_fd;
361 if (conn->socket_fd < 0) {
362 log_error("cannot create TCP socket");
363 return -1;
366 if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
367 return -1;
369 onearg = 1;
370 rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
371 sizeof (onearg));
372 if (rc < 0) {
373 log_error("cannot set TCP_NODELAY option on socket");
374 close(conn->socket_fd);
375 conn->socket_fd = -1;
376 return rc;
379 /* optionally set the window sizes */
380 if (conn->tcp_window_size) {
381 int window_size = conn->tcp_window_size;
382 socklen_t arglen = sizeof (window_size);
384 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
385 (char *) &window_size, sizeof (window_size)) < 0) {
386 log_warning("failed to set TCP recv window size "
387 "to %u", window_size);
388 } else {
389 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
390 (char *) &window_size, &arglen) >= 0) {
391 log_debug(4, "set TCP recv window size to %u, "
392 "actually got %u",
393 conn->tcp_window_size, window_size);
397 window_size = conn->tcp_window_size;
398 arglen = sizeof (window_size);
400 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
401 (char *) &window_size, sizeof (window_size)) < 0) {
402 log_warning("failed to set TCP send window size "
403 "to %u", window_size);
404 } else {
405 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
406 (char *) &window_size, &arglen) >= 0) {
407 log_debug(4, "set TCP send window size to %u, "
408 "actually got %u",
409 conn->tcp_window_size, window_size);
415 * Build a TCP connection to the target
417 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
418 conn->host, sizeof(conn->host), serv, sizeof(serv),
419 NI_NUMERICHOST|NI_NUMERICSERV);
421 log_debug(1, "connecting to %s:%s", conn->host, serv);
422 if (non_blocking)
423 set_non_blocking(conn->socket_fd);
425 if (conn->session->netdev[0])
426 set_dcb_priority(conn, conn->session->netdev);
428 rc = connect(conn->socket_fd, (struct sockaddr *) ss, sizeof (*ss));
429 return rc;
433 iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
435 int rc;
436 struct pollfd pdesc;
437 char serv[NI_MAXSERV], lserv[NI_MAXSERV];
438 struct sockaddr_storage ss;
439 socklen_t len;
441 pdesc.fd = conn->socket_fd;
442 pdesc.events = POLLOUT;
443 rc = poll(&pdesc, 1, timeout_ms);
444 if (rc == 0)
445 return 0;
447 if (rc < 0) {
448 getnameinfo((struct sockaddr *) &conn->saddr,
449 sizeof(conn->saddr),
450 conn->host, sizeof(conn->host), serv, sizeof(serv),
451 NI_NUMERICHOST|NI_NUMERICSERV);
453 log_error("cannot make connection to %s:%s (%s)",
454 conn->host, serv, strerror(errno));
455 return rc;
458 len = sizeof(int);
459 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
460 (char *) &rc, &len) < 0) {
461 log_error("getsockopt for connect poll failed\n");
462 return -1;
464 if (rc) {
465 getnameinfo((struct sockaddr *) &conn->saddr,
466 sizeof(conn->saddr),
467 conn->host, sizeof(conn->host), serv, sizeof(serv),
468 NI_NUMERICHOST|NI_NUMERICSERV);
470 log_error("connect to %s:%s failed (%s)\n",
471 conn->host, serv, strerror(rc));
472 return -rc;
475 len = sizeof(ss);
476 if (log_level > 0 || !conn->session->netdev[0])
477 rc = getsockname(conn->socket_fd, (struct sockaddr *)&ss, &len);
478 if (log_level > 0 && rc >= 0) {
479 getnameinfo((struct sockaddr *) &conn->saddr,
480 sizeof(conn->saddr), conn->host,
481 sizeof(conn->host), serv, sizeof(serv),
482 NI_NUMERICHOST|NI_NUMERICSERV);
484 getnameinfo((struct sockaddr *) &ss, sizeof(ss),
485 NULL, 0, lserv, sizeof(lserv), NI_NUMERICSERV);
487 log_debug(1, "connected local port %s to %s:%s",
488 lserv, conn->host, serv);
491 if (!conn->session->netdev[0] && rc >= 0) {
492 struct ifaddrs *ifa;
493 char *ifname;
495 rc = getifaddrs(&ifa);
496 if (rc < 0)
497 log_error("getifaddrs failed with %d\n", errno);
498 else {
499 ifname = find_ifname(ifa, (union sockaddr_u *)&ss);
500 if (ifname)
501 set_dcb_priority(conn, ifname);
502 freeifaddrs(ifa);
506 return 1;
509 void
510 iscsi_io_tcp_disconnect(iscsi_conn_t *conn)
512 if (conn->socket_fd >= 0) {
513 log_debug(1, "disconnecting conn %p, fd %d", conn,
514 conn->socket_fd);
515 close(conn->socket_fd);
516 conn->socket_fd = -1;
521 iscsi_io_connect(iscsi_conn_t *conn)
523 int rc, ret;
524 struct sigaction action;
525 struct sigaction old;
527 /* set a timeout, since the socket calls may take a long time to
528 * timeout on their own
530 memset(&action, 0, sizeof (struct sigaction));
531 memset(&old, 0, sizeof (struct sigaction));
532 action.sa_sigaction = NULL;
533 action.sa_flags = 0;
534 action.sa_handler = sigalarm_handler;
535 sigaction(SIGALRM, &action, &old);
536 timedout = 0;
537 alarm(conn->login_timeout);
539 /* perform blocking TCP connect operation when no async request
540 * associated. SendTargets Discovery know to work in such a mode.
542 rc = iscsi_io_tcp_connect(conn, 0);
543 if (timedout) {
544 log_error("connect to %s timed out", conn->host);
546 log_debug(1, "socket %d connect timed out", conn->socket_fd);
547 ret = 0;
548 goto done;
549 } else if (rc < 0) {
550 log_error("cannot make connection to %s: %s",
551 conn->host, strerror(errno));
552 close(conn->socket_fd);
553 ret = 0;
554 goto done;
555 } else if (log_level > 0) {
556 struct sockaddr_storage ss;
557 char lserv[NI_MAXSERV];
558 char serv[NI_MAXSERV];
559 socklen_t salen = sizeof(ss);
561 if (getsockname(conn->socket_fd, (struct sockaddr *) &ss,
562 &salen) >= 0) {
563 getnameinfo((struct sockaddr *) &conn->saddr,
564 sizeof(conn->saddr),
565 conn->host, sizeof(conn->host), serv,
566 sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
568 getnameinfo((struct sockaddr *) &ss,
569 sizeof(ss),
570 NULL, 0, lserv, sizeof(lserv),
571 NI_NUMERICSERV);
573 log_debug(1, "connected local port %s to %s:%s",
574 lserv, conn->host, serv);
578 ret = 1;
580 done:
581 alarm(0);
582 sigaction(SIGALRM, &old, NULL);
583 return ret;
586 void
587 iscsi_io_disconnect(iscsi_conn_t *conn)
589 iscsi_io_tcp_disconnect(conn);
592 static void
593 iscsi_log_text(struct iscsi_hdr *pdu, char *data)
595 int dlength = ntoh24(pdu->dlength);
596 char *text = data;
597 char *end = text + dlength;
599 while (text && (text < end)) {
600 log_debug(4, "> %s", text);
601 text += strlen(text);
602 while ((text < end) && (*text == '\0'))
603 text++;
608 iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
609 int hdr_digest, char *data, int data_digest, int timeout)
611 int rc, ret = 0;
612 char *header = (char *) hdr;
613 char *end;
614 char pad[4];
615 struct iovec vec[3];
616 int pad_bytes;
617 int pdu_length = sizeof (*hdr) + hdr->hlength + ntoh24(hdr->dlength);
618 int remaining;
619 struct sigaction action;
620 struct sigaction old;
621 iscsi_session_t *session = conn->session;
623 /* set a timeout, since the socket calls may take a long time
624 * to timeout on their own
626 if (!session->use_ipc) {
627 memset(&action, 0, sizeof (struct sigaction));
628 memset(&old, 0, sizeof (struct sigaction));
629 action.sa_sigaction = NULL;
630 action.sa_flags = 0;
631 action.sa_handler = sigalarm_handler;
632 sigaction(SIGALRM, &action, &old);
633 timedout = 0;
634 alarm(timeout);
637 memset(&pad, 0, sizeof (pad));
638 memset(&vec, 0, sizeof (vec));
640 switch (hdr->opcode & ISCSI_OPCODE_MASK) {
641 case ISCSI_OP_LOGIN:{
642 struct iscsi_login *login_hdr = (struct iscsi_login *) hdr;
644 log_debug(4, "sending login PDU with current stage "
645 "%d, next stage %d, transit 0x%x, isid"
646 " 0x%02x%02x%02x%02x%02x%02x exp_statsn %u",
647 ISCSI_LOGIN_CURRENT_STAGE(login_hdr->flags),
648 ISCSI_LOGIN_NEXT_STAGE(login_hdr->flags),
649 login_hdr->flags & ISCSI_FLAG_LOGIN_TRANSIT,
650 login_hdr->isid[0], login_hdr->isid[1],
651 login_hdr->isid[2], login_hdr->isid[3],
652 login_hdr->isid[4], login_hdr->isid[5],
653 ntohl(login_hdr->exp_statsn));
655 iscsi_log_text(hdr, data);
656 break;
658 case ISCSI_OP_TEXT:{
659 struct iscsi_text *text_hdr = (struct iscsi_text *) hdr;
661 log_debug(4, "sending text pdu with CmdSN %x, exp_statsn %u",
662 ntohl(text_hdr->cmdsn), ntohl(text_hdr->cmdsn));
663 iscsi_log_text(hdr, data);
664 break;
666 case ISCSI_OP_NOOP_OUT:{
667 struct iscsi_nopout *nopout_hdr = (struct iscsi_nopout *) hdr;
669 log_debug(4, "sending Nop-out pdu with ttt %x, CmdSN %x:",
670 ntohl(nopout_hdr->ttt), ntohl(nopout_hdr->cmdsn));
671 iscsi_log_text(hdr, data);
672 break;
674 default:
675 log_debug(4, "sending pdu opcode 0x%x:", hdr->opcode);
676 break;
679 /* send the PDU header */
680 header = (char *) hdr;
681 end = header + sizeof (*hdr) + hdr->hlength;
683 /* send all the data and any padding */
684 if (pdu_length % ISCSI_PAD_LEN)
685 pad_bytes = ISCSI_PAD_LEN - (pdu_length % ISCSI_PAD_LEN);
686 else
687 pad_bytes = 0;
689 if (session->use_ipc)
690 ipc->send_pdu_begin(session->t->handle, session->id,
691 conn->id, end - header,
692 ntoh24(hdr->dlength) + pad_bytes);
694 while (header < end) {
695 vec[0].iov_base = header;
696 vec[0].iov_len = end - header;
698 if (!session->use_ipc)
699 rc = writev(conn->socket_fd, vec, 1);
700 else
701 rc = ipc->writev(0, vec, 1);
702 if (timedout) {
703 log_error("socket %d write timed out",
704 conn->socket_fd);
705 ret = 0;
706 goto done;
707 } else if ((rc <= 0) && (errno != EAGAIN)) {
708 LOG_CONN_FAIL(conn);
709 ret = 0;
710 goto done;
711 } else if (rc > 0) {
712 log_debug(4, "wrote %d bytes of PDU header", rc);
713 header += rc;
717 end = data + ntoh24(hdr->dlength);
718 remaining = ntoh24(hdr->dlength) + pad_bytes;
720 while (remaining > 0) {
721 vec[0].iov_base = data;
722 vec[0].iov_len = end - data;
723 vec[1].iov_base = (void *) &pad;
724 vec[1].iov_len = pad_bytes;
726 if (!session->use_ipc)
727 rc = writev(conn->socket_fd, vec, 2);
728 else
729 rc = ipc->writev(0, vec, 2);
730 if (timedout) {
731 log_error("socket %d write timed out",
732 conn->socket_fd);
733 ret = 0;
734 goto done;
735 } else if ((rc <= 0) && (errno != EAGAIN)) {
736 LOG_CONN_FAIL(conn);
737 ret = 0;
738 goto done;
739 } else if (rc > 0) {
740 log_debug(4, "wrote %d bytes of PDU data", rc);
741 remaining -= rc;
742 if (data < end) {
743 data += rc;
744 if (data > end)
745 data = end;
750 if (session->use_ipc) {
751 if (ipc->send_pdu_end(session->t->handle, session->id,
752 conn->id, &rc)) {
753 ret = 0;
754 goto done;
758 ret = 1;
760 done:
761 if (!session->use_ipc) {
762 alarm(0);
763 sigaction(SIGALRM, &old, NULL);
764 timedout = 0;
766 return ret;
770 iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
771 int hdr_digest, char *data, int max_data_length, int data_digest,
772 int timeout)
774 uint32_t h_bytes = 0;
775 uint32_t ahs_bytes = 0;
776 uint32_t d_bytes = 0;
777 uint32_t ahslength = 0;
778 uint32_t dlength = 0;
779 uint32_t pad = 0;
780 int rlen = 0;
781 int failed = 0;
782 char *header = (char *) hdr;
783 char *end = data + max_data_length;
784 struct sigaction action;
785 struct sigaction old;
786 iscsi_session_t *session = conn->session;
788 memset(data, 0, max_data_length);
790 /* set a timeout, since the socket calls may take a long
791 * time to timeout on their own
793 if (!session->use_ipc) {
794 memset(&action, 0, sizeof (struct sigaction));
795 memset(&old, 0, sizeof (struct sigaction));
796 action.sa_sigaction = NULL;
797 action.sa_flags = 0;
798 action.sa_handler = sigalarm_handler;
799 sigaction(SIGALRM, &action, &old);
800 timedout = 0;
801 alarm(timeout);
802 } else {
803 failed = ipc->recv_pdu_begin(conn);
804 if (failed == -EAGAIN)
805 return -EAGAIN;
806 else if (failed < 0) {
807 failed = 1;
808 goto done;
812 /* read a response header */
813 do {
814 if (!session->use_ipc)
815 rlen = read(conn->socket_fd, header,
816 sizeof (*hdr) - h_bytes);
817 else
818 rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
819 if (timedout) {
820 log_error("socket %d header read timed out",
821 conn->socket_fd);
822 failed = 1;
823 goto done;
824 } else if (rlen == 0) {
825 LOG_CONN_CLOSED(conn);
826 failed = 1;
827 goto done;
828 } else if ((rlen < 0) && (errno != EAGAIN)) {
829 LOG_CONN_FAIL(conn);
830 failed = 1;
831 goto done;
832 } else if (rlen > 0) {
833 log_debug(4, "read %d bytes of PDU header", rlen);
834 header += rlen;
835 h_bytes += rlen;
837 } while (h_bytes < sizeof (*hdr));
839 log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
840 "data %p, max %u", h_bytes, hdr->opcode & ISCSI_OPCODE_MASK,
841 ntoh24(hdr->dlength), data, max_data_length);
843 /* check for additional headers */
844 ahslength = hdr->hlength; /* already includes padding */
845 if (ahslength) {
846 log_warning("additional header segment length %u not supported",
847 ahslength);
848 failed = 1;
849 goto done;
852 /* read exactly what we expect, plus padding */
853 dlength = hdr->dlength[0] << 16;
854 dlength |= hdr->dlength[1] << 8;
855 dlength |= hdr->dlength[2];
857 /* if we only expected to receive a header, exit */
858 if (dlength == 0)
859 goto done;
861 if (data + dlength > end) {
862 log_warning("buffer size %u too small for data length %u",
863 max_data_length, dlength);
864 failed = 1;
865 goto done;
868 /* read the rest into our buffer */
869 d_bytes = 0;
870 while (d_bytes < dlength) {
871 if (!session->use_ipc)
872 rlen = read(conn->socket_fd, data + d_bytes,
873 dlength - d_bytes);
874 else
875 rlen = ipc->read(data + d_bytes, dlength - d_bytes);
876 if (timedout) {
877 log_error("socket %d data read timed out",
878 conn->socket_fd);
879 failed = 1;
880 goto done;
881 } else if (rlen == 0) {
882 LOG_CONN_CLOSED(conn);
883 failed = 1;
884 goto done;
885 } else if ((rlen < 0 && errno != EAGAIN)) {
886 LOG_CONN_FAIL(conn);
887 failed = 1;
888 goto done;
889 } else if (rlen > 0) {
890 log_debug(4, "read %d bytes of PDU data", rlen);
891 d_bytes += rlen;
895 /* handle PDU data padding.
896 * data is padded in case of kernel_io */
897 pad = dlength % ISCSI_PAD_LEN;
898 if (pad && !session->use_ipc) {
899 int pad_bytes = pad = ISCSI_PAD_LEN - pad;
900 char bytes[ISCSI_PAD_LEN];
902 while (pad_bytes > 0) {
903 rlen = read(conn->socket_fd, &bytes, pad_bytes);
904 if (timedout) {
905 log_error("socket %d pad read timed out",
906 conn->socket_fd);
907 failed = 1;
908 goto done;
909 } else if (rlen == 0) {
910 LOG_CONN_CLOSED(conn);
911 failed = 1;
912 goto done;
913 } else if ((rlen < 0 && errno != EAGAIN)) {
914 LOG_CONN_FAIL(conn);
915 failed = 1;
916 goto done;
917 } else if (rlen > 0) {
918 log_debug(4, "read %d pad bytes", rlen);
919 pad_bytes -= rlen;
924 switch (hdr->opcode) {
925 case ISCSI_OP_TEXT_RSP:
926 log_debug(4, "finished reading text PDU, %u hdr, %u "
927 "ah, %u data, %u pad",
928 h_bytes, ahs_bytes, d_bytes, pad);
929 iscsi_log_text(hdr, data);
930 break;
931 case ISCSI_OP_LOGIN_RSP:{
932 struct iscsi_login_rsp *login_rsp =
933 (struct iscsi_login_rsp *) hdr;
935 log_debug(4, "finished reading login PDU, %u hdr, "
936 "%u ah, %u data, %u pad",
937 h_bytes, ahs_bytes, d_bytes, pad);
938 log_debug(4, "login current stage %d, next stage "
939 "%d, transit 0x%x",
940 ISCSI_LOGIN_CURRENT_STAGE(login_rsp->flags),
941 ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags),
942 login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT);
943 iscsi_log_text(hdr, data);
944 break;
946 case ISCSI_OP_ASYNC_EVENT:
947 /* FIXME: log the event info */
948 break;
949 default:
950 break;
953 done:
954 if (!session->use_ipc) {
955 alarm(0);
956 sigaction(SIGALRM, &old, NULL);
957 } else {
958 /* finalyze receive transaction */
959 if (ipc->recv_pdu_end(conn)) {
960 failed = 1;
964 if (timedout || failed) {
965 timedout = 0;
966 return -EIO;
969 return h_bytes + ahs_bytes + d_bytes;