configurator: HAVE_SECTION_START_STOP
[ccan] / ccan / iscsi / discovery.c
1 /*
2    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3    
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.
8    
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.
13    
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/>.
16 */
17
18 #include "config.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <arpa/inet.h>
23 #include "iscsi.h"
24 #include "iscsi-private.h"
25
26 int iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data)
27 {
28         struct iscsi_pdu *pdu;
29         const char *str;
30
31         if (iscsi == NULL) {
32                 printf("trying to send text on NULL context\n");
33                 return -1;
34         }
35
36         if (iscsi->session_type != ISCSI_SESSION_DISCOVERY) {
37                 printf("Trying to do discovery on non-discovery session\n");
38                 return -2;
39         }
40
41         pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_TEXT_REQUEST, ISCSI_PDU_TEXT_RESPONSE);
42         if (pdu == NULL) {
43                 printf("Failed to allocate text pdu\n");
44                 return -3;
45         }
46
47         /* immediate */
48         iscsi_pdu_set_immediate(pdu);
49
50         /* flags */
51         iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_TEXT_FINAL);
52
53         /* target transfer tag */
54         iscsi_pdu_set_ttt(pdu, 0xffffffff);
55
56         /* sendtargets */
57         str = "SendTargets=All";
58         if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
59                 printf("pdu add data failed\n");
60                 iscsi_free_pdu(iscsi, pdu);
61                 return -4;
62         }
63
64         pdu->callback     = cb;
65         pdu->private_data = private_data;
66
67         if (iscsi_queue_pdu(iscsi, pdu) != 0) {
68                 printf("failed to queue iscsi text pdu\n");
69                 iscsi_free_pdu(iscsi, pdu);
70                 return -5;
71         }
72
73         return 0;
74 }
75
76 static void iscsi_free_discovery_addresses(struct iscsi_discovery_address *addresses)
77 {
78         while (addresses != NULL) {
79                 struct iscsi_discovery_address *next = addresses->next;
80
81                 if (addresses->target_name != NULL) {
82                         free(discard_const(addresses->target_name));
83                         addresses->target_name = NULL;
84                 }
85                 if (addresses->target_address != NULL) {
86                         free(discard_const(addresses->target_address));
87                         addresses->target_address = NULL;
88                 }
89                 addresses->next = NULL;
90                 free(addresses);
91                 addresses = next;
92         }
93 }
94
95 int iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, const unsigned char *hdr, int size)
96 {
97         struct iscsi_discovery_address *targets = NULL;
98
99         /* verify the response looks sane */
100         if (hdr[1] != ISCSI_PDU_TEXT_FINAL) {
101                 printf("unsupported flags in text reply %02x\n", hdr[1]);
102                 pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
103                 return -1;
104         }
105
106         /* skip past the header */
107         hdr  += ISCSI_HEADER_SIZE;
108         size -= ISCSI_HEADER_SIZE;
109
110         while (size > 0) {
111                 int len;
112
113                 len = strlen((char *)hdr);
114
115                 if (len == 0) {
116                         break;
117                 }
118
119                 if (len > size) {
120                         printf("len > size when parsing discovery data %d>%d\n", len, size);
121                         pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
122                         iscsi_free_discovery_addresses(targets);
123                         return -1;
124                 }
125
126                 /* parse the strings */
127                 if (!strncmp((char *)hdr, "TargetName=", 11)) {
128                         struct iscsi_discovery_address *target;
129
130                         target = malloc(sizeof(struct iscsi_discovery_address));
131                         if (target == NULL) {
132                                 printf("Failed to allocate data for new discovered target\n");
133                                 pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
134                                 iscsi_free_discovery_addresses(targets);
135                                 return -1;
136                         }
137                         bzero(target, sizeof(struct iscsi_discovery_address));
138                         target->target_name = strdup((char *)hdr+11);
139                         if (target->target_name == NULL) {
140                                 printf("Failed to allocate data for new discovered target name\n");
141                                 pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
142                                 free(target);
143                                 target = NULL;
144                                 iscsi_free_discovery_addresses(targets);
145                                 return -1;
146                         }
147                         target->next = targets;
148                         targets = target;
149                 } else if (!strncmp((char *)hdr, "TargetAddress=", 14)) {
150                         targets->target_address = strdup((char *)hdr+14);
151                         if (targets->target_address == NULL) {
152                                 printf("Failed to allocate data for new discovered target address\n");
153                                 pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
154                                 iscsi_free_discovery_addresses(targets);
155                                 return -1;
156                         }
157                 } else {
158                         printf("Don't know how to handle discovery string : %s\n", hdr);
159                         pdu->callback(iscsi, ISCSI_STATUS_ERROR, NULL, pdu->private_data);
160                         iscsi_free_discovery_addresses(targets);
161                         return -1;
162                 }
163
164                 hdr  += len + 1;
165                 size -= len + 1;
166         }
167
168         pdu->callback(iscsi, ISCSI_STATUS_GOOD, targets, pdu->private_data);
169         iscsi_free_discovery_addresses(targets);
170
171         return 0;
172 }