2.6.27 kernel compat patch
[open-iscsi.git] / usr / io.c
blob8fb806d14fad2b29ec7569f11f372849bd663ede
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 <netinet/tcp.h>
30 #include <arpa/inet.h>
32 #include "types.h"
33 #include "iscsi_proto.h"
34 #include "initiator.h"
35 #include "iscsi_ipc.h"
36 #include "log.h"
37 #include "transport.h"
38 #include "idbm.h"
39 #include "iface.h"
40 #include "sysdeps.h"
42 #define LOG_CONN_CLOSED(conn) \
43 do { \
44 getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
45 conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
46 log_error("Connection to Discovery Address %s closed", conn->host); \
47 } while (0)
49 #define LOG_CONN_FAIL(conn) \
50 do { \
51 getnameinfo((struct sockaddr *) &conn->saddr, sizeof(conn->saddr), \
52 conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST); \
53 log_error("Connection to Discovery Address %s failed", conn->host); \
54 } while (0)
56 static int timedout;
58 static void
59 sigalarm_handler(int unused)
61 timedout = 1;
64 static void
65 set_non_blocking(int fd)
67 int res = fcntl(fd, F_GETFL);
69 if (res != -1) {
70 res = fcntl(fd, F_SETFL, res | O_NONBLOCK);
71 if (res)
72 log_warning("unable to set fd flags (%s)!",
73 strerror(errno));
74 } else
75 log_warning("unable to get fd flags (%s)!", strerror(errno));
79 #if 0
80 /* not used by anyone */
81 static int get_hwaddress_from_netdev(char *netdev, char *hwaddress)
83 struct ifaddrs *ifap, *ifa;
84 struct sockaddr_in *s4;
85 struct sockaddr_in6 *s6;
86 struct ifreq if_hwaddr;
87 int found = 0, sockfd;
88 unsigned char *hwaddr;
89 char buf[INET6_ADDRSTRLEN];
91 if (getifaddrs(&ifap)) {
92 log_error("Could not match hwaddress %s to netdev. "
93 "getifaddrs failed %d", hwaddress, errno);
94 return 0;
97 /* Open a basic socket. */
98 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
99 if (sockfd < 0) {
100 log_error("Could not open socket for ioctl.");
101 goto free_ifap;
104 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
105 if (!ifa->ifa_addr)
106 continue;
108 switch (ifa->ifa_addr->sa_family) {
109 case AF_INET:
110 s4 = (struct sockaddr_in *)(ifa->ifa_addr);
111 if (!inet_ntop(ifa->ifa_addr->sa_family,
112 (void *)&(s4->sin_addr), buf,
113 INET_ADDRSTRLEN))
114 continue;
115 log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
116 break;
117 case AF_INET6:
118 s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
119 if (!inet_ntop(ifa->ifa_addr->sa_family,
120 (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN))
121 continue;
122 log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
123 break;
124 default:
125 continue;
128 if (strcmp(ifa->ifa_name, netdev))
129 continue;
131 strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ);
132 if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
133 log_error("Could not match %s to netdevice.",
134 hwaddress);
135 continue;
138 /* check for ARPHRD_ETHER (ethernet) */
139 if (if_hwaddr.ifr_hwaddr.sa_family != 1)
140 continue;
141 hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
143 memset(hwaddress, 0, ISCSI_MAX_IFACE_LEN);
144 /* TODO should look and covert so we do not need tmp buf */
145 sprintf(hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
146 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
147 hwaddr[4], hwaddr[5]);
148 log_debug(4, "Found hardware address %s", hwaddress);
149 found = 1;
150 break;
153 close(sockfd);
154 free_ifap:
155 freeifaddrs(ifap);
156 return found;
158 #endif
161 #if 0
163 This is not supported for now, because it is not exactly what we want.
164 It also turns out that targets will send packets to other interfaces
165 causing all types of weird things to happen.
168 static int bind_src_by_address(int sockfd, char *address)
170 int rc = 0;
171 char port[NI_MAXSERV];
172 struct sockaddr_storage saddr;
174 memset(&saddr, 0, sizeof(struct sockaddr_storage));
175 if (resolve_address(address, port, &saddr)) {
176 log_error("Could not bind %s to conn.", address);
177 return -1;
180 switch (saddr.ss_family) {
181 case AF_INET:
182 rc = bind(sockfd, (struct sockaddr *)&saddr,
183 sizeof(struct sockaddr_in));
184 break;
185 case AF_INET6:
186 rc = bind(sockfd, (struct sockaddr *)&saddr,
187 sizeof(struct sockaddr_in6));
188 break;
189 default:
190 rc = -1;
192 if (rc)
193 log_error("Could not bind %s to %d.", address, sockfd);
194 else
195 log_debug(4, "Bound %s to socket fd %d", address, sockfd);
196 return rc;
198 #endif
200 static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface)
202 struct iscsi_session *session = conn->session;
204 memset(session->netdev, 0, IFNAMSIZ);
205 if (iface_is_bound_by_hwaddr(iface) &&
206 net_get_netdev_from_hwaddress(iface->hwaddress, session->netdev)) {
207 log_error("Cannot match %s to net/scsi interface.",
208 iface->hwaddress);
209 return -1;
210 } else if (iface_is_bound_by_netdev(iface))
211 strcpy(session->netdev, iface->netdev);
212 else if (iface_is_bound_by_ipaddr(iface)) {
214 * we never supported this but now with offload having to
215 * set the ip address in the iface, useris may forget to
216 * set the offload's transport type and we end up here by
217 * accident.
219 log_error("Cannot bind %s to net/scsi interface. This is not "
220 "supported with software iSCSI (iscsi_tcp).",
221 iface->ipaddress);
222 return -1;
225 if (strlen(session->netdev)) {
226 struct ifreq ifr;
228 log_debug(4, "Binding session %d to %s", session->id,
229 session->netdev);
230 memset(&ifr, 0, sizeof(ifr));
231 strlcpy(ifr.ifr_name, session->netdev, IFNAMSIZ);
233 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
234 session->netdev,
235 strlen(session->netdev) + 1) < 0) {
236 log_error("Could not bind connection %d to %s\n",
237 conn->id, session->netdev);
238 return -1;
242 return 0;
246 iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking)
248 int rc, onearg;
249 struct sockaddr_storage *ss = &conn->saddr;
250 char serv[NI_MAXSERV];
252 /* create a socket */
253 conn->socket_fd = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
255 /* the trasport ep handle is used to bind with */
256 conn->transport_ep_handle = conn->socket_fd;
258 if (conn->socket_fd < 0) {
259 log_error("cannot create TCP socket");
260 return -1;
263 if (conn->session) {
264 if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
265 return -1;
268 onearg = 1;
269 rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
270 sizeof (onearg));
271 if (rc < 0) {
272 log_error("cannot set TCP_NODELAY option on socket");
273 close(conn->socket_fd);
274 conn->socket_fd = -1;
275 return rc;
278 /* optionally set the window sizes */
279 if (conn->tcp_window_size) {
280 int window_size = conn->tcp_window_size;
281 socklen_t arglen = sizeof (window_size);
283 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
284 (char *) &window_size, sizeof (window_size)) < 0) {
285 log_warning("failed to set TCP recv window size "
286 "to %u", window_size);
287 } else {
288 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
289 (char *) &window_size, &arglen) >= 0) {
290 log_debug(4, "set TCP recv window size to %u, "
291 "actually got %u",
292 conn->tcp_window_size, window_size);
296 window_size = conn->tcp_window_size;
297 arglen = sizeof (window_size);
299 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
300 (char *) &window_size, sizeof (window_size)) < 0) {
301 log_warning("failed to set TCP send window size "
302 "to %u", window_size);
303 } else {
304 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
305 (char *) &window_size, &arglen) >= 0) {
306 log_debug(4, "set TCP send window size to %u, "
307 "actually got %u",
308 conn->tcp_window_size, window_size);
314 * Build a TCP connection to the target
316 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
317 conn->host, sizeof(conn->host), serv, sizeof(serv),
318 NI_NUMERICHOST|NI_NUMERICSERV);
320 log_debug(1, "connecting to %s:%s", conn->host, serv);
321 if (non_blocking)
322 set_non_blocking(conn->socket_fd);
323 rc = connect(conn->socket_fd, (struct sockaddr *) ss, sizeof (*ss));
324 return rc;
328 iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
330 int rc;
331 struct pollfd pdesc;
332 char serv[NI_MAXSERV], lserv[NI_MAXSERV];
333 struct sockaddr_storage ss;
334 socklen_t len = sizeof(ss);
336 pdesc.fd = conn->socket_fd;
337 pdesc.events = POLLOUT;
338 rc = poll(&pdesc, 1, timeout_ms);
339 if (rc == 0)
340 return 0;
342 if (rc < 0) {
343 getnameinfo((struct sockaddr *) &conn->saddr,
344 sizeof(conn->saddr),
345 conn->host, sizeof(conn->host), serv, sizeof(serv),
346 NI_NUMERICHOST|NI_NUMERICSERV);
348 log_error("cannot make connection to %s:%s (%s)",
349 conn->host, serv, strerror(errno));
350 return rc;
353 len = sizeof(int);
354 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
355 (char *) &rc, &len) < 0) {
356 log_error("getsockopt for connect poll failed\n");
357 return -1;
359 if (rc) {
360 getnameinfo((struct sockaddr *) &conn->saddr,
361 sizeof(conn->saddr),
362 conn->host, sizeof(conn->host), serv, sizeof(serv),
363 NI_NUMERICHOST|NI_NUMERICSERV);
365 log_error("connect to %s:%s failed (%s)\n",
366 conn->host, serv, strerror(rc));
367 return -rc;
370 len = sizeof(ss);
371 if (log_level > 0 &&
372 getsockname(conn->socket_fd, (struct sockaddr *) &ss, &len) >= 0) {
373 getnameinfo((struct sockaddr *) &conn->saddr,
374 sizeof(conn->saddr), conn->host,
375 sizeof(conn->host), serv, sizeof(serv),
376 NI_NUMERICHOST|NI_NUMERICSERV);
378 getnameinfo((struct sockaddr *) &ss, sizeof(ss),
379 NULL, 0, lserv, sizeof(lserv), NI_NUMERICSERV);
381 log_debug(1, "connected local port %s to %s:%s",
382 lserv, conn->host, serv);
384 return 1;
387 void
388 iscsi_io_tcp_disconnect(iscsi_conn_t *conn)
390 if (conn->socket_fd >= 0) {
391 log_debug(1, "disconnecting conn %p, fd %d", conn,
392 conn->socket_fd);
393 close(conn->socket_fd);
394 conn->socket_fd = -1;
399 iscsi_io_connect(iscsi_conn_t *conn)
401 int rc, ret;
402 struct sigaction action;
403 struct sigaction old;
404 char serv[NI_MAXSERV];
406 /* set a timeout, since the socket calls may take a long time to
407 * timeout on their own
409 memset(&action, 0, sizeof (struct sigaction));
410 memset(&old, 0, sizeof (struct sigaction));
411 action.sa_sigaction = NULL;
412 action.sa_flags = 0;
413 action.sa_handler = sigalarm_handler;
414 sigaction(SIGALRM, &action, &old);
415 timedout = 0;
416 alarm(conn->login_timeout);
418 /* perform blocking TCP connect operation when no async request
419 * associated. SendTargets Discovery know to work in such a mode.
421 rc = iscsi_io_tcp_connect(conn, 0);
422 if (timedout) {
423 log_debug(1, "socket %d connect timed out", conn->socket_fd);
424 ret = 0;
425 goto done;
426 } else if (rc < 0) {
427 getnameinfo((struct sockaddr *) &conn->saddr,
428 sizeof(conn->saddr),
429 conn->host, sizeof(conn->host), serv, sizeof(serv),
430 NI_NUMERICHOST|NI_NUMERICSERV);
431 log_error("cannot make connection to %s:%s (%d)",
432 conn->host, serv, errno);
433 close(conn->socket_fd);
434 ret = 0;
435 goto done;
436 } else if (log_level > 0) {
437 struct sockaddr_storage ss;
438 char lserv[NI_MAXSERV];
439 socklen_t salen = sizeof(ss);
441 if (getsockname(conn->socket_fd, (struct sockaddr *) &ss,
442 &salen) >= 0) {
443 getnameinfo((struct sockaddr *) &conn->saddr,
444 sizeof(conn->saddr),
445 conn->host, sizeof(conn->host), serv,
446 sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
448 getnameinfo((struct sockaddr *) &ss,
449 sizeof(ss),
450 NULL, 0, lserv, sizeof(lserv),
451 NI_NUMERICSERV);
453 log_debug(1, "connected local port %s to %s:%s",
454 lserv, conn->host, serv);
458 ret = 1;
460 done:
461 alarm(0);
462 sigaction(SIGALRM, &old, NULL);
463 return ret;
466 void
467 iscsi_io_disconnect(iscsi_conn_t *conn)
469 iscsi_io_tcp_disconnect(conn);
472 static void
473 iscsi_log_text(struct iscsi_hdr *pdu, char *data)
475 int dlength = ntoh24(pdu->dlength);
476 char *text = data;
477 char *end = text + dlength;
479 while (text && (text < end)) {
480 log_debug(4, "> %s", text);
481 text += strlen(text);
482 while ((text < end) && (*text == '\0'))
483 text++;
488 iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
489 int hdr_digest, char *data, int data_digest, int timeout)
491 int rc, ret = 0;
492 char *header = (char *) hdr;
493 char *end;
494 char pad[4];
495 struct iovec vec[3];
496 int pad_bytes;
497 int pdu_length = sizeof (*hdr) + hdr->hlength + ntoh24(hdr->dlength);
498 int remaining;
499 struct sigaction action;
500 struct sigaction old;
501 iscsi_session_t *session = conn->session;
503 /* set a timeout, since the socket calls may take a long time
504 * to timeout on their own
506 if (!ipc) {
507 memset(&action, 0, sizeof (struct sigaction));
508 memset(&old, 0, sizeof (struct sigaction));
509 action.sa_sigaction = NULL;
510 action.sa_flags = 0;
511 action.sa_handler = sigalarm_handler;
512 sigaction(SIGALRM, &action, &old);
513 timedout = 0;
514 alarm(timeout);
517 memset(&pad, 0, sizeof (pad));
518 memset(&vec, 0, sizeof (vec));
520 switch (hdr->opcode & ISCSI_OPCODE_MASK) {
521 case ISCSI_OP_LOGIN:{
522 struct iscsi_login *login_hdr = (struct iscsi_login *) hdr;
524 log_debug(4, "sending login PDU with current stage "
525 "%d, next stage %d, transit 0x%x, isid"
526 " 0x%02x%02x%02x%02x%02x%02x exp_statsn %u",
527 ISCSI_LOGIN_CURRENT_STAGE(login_hdr->flags),
528 ISCSI_LOGIN_NEXT_STAGE(login_hdr->flags),
529 login_hdr->flags & ISCSI_FLAG_LOGIN_TRANSIT,
530 login_hdr->isid[0], login_hdr->isid[1],
531 login_hdr->isid[2], login_hdr->isid[3],
532 login_hdr->isid[4], login_hdr->isid[5],
533 ntohl(login_hdr->exp_statsn));
535 iscsi_log_text(hdr, data);
536 break;
538 case ISCSI_OP_TEXT:{
539 struct iscsi_text *text_hdr = (struct iscsi_text *) hdr;
541 log_debug(4, "sending text pdu with CmdSN %x, exp_statsn %u",
542 ntohl(text_hdr->cmdsn), ntohl(text_hdr->cmdsn));
543 iscsi_log_text(hdr, data);
544 break;
546 case ISCSI_OP_NOOP_OUT:{
547 struct iscsi_nopout *nopout_hdr = (struct iscsi_nopout *) hdr;
549 log_debug(4, "sending Nop-out pdu with ttt %x, CmdSN %x:",
550 ntohl(nopout_hdr->ttt), ntohl(nopout_hdr->cmdsn));
551 iscsi_log_text(hdr, data);
552 break;
554 default:
555 log_debug(4, "sending pdu opcode 0x%x:", hdr->opcode);
556 break;
559 /* send the PDU header */
560 header = (char *) hdr;
561 end = header + sizeof (*hdr) + hdr->hlength;
563 /* send all the data and any padding */
564 if (pdu_length % ISCSI_PAD_LEN)
565 pad_bytes = ISCSI_PAD_LEN - (pdu_length % ISCSI_PAD_LEN);
566 else
567 pad_bytes = 0;
569 if (ipc)
570 ipc->send_pdu_begin(session->t->handle, session->id,
571 conn->id, end - header,
572 ntoh24(hdr->dlength) + pad_bytes);
574 while (header < end) {
575 vec[0].iov_base = header;
576 vec[0].iov_len = end - header;
578 if (!ipc)
579 rc = writev(session->ctrl_fd, vec, 1);
580 else
581 rc = ipc->writev(0, vec, 1);
582 if (timedout) {
583 log_error("socket %d write timed out",
584 conn->socket_fd);
585 ret = 0;
586 goto done;
587 } else if ((rc <= 0) && (errno != EAGAIN)) {
588 LOG_CONN_FAIL(conn);
589 ret = 0;
590 goto done;
591 } else if (rc > 0) {
592 log_debug(4, "wrote %d bytes of PDU header", rc);
593 header += rc;
597 end = data + ntoh24(hdr->dlength);
598 remaining = ntoh24(hdr->dlength) + pad_bytes;
600 while (remaining > 0) {
601 vec[0].iov_base = data;
602 vec[0].iov_len = end - data;
603 vec[1].iov_base = (void *) &pad;
604 vec[1].iov_len = pad_bytes;
606 if (!ipc)
607 rc = writev(session->ctrl_fd, vec, 2);
608 else
609 rc = ipc->writev(0, vec, 2);
610 if (timedout) {
611 log_error("socket %d write timed out",
612 conn->socket_fd);
613 ret = 0;
614 goto done;
615 } else if ((rc <= 0) && (errno != EAGAIN)) {
616 LOG_CONN_FAIL(conn);
617 ret = 0;
618 goto done;
619 } else if (rc > 0) {
620 log_debug(4, "wrote %d bytes of PDU data", rc);
621 remaining -= rc;
622 if (data < end) {
623 data += rc;
624 if (data > end)
625 data = end;
630 if (ipc) {
631 if (ipc->send_pdu_end(session->t->handle, session->id,
632 conn->id, &rc)) {
633 ret = 0;
634 goto done;
638 ret = 1;
640 done:
641 if (!ipc) {
642 alarm(0);
643 sigaction(SIGALRM, &old, NULL);
644 timedout = 0;
646 return ret;
650 iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
651 int hdr_digest, char *data, int max_data_length, int data_digest,
652 int timeout)
654 uint32_t h_bytes = 0;
655 uint32_t ahs_bytes = 0;
656 uint32_t d_bytes = 0;
657 uint32_t ahslength = 0;
658 uint32_t dlength = 0;
659 uint32_t pad = 0;
660 int rlen = 0;
661 int failed = 0;
662 char *header = (char *) hdr;
663 char *end = data + max_data_length;
664 struct sigaction action;
665 struct sigaction old;
666 iscsi_session_t *session = conn->session;
668 memset(data, 0, max_data_length);
670 /* set a timeout, since the socket calls may take a long
671 * time to timeout on their own
673 if (!ipc) {
674 memset(&action, 0, sizeof (struct sigaction));
675 memset(&old, 0, sizeof (struct sigaction));
676 action.sa_sigaction = NULL;
677 action.sa_flags = 0;
678 action.sa_handler = sigalarm_handler;
679 sigaction(SIGALRM, &action, &old);
680 timedout = 0;
681 alarm(timeout);
682 } else {
683 if (ipc->recv_pdu_begin(conn)) {
684 failed = 1;
685 goto done;
689 /* read a response header */
690 do {
691 if (!ipc)
692 rlen = read(session->ctrl_fd, header,
693 sizeof (*hdr) - h_bytes);
694 else
695 rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
696 if (timedout) {
697 log_error("socket %d header read timed out",
698 conn->socket_fd);
699 failed = 1;
700 goto done;
701 } else if (rlen == 0) {
702 LOG_CONN_CLOSED(conn);
703 failed = 1;
704 goto done;
705 } else if ((rlen < 0) && (errno != EAGAIN)) {
706 LOG_CONN_FAIL(conn);
707 failed = 1;
708 goto done;
709 } else if (rlen > 0) {
710 log_debug(4, "read %d bytes of PDU header", rlen);
711 header += rlen;
712 h_bytes += rlen;
714 } while (h_bytes < sizeof (*hdr));
716 log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
717 "data %p, max %u", h_bytes, hdr->opcode,
718 ntoh24(hdr->dlength), data, max_data_length);
720 /* check for additional headers */
721 ahslength = hdr->hlength; /* already includes padding */
722 if (ahslength) {
723 log_warning("additional header segment length %u not supported",
724 ahslength);
725 failed = 1;
726 goto done;
729 /* read exactly what we expect, plus padding */
730 dlength = hdr->dlength[0] << 16;
731 dlength |= hdr->dlength[1] << 8;
732 dlength |= hdr->dlength[2];
734 /* if we only expected to receive a header, exit */
735 if (dlength == 0)
736 goto done;
738 if (data + dlength > end) {
739 log_warning("buffer size %u too small for data length %u",
740 max_data_length, dlength);
741 failed = 1;
742 goto done;
745 /* read the rest into our buffer */
746 d_bytes = 0;
747 while (d_bytes < dlength) {
748 if (!ipc)
749 rlen = read(session->ctrl_fd, data + d_bytes,
750 dlength - d_bytes);
751 else
752 rlen = ipc->read(data + d_bytes, dlength - d_bytes);
753 if (timedout) {
754 log_error("socket %d data read timed out",
755 conn->socket_fd);
756 failed = 1;
757 goto done;
758 } else if (rlen == 0) {
759 LOG_CONN_CLOSED(conn);
760 failed = 1;
761 goto done;
762 } else if ((rlen < 0 && errno != EAGAIN)) {
763 LOG_CONN_FAIL(conn);
764 failed = 1;
765 goto done;
766 } else if (rlen > 0) {
767 log_debug(4, "read %d bytes of PDU data", rlen);
768 d_bytes += rlen;
772 /* handle PDU data padding.
773 * data is padded in case of kernel_io */
774 pad = dlength % ISCSI_PAD_LEN;
775 if (pad && !ipc) {
776 int pad_bytes = pad = ISCSI_PAD_LEN - pad;
777 char bytes[ISCSI_PAD_LEN];
779 while (pad_bytes > 0) {
780 rlen = read(conn->socket_fd, &bytes, pad_bytes);
781 if (timedout) {
782 log_error("socket %d pad read timed out",
783 conn->socket_fd);
784 failed = 1;
785 goto done;
786 } else if (rlen == 0) {
787 LOG_CONN_CLOSED(conn);
788 failed = 1;
789 goto done;
790 } else if ((rlen < 0 && errno != EAGAIN)) {
791 LOG_CONN_FAIL(conn);
792 failed = 1;
793 goto done;
794 } else if (rlen > 0) {
795 log_debug(4, "read %d pad bytes", rlen);
796 pad_bytes -= rlen;
801 switch (hdr->opcode) {
802 case ISCSI_OP_TEXT_RSP:
803 log_debug(4, "finished reading text PDU, %u hdr, %u "
804 "ah, %u data, %u pad",
805 h_bytes, ahs_bytes, d_bytes, pad);
806 iscsi_log_text(hdr, data);
807 break;
808 case ISCSI_OP_LOGIN_RSP:{
809 struct iscsi_login_rsp *login_rsp =
810 (struct iscsi_login_rsp *) hdr;
812 log_debug(4, "finished reading login PDU, %u hdr, "
813 "%u ah, %u data, %u pad",
814 h_bytes, ahs_bytes, d_bytes, pad);
815 log_debug(4, "login current stage %d, next stage "
816 "%d, transit 0x%x",
817 ISCSI_LOGIN_CURRENT_STAGE(login_rsp->flags),
818 ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags),
819 login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT);
820 iscsi_log_text(hdr, data);
821 break;
823 case ISCSI_OP_ASYNC_EVENT:
824 /* FIXME: log the event info */
825 break;
826 default:
827 break;
830 done:
831 if (!ipc) {
832 alarm(0);
833 sigaction(SIGALRM, &old, NULL);
834 } else {
835 /* finalyze receive transaction */
836 if (ipc->recv_pdu_end(conn)) {
837 failed = 1;
841 if (timedout || failed) {
842 timedout = 0;
843 return 0;
846 return h_bytes + ahs_bytes + d_bytes;