open-isns: Fix warnings reported by gcc-4.5.2
[open-iscsi.git] / usr / io.c
blob8d37d4320840e202ce6b159f0616e8ca5a8d366b
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 (conn->session) {
367 if (bind_conn_to_iface(conn, &conn->session->nrec.iface))
368 return -1;
371 onearg = 1;
372 rc = setsockopt(conn->socket_fd, IPPROTO_TCP, TCP_NODELAY, &onearg,
373 sizeof (onearg));
374 if (rc < 0) {
375 log_error("cannot set TCP_NODELAY option on socket");
376 close(conn->socket_fd);
377 conn->socket_fd = -1;
378 return rc;
381 /* optionally set the window sizes */
382 if (conn->tcp_window_size) {
383 int window_size = conn->tcp_window_size;
384 socklen_t arglen = sizeof (window_size);
386 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
387 (char *) &window_size, sizeof (window_size)) < 0) {
388 log_warning("failed to set TCP recv window size "
389 "to %u", window_size);
390 } else {
391 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_RCVBUF,
392 (char *) &window_size, &arglen) >= 0) {
393 log_debug(4, "set TCP recv window size to %u, "
394 "actually got %u",
395 conn->tcp_window_size, window_size);
399 window_size = conn->tcp_window_size;
400 arglen = sizeof (window_size);
402 if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
403 (char *) &window_size, sizeof (window_size)) < 0) {
404 log_warning("failed to set TCP send window size "
405 "to %u", window_size);
406 } else {
407 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_SNDBUF,
408 (char *) &window_size, &arglen) >= 0) {
409 log_debug(4, "set TCP send window size to %u, "
410 "actually got %u",
411 conn->tcp_window_size, window_size);
417 * Build a TCP connection to the target
419 getnameinfo((struct sockaddr *) ss, sizeof(*ss),
420 conn->host, sizeof(conn->host), serv, sizeof(serv),
421 NI_NUMERICHOST|NI_NUMERICSERV);
423 log_debug(1, "connecting to %s:%s", conn->host, serv);
424 if (non_blocking)
425 set_non_blocking(conn->socket_fd);
427 if (conn->session->netdev[0])
428 set_dcb_priority(conn, conn->session->netdev);
430 rc = connect(conn->socket_fd, (struct sockaddr *) ss, sizeof (*ss));
431 return rc;
435 iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
437 int rc;
438 struct pollfd pdesc;
439 char serv[NI_MAXSERV], lserv[NI_MAXSERV];
440 struct sockaddr_storage ss;
441 socklen_t len;
443 pdesc.fd = conn->socket_fd;
444 pdesc.events = POLLOUT;
445 rc = poll(&pdesc, 1, timeout_ms);
446 if (rc == 0)
447 return 0;
449 if (rc < 0) {
450 getnameinfo((struct sockaddr *) &conn->saddr,
451 sizeof(conn->saddr),
452 conn->host, sizeof(conn->host), serv, sizeof(serv),
453 NI_NUMERICHOST|NI_NUMERICSERV);
455 log_error("cannot make connection to %s:%s (%s)",
456 conn->host, serv, strerror(errno));
457 return rc;
460 len = sizeof(int);
461 if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
462 (char *) &rc, &len) < 0) {
463 log_error("getsockopt for connect poll failed\n");
464 return -1;
466 if (rc) {
467 getnameinfo((struct sockaddr *) &conn->saddr,
468 sizeof(conn->saddr),
469 conn->host, sizeof(conn->host), serv, sizeof(serv),
470 NI_NUMERICHOST|NI_NUMERICSERV);
472 log_error("connect to %s:%s failed (%s)\n",
473 conn->host, serv, strerror(rc));
474 return -rc;
477 len = sizeof(ss);
478 if (log_level > 0 || !conn->session->netdev[0])
479 rc = getsockname(conn->socket_fd, (struct sockaddr *)&ss, &len);
480 if (log_level > 0 && rc >= 0) {
481 getnameinfo((struct sockaddr *) &conn->saddr,
482 sizeof(conn->saddr), conn->host,
483 sizeof(conn->host), serv, sizeof(serv),
484 NI_NUMERICHOST|NI_NUMERICSERV);
486 getnameinfo((struct sockaddr *) &ss, sizeof(ss),
487 NULL, 0, lserv, sizeof(lserv), NI_NUMERICSERV);
489 log_debug(1, "connected local port %s to %s:%s",
490 lserv, conn->host, serv);
493 if (!conn->session->netdev[0] && rc >= 0) {
494 struct ifaddrs *ifa;
495 char *ifname;
497 rc = getifaddrs(&ifa);
498 if (rc < 0)
499 log_error("getifaddrs failed with %d\n", errno);
500 else {
501 ifname = find_ifname(ifa, (union sockaddr_u *)&ss);
502 if (ifname)
503 set_dcb_priority(conn, ifname);
504 freeifaddrs(ifa);
508 return 1;
511 void
512 iscsi_io_tcp_disconnect(iscsi_conn_t *conn)
514 if (conn->socket_fd >= 0) {
515 log_debug(1, "disconnecting conn %p, fd %d", conn,
516 conn->socket_fd);
517 close(conn->socket_fd);
518 conn->socket_fd = -1;
523 iscsi_io_connect(iscsi_conn_t *conn)
525 int rc, ret;
526 struct sigaction action;
527 struct sigaction old;
529 /* set a timeout, since the socket calls may take a long time to
530 * timeout on their own
532 memset(&action, 0, sizeof (struct sigaction));
533 memset(&old, 0, sizeof (struct sigaction));
534 action.sa_sigaction = NULL;
535 action.sa_flags = 0;
536 action.sa_handler = sigalarm_handler;
537 sigaction(SIGALRM, &action, &old);
538 timedout = 0;
539 alarm(conn->login_timeout);
541 /* perform blocking TCP connect operation when no async request
542 * associated. SendTargets Discovery know to work in such a mode.
544 rc = iscsi_io_tcp_connect(conn, 0);
545 if (timedout) {
546 log_error("connect to %s timed out", conn->host);
548 log_debug(1, "socket %d connect timed out", conn->socket_fd);
549 ret = 0;
550 goto done;
551 } else if (rc < 0) {
552 log_error("cannot make connection to %s: %s",
553 conn->host, strerror(errno));
554 close(conn->socket_fd);
555 ret = 0;
556 goto done;
557 } else if (log_level > 0) {
558 struct sockaddr_storage ss;
559 char lserv[NI_MAXSERV];
560 char serv[NI_MAXSERV];
561 socklen_t salen = sizeof(ss);
563 if (getsockname(conn->socket_fd, (struct sockaddr *) &ss,
564 &salen) >= 0) {
565 getnameinfo((struct sockaddr *) &conn->saddr,
566 sizeof(conn->saddr),
567 conn->host, sizeof(conn->host), serv,
568 sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV);
570 getnameinfo((struct sockaddr *) &ss,
571 sizeof(ss),
572 NULL, 0, lserv, sizeof(lserv),
573 NI_NUMERICSERV);
575 log_debug(1, "connected local port %s to %s:%s",
576 lserv, conn->host, serv);
580 ret = 1;
582 done:
583 alarm(0);
584 sigaction(SIGALRM, &old, NULL);
585 return ret;
588 void
589 iscsi_io_disconnect(iscsi_conn_t *conn)
591 iscsi_io_tcp_disconnect(conn);
594 static void
595 iscsi_log_text(struct iscsi_hdr *pdu, char *data)
597 int dlength = ntoh24(pdu->dlength);
598 char *text = data;
599 char *end = text + dlength;
601 while (text && (text < end)) {
602 log_debug(4, "> %s", text);
603 text += strlen(text);
604 while ((text < end) && (*text == '\0'))
605 text++;
610 iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
611 int hdr_digest, char *data, int data_digest, int timeout)
613 int rc, ret = 0;
614 char *header = (char *) hdr;
615 char *end;
616 char pad[4];
617 struct iovec vec[3];
618 int pad_bytes;
619 int pdu_length = sizeof (*hdr) + hdr->hlength + ntoh24(hdr->dlength);
620 int remaining;
621 struct sigaction action;
622 struct sigaction old;
623 iscsi_session_t *session = conn->session;
625 /* set a timeout, since the socket calls may take a long time
626 * to timeout on their own
628 if (!session->use_ipc) {
629 memset(&action, 0, sizeof (struct sigaction));
630 memset(&old, 0, sizeof (struct sigaction));
631 action.sa_sigaction = NULL;
632 action.sa_flags = 0;
633 action.sa_handler = sigalarm_handler;
634 sigaction(SIGALRM, &action, &old);
635 timedout = 0;
636 alarm(timeout);
639 memset(&pad, 0, sizeof (pad));
640 memset(&vec, 0, sizeof (vec));
642 switch (hdr->opcode & ISCSI_OPCODE_MASK) {
643 case ISCSI_OP_LOGIN:{
644 struct iscsi_login *login_hdr = (struct iscsi_login *) hdr;
646 log_debug(4, "sending login PDU with current stage "
647 "%d, next stage %d, transit 0x%x, isid"
648 " 0x%02x%02x%02x%02x%02x%02x exp_statsn %u",
649 ISCSI_LOGIN_CURRENT_STAGE(login_hdr->flags),
650 ISCSI_LOGIN_NEXT_STAGE(login_hdr->flags),
651 login_hdr->flags & ISCSI_FLAG_LOGIN_TRANSIT,
652 login_hdr->isid[0], login_hdr->isid[1],
653 login_hdr->isid[2], login_hdr->isid[3],
654 login_hdr->isid[4], login_hdr->isid[5],
655 ntohl(login_hdr->exp_statsn));
657 iscsi_log_text(hdr, data);
658 break;
660 case ISCSI_OP_TEXT:{
661 struct iscsi_text *text_hdr = (struct iscsi_text *) hdr;
663 log_debug(4, "sending text pdu with CmdSN %x, exp_statsn %u",
664 ntohl(text_hdr->cmdsn), ntohl(text_hdr->cmdsn));
665 iscsi_log_text(hdr, data);
666 break;
668 case ISCSI_OP_NOOP_OUT:{
669 struct iscsi_nopout *nopout_hdr = (struct iscsi_nopout *) hdr;
671 log_debug(4, "sending Nop-out pdu with ttt %x, CmdSN %x:",
672 ntohl(nopout_hdr->ttt), ntohl(nopout_hdr->cmdsn));
673 iscsi_log_text(hdr, data);
674 break;
676 default:
677 log_debug(4, "sending pdu opcode 0x%x:", hdr->opcode);
678 break;
681 /* send the PDU header */
682 header = (char *) hdr;
683 end = header + sizeof (*hdr) + hdr->hlength;
685 /* send all the data and any padding */
686 if (pdu_length % ISCSI_PAD_LEN)
687 pad_bytes = ISCSI_PAD_LEN - (pdu_length % ISCSI_PAD_LEN);
688 else
689 pad_bytes = 0;
691 if (session->use_ipc)
692 ipc->send_pdu_begin(session->t->handle, session->id,
693 conn->id, end - header,
694 ntoh24(hdr->dlength) + pad_bytes);
696 while (header < end) {
697 vec[0].iov_base = header;
698 vec[0].iov_len = end - header;
700 if (!session->use_ipc)
701 rc = writev(conn->socket_fd, vec, 1);
702 else
703 rc = ipc->writev(0, vec, 1);
704 if (timedout) {
705 log_error("socket %d write timed out",
706 conn->socket_fd);
707 ret = 0;
708 goto done;
709 } else if ((rc <= 0) && (errno != EAGAIN)) {
710 LOG_CONN_FAIL(conn);
711 ret = 0;
712 goto done;
713 } else if (rc > 0) {
714 log_debug(4, "wrote %d bytes of PDU header", rc);
715 header += rc;
719 end = data + ntoh24(hdr->dlength);
720 remaining = ntoh24(hdr->dlength) + pad_bytes;
722 while (remaining > 0) {
723 vec[0].iov_base = data;
724 vec[0].iov_len = end - data;
725 vec[1].iov_base = (void *) &pad;
726 vec[1].iov_len = pad_bytes;
728 if (!session->use_ipc)
729 rc = writev(conn->socket_fd, vec, 2);
730 else
731 rc = ipc->writev(0, vec, 2);
732 if (timedout) {
733 log_error("socket %d write timed out",
734 conn->socket_fd);
735 ret = 0;
736 goto done;
737 } else if ((rc <= 0) && (errno != EAGAIN)) {
738 LOG_CONN_FAIL(conn);
739 ret = 0;
740 goto done;
741 } else if (rc > 0) {
742 log_debug(4, "wrote %d bytes of PDU data", rc);
743 remaining -= rc;
744 if (data < end) {
745 data += rc;
746 if (data > end)
747 data = end;
752 if (session->use_ipc) {
753 if (ipc->send_pdu_end(session->t->handle, session->id,
754 conn->id, &rc)) {
755 ret = 0;
756 goto done;
760 ret = 1;
762 done:
763 if (!session->use_ipc) {
764 alarm(0);
765 sigaction(SIGALRM, &old, NULL);
766 timedout = 0;
768 return ret;
772 iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
773 int hdr_digest, char *data, int max_data_length, int data_digest,
774 int timeout)
776 uint32_t h_bytes = 0;
777 uint32_t ahs_bytes = 0;
778 uint32_t d_bytes = 0;
779 uint32_t ahslength = 0;
780 uint32_t dlength = 0;
781 uint32_t pad = 0;
782 int rlen = 0;
783 int failed = 0;
784 char *header = (char *) hdr;
785 char *end = data + max_data_length;
786 struct sigaction action;
787 struct sigaction old;
788 iscsi_session_t *session = conn->session;
790 memset(data, 0, max_data_length);
792 /* set a timeout, since the socket calls may take a long
793 * time to timeout on their own
795 if (!session->use_ipc) {
796 memset(&action, 0, sizeof (struct sigaction));
797 memset(&old, 0, sizeof (struct sigaction));
798 action.sa_sigaction = NULL;
799 action.sa_flags = 0;
800 action.sa_handler = sigalarm_handler;
801 sigaction(SIGALRM, &action, &old);
802 timedout = 0;
803 alarm(timeout);
804 } else {
805 failed = ipc->recv_pdu_begin(conn);
806 if (failed == -EAGAIN)
807 return -EAGAIN;
808 else if (failed < 0) {
809 failed = 1;
810 goto done;
814 /* read a response header */
815 do {
816 if (!session->use_ipc)
817 rlen = read(conn->socket_fd, header,
818 sizeof (*hdr) - h_bytes);
819 else
820 rlen = ipc->read(header, sizeof (*hdr) - h_bytes);
821 if (timedout) {
822 log_error("socket %d header read timed out",
823 conn->socket_fd);
824 failed = 1;
825 goto done;
826 } else if (rlen == 0) {
827 LOG_CONN_CLOSED(conn);
828 failed = 1;
829 goto done;
830 } else if ((rlen < 0) && (errno != EAGAIN)) {
831 LOG_CONN_FAIL(conn);
832 failed = 1;
833 goto done;
834 } else if (rlen > 0) {
835 log_debug(4, "read %d bytes of PDU header", rlen);
836 header += rlen;
837 h_bytes += rlen;
839 } while (h_bytes < sizeof (*hdr));
841 log_debug(4, "read %d PDU header bytes, opcode 0x%x, dlength %u, "
842 "data %p, max %u", h_bytes, hdr->opcode & ISCSI_OPCODE_MASK,
843 ntoh24(hdr->dlength), data, max_data_length);
845 /* check for additional headers */
846 ahslength = hdr->hlength; /* already includes padding */
847 if (ahslength) {
848 log_warning("additional header segment length %u not supported",
849 ahslength);
850 failed = 1;
851 goto done;
854 /* read exactly what we expect, plus padding */
855 dlength = hdr->dlength[0] << 16;
856 dlength |= hdr->dlength[1] << 8;
857 dlength |= hdr->dlength[2];
859 /* if we only expected to receive a header, exit */
860 if (dlength == 0)
861 goto done;
863 if (data + dlength > end) {
864 log_warning("buffer size %u too small for data length %u",
865 max_data_length, dlength);
866 failed = 1;
867 goto done;
870 /* read the rest into our buffer */
871 d_bytes = 0;
872 while (d_bytes < dlength) {
873 if (!session->use_ipc)
874 rlen = read(conn->socket_fd, data + d_bytes,
875 dlength - d_bytes);
876 else
877 rlen = ipc->read(data + d_bytes, dlength - d_bytes);
878 if (timedout) {
879 log_error("socket %d data read timed out",
880 conn->socket_fd);
881 failed = 1;
882 goto done;
883 } else if (rlen == 0) {
884 LOG_CONN_CLOSED(conn);
885 failed = 1;
886 goto done;
887 } else if ((rlen < 0 && errno != EAGAIN)) {
888 LOG_CONN_FAIL(conn);
889 failed = 1;
890 goto done;
891 } else if (rlen > 0) {
892 log_debug(4, "read %d bytes of PDU data", rlen);
893 d_bytes += rlen;
897 /* handle PDU data padding.
898 * data is padded in case of kernel_io */
899 pad = dlength % ISCSI_PAD_LEN;
900 if (pad && !session->use_ipc) {
901 int pad_bytes = pad = ISCSI_PAD_LEN - pad;
902 char bytes[ISCSI_PAD_LEN];
904 while (pad_bytes > 0) {
905 rlen = read(conn->socket_fd, &bytes, pad_bytes);
906 if (timedout) {
907 log_error("socket %d pad read timed out",
908 conn->socket_fd);
909 failed = 1;
910 goto done;
911 } else if (rlen == 0) {
912 LOG_CONN_CLOSED(conn);
913 failed = 1;
914 goto done;
915 } else if ((rlen < 0 && errno != EAGAIN)) {
916 LOG_CONN_FAIL(conn);
917 failed = 1;
918 goto done;
919 } else if (rlen > 0) {
920 log_debug(4, "read %d pad bytes", rlen);
921 pad_bytes -= rlen;
926 switch (hdr->opcode) {
927 case ISCSI_OP_TEXT_RSP:
928 log_debug(4, "finished reading text PDU, %u hdr, %u "
929 "ah, %u data, %u pad",
930 h_bytes, ahs_bytes, d_bytes, pad);
931 iscsi_log_text(hdr, data);
932 break;
933 case ISCSI_OP_LOGIN_RSP:{
934 struct iscsi_login_rsp *login_rsp =
935 (struct iscsi_login_rsp *) hdr;
937 log_debug(4, "finished reading login PDU, %u hdr, "
938 "%u ah, %u data, %u pad",
939 h_bytes, ahs_bytes, d_bytes, pad);
940 log_debug(4, "login current stage %d, next stage "
941 "%d, transit 0x%x",
942 ISCSI_LOGIN_CURRENT_STAGE(login_rsp->flags),
943 ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags),
944 login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT);
945 iscsi_log_text(hdr, data);
946 break;
948 case ISCSI_OP_ASYNC_EVENT:
949 /* FIXME: log the event info */
950 break;
951 default:
952 break;
955 done:
956 if (!session->use_ipc) {
957 alarm(0);
958 sigaction(SIGALRM, &old, NULL);
959 } else {
960 /* finalyze receive transaction */
961 if (ipc->recv_pdu_end(conn)) {
962 failed = 1;
966 if (timedout || failed) {
967 timedout = 0;
968 return -EIO;
971 return h_bytes + ahs_bytes + d_bytes;