2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 #include <netinet/in.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
33 #include "iscsi-private.h"
34 #include "dlinklist.h"
36 #include <sys/filio.h>
39 static void set_nonblocking(int fd)
42 v = fcntl(fd, F_GETFL, 0);
43 fcntl(fd, F_SETFL, v | O_NONBLOCK);
46 int iscsi_connect_async(struct iscsi_context *iscsi, const char *target, iscsi_command_cb cb, void *private_data)
53 struct sockaddr_storage ss;
54 struct sockaddr_in sin;
59 printf("Trying to connect NULL context\n");
62 if (iscsi->fd != -1) {
63 printf("Trying to connect but already connected\n");
67 addr = strdup(target);
69 printf("failed to strdup target address\n");
73 /* check if we have a target portal group tag */
74 if ((str = rindex(addr, ',')) != NULL) {
78 /* XXX need handling for {ipv6 addresses} */
79 /* for now, assume all is ipv4 */
80 if ((str = rindex(addr, ':')) != NULL) {
85 s.sin.sin_family = AF_INET;
86 s.sin.sin_port = htons(port);
87 if (inet_pton(AF_INET, addr, &s.sin.sin_addr) != 1) {
88 printf("failed to convert to ip address\n");
94 switch (s.ss.ss_family) {
96 iscsi->fd = socket(AF_INET, SOCK_STREAM, 0);
97 socksize = sizeof(struct sockaddr_in);
100 printf("Unknown family :%d\n", s.ss.ss_family);
105 if (iscsi->fd == -1) {
106 printf("Failed to open socket\n");
111 iscsi->connect_cb = cb;
112 iscsi->connect_data = private_data;
114 set_nonblocking(iscsi->fd);
116 if (connect(iscsi->fd, &s.sa, socksize) != 0 && errno != EINPROGRESS) {
117 printf("Connect failed errno : %s (%d)\n", strerror(errno), errno);
124 int iscsi_disconnect(struct iscsi_context *iscsi)
127 printf("Trying to disconnect NULL context\n");
130 if (iscsi->is_loggedin != 0) {
131 printf("Trying to disconnect while logged in\n");
134 if (iscsi->fd == -1) {
135 printf("Trying to disconnect but not connected\n");
142 iscsi->is_connected = 0;
147 int iscsi_get_fd(struct iscsi_context *iscsi)
150 printf("Trying to get fd for NULL context\n");
157 int iscsi_which_events(struct iscsi_context *iscsi)
161 if (iscsi->is_connected == 0) {
165 if (iscsi->outqueue) {
171 static int iscsi_read_from_socket(struct iscsi_context *iscsi)
178 if (ioctl(iscsi->fd, FIONREAD, &available) != 0) {
179 printf("ioctl FIONREAD returned error : %d\n", errno);
182 if (available == 0) {
183 printf("no data readable in socket, socket is closed\n");
186 size = iscsi->insize - iscsi->inpos + available;
189 printf("failed to allocate %d bytes for input buffer\n", size);
192 if (iscsi->insize > iscsi->inpos) {
193 memcpy(buf, iscsi->inbuf + iscsi->inpos, iscsi->insize - iscsi->inpos);
194 iscsi->insize -= iscsi->inpos;
198 count = read(iscsi->fd, buf + iscsi->insize, available);
200 if (errno == EINTR) {
205 printf("read from socket failed, errno:%d\n", errno);
211 if (iscsi->inbuf != NULL) {
215 iscsi->insize += count;
218 if (iscsi->insize - iscsi->inpos < 48) {
221 count = iscsi_get_pdu_size(iscsi->inbuf + iscsi->inpos);
222 if (iscsi->insize + iscsi->inpos < count) {
225 if (iscsi_process_pdu(iscsi, iscsi->inbuf + iscsi->inpos, count) != 0) {
226 printf("failed to process pdu\n");
229 iscsi->inpos += count;
230 if (iscsi->inpos == iscsi->insize) {
236 if (iscsi->inpos > iscsi->insize) {
237 printf("inpos > insize. bug!\n");
245 static int iscsi_write_to_socket(struct iscsi_context *iscsi)
250 printf("trying to write to socket for NULL context\n");
253 if (iscsi->fd == -1) {
254 printf("trying to write but not connected\n");
258 while (iscsi->outqueue != NULL) {
261 total = iscsi->outqueue->outdata.size;
262 total = (total +3) & 0xfffffffc;
264 count = write(iscsi->fd, iscsi->outqueue->outdata.data + iscsi->outqueue->written, total - iscsi->outqueue->written);
266 if (errno == EAGAIN || errno == EWOULDBLOCK) {
267 printf("socket would block, return from write to socket\n");
270 printf("Error when writing to socket :%d\n", errno);
274 iscsi->outqueue->written += count;
275 if (iscsi->outqueue->written == total) {
276 struct iscsi_pdu *pdu = iscsi->outqueue;
278 DLIST_REMOVE(iscsi->outqueue, pdu);
279 DLIST_ADD_END(iscsi->waitpdu, pdu, NULL);
285 int iscsi_service(struct iscsi_context *iscsi, int revents)
287 if (revents & POLLERR) {
288 printf("iscsi_service: POLLERR, socket error\n");
289 iscsi->connect_cb(iscsi, ISCSI_STATUS_ERROR, NULL, iscsi->connect_data);
292 if (revents & POLLHUP) {
293 printf("iscsi_service: POLLHUP, socket error\n");
294 iscsi->connect_cb(iscsi, ISCSI_STATUS_ERROR, NULL, iscsi->connect_data);
298 if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) {
299 iscsi->is_connected = 1;
300 iscsi->connect_cb(iscsi, ISCSI_STATUS_GOOD, NULL, iscsi->connect_data);
304 if (revents & POLLOUT && iscsi->outqueue != NULL) {
305 if (iscsi_write_to_socket(iscsi) != 0) {
306 printf("write to socket failed\n");
310 if (revents & POLLIN) {
311 if (iscsi_read_from_socket(iscsi) != 0) {
312 printf("read from socket failed\n");
320 int iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
323 printf("trying to queue to NULL context\n");
327 printf("trying to queue NULL pdu\n");
330 DLIST_ADD_END(iscsi->outqueue, pdu, NULL);