2 * @file xml_interface.c
4 * @brief Implementation of xml_interface_t.
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 #include "xml_interface.h"
27 #include <sys/types.h>
29 #include <sys/socket.h>
35 #include <libxml/xmlreader.h>
36 #include <libxml/xmlwriter.h>
40 #include <processing/jobs/callback_job.h>
43 typedef struct private_xml_interface_t private_xml_interface_t
;
46 * Private data of an xml_interface_t object.
48 struct private_xml_interface_t
{
51 * Public part of xml_t object.
53 xml_interface_t
public;
61 * job accepting stroke messages
66 ENUM(ike_sa_state_lower_names
, IKE_CREATED
, IKE_DELETING
,
75 * write a bool into element
77 static void write_bool(xmlTextWriterPtr writer
, char *element
, bool val
)
79 xmlTextWriterWriteElement(writer
, element
, val ?
"true" : "false");
83 * write a identification_t into element
85 static void write_id(xmlTextWriterPtr writer
, char *element
, identification_t
*id
)
87 xmlTextWriterStartElement(writer
, element
);
88 switch (id
->get_type(id
))
113 xmlTextWriterWriteAttribute(writer
, "type", type
);
114 xmlTextWriterWriteFormatString(writer
, "%D", id
);
118 xmlTextWriterWriteAttribute(writer
, "type", "any");
121 /* TODO: base64 keyid */
122 xmlTextWriterWriteAttribute(writer
, "type", "keyid");
125 xmlTextWriterEndElement(writer
);
129 * write a host_t address into an element
131 static void write_address(xmlTextWriterPtr writer
, char *element
, host_t
*host
)
133 xmlTextWriterStartElement(writer
, element
);
134 xmlTextWriterWriteAttribute(writer
, "type",
135 host
->get_family(host
) == AF_INET ?
"ipv4" : "ipv6");
136 if (host
->is_anyaddr(host
))
137 { /* do not use %any for XML */
138 xmlTextWriterWriteFormatString(writer
, "%s",
139 host
->get_family(host
) == AF_INET ?
"0.0.0.0" : "::");
143 xmlTextWriterWriteFormatString(writer
, "%H", host
);
145 xmlTextWriterEndElement(writer
);
149 * process a ikesalist query request message
151 static void request_query_ikesa(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
153 iterator_t
*iterator
;
157 xmlTextWriterStartElement(writer
, "ikesalist");
159 iterator
= charon
->ike_sa_manager
->create_iterator(charon
->ike_sa_manager
);
160 while (iterator
->iterate(iterator
, (void**)&ike_sa
))
163 host_t
*local
, *remote
;
164 iterator_t
*children
;
165 child_sa_t
*child_sa
;
167 id
= ike_sa
->get_id(ike_sa
);
169 xmlTextWriterStartElement(writer
, "ikesa");
170 xmlTextWriterWriteFormatElement(writer
, "id", "%d",
171 ike_sa
->get_unique_id(ike_sa
));
172 xmlTextWriterWriteFormatElement(writer
, "status", "%N",
173 ike_sa_state_lower_names
, ike_sa
->get_state(ike_sa
));
174 xmlTextWriterWriteElement(writer
, "role",
175 id
->is_initiator(id
) ?
"initiator" : "responder");
176 xmlTextWriterWriteElement(writer
, "peerconfig", ike_sa
->get_name(ike_sa
));
179 local
= ike_sa
->get_my_host(ike_sa
);
180 xmlTextWriterStartElement(writer
, "local");
181 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
182 id
->is_initiator(id
) ? id
->get_initiator_spi(id
)
183 : id
->get_responder_spi(id
));
184 write_id(writer
, "identification", ike_sa
->get_my_id(ike_sa
));
185 write_address(writer
, "address", local
);
186 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
187 local
->get_port(local
));
188 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
190 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_HERE
));
192 xmlTextWriterEndElement(writer
);
196 remote
= ike_sa
->get_other_host(ike_sa
);
197 xmlTextWriterStartElement(writer
, "remote");
198 xmlTextWriterWriteFormatElement(writer
, "spi", "%.16llx",
199 id
->is_initiator(id
) ? id
->get_responder_spi(id
)
200 : id
->get_initiator_spi(id
));
201 write_id(writer
, "identification", ike_sa
->get_other_id(ike_sa
));
202 write_address(writer
, "address", remote
);
203 xmlTextWriterWriteFormatElement(writer
, "port", "%d",
204 remote
->get_port(remote
));
205 if (ike_sa
->supports_extension(ike_sa
, EXT_NATT
))
207 write_bool(writer
, "nat", ike_sa
->has_condition(ike_sa
, COND_NAT_THERE
));
209 xmlTextWriterEndElement(writer
);
213 xmlTextWriterStartElement(writer
, "childsalist");
214 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
215 while (children
->iterate(children
, (void**)&child_sa
))
219 children
->destroy(children
);
221 xmlTextWriterEndElement(writer
);
224 xmlTextWriterEndElement(writer
);
226 iterator
->destroy(iterator
);
229 xmlTextWriterEndElement(writer
);
233 * process a query request
235 static void request_query(xmlTextReaderPtr reader
, xmlTextWriterPtr writer
)
238 xmlTextWriterStartElement(writer
, "query");
239 while (xmlTextReaderRead(reader
))
241 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
243 if (streq(xmlTextReaderConstName(reader
), "ikesalist"))
245 request_query_ikesa(reader
, writer
);
251 xmlTextWriterEndElement(writer
);
255 * process a request message
257 static void request(xmlTextReaderPtr reader
, char *id
, int fd
)
259 xmlTextWriterPtr writer
;
261 writer
= xmlNewTextWriter(xmlOutputBufferCreateFd(fd
, NULL
));
264 DBG1(DBG_CFG
, "opening SMP XML writer failed");
268 xmlTextWriterStartDocument(writer
, NULL
, NULL
, NULL
);
269 /* <message xmlns="http://www.strongswan.org/smp/1.0"
270 id="id" type="response"> */
271 xmlTextWriterStartElement(writer
, "message");
272 xmlTextWriterWriteAttribute(writer
, "xmlns",
273 "http://www.strongswan.org/smp/1.0");
274 xmlTextWriterWriteAttribute(writer
, "id", id
);
275 xmlTextWriterWriteAttribute(writer
, "type", "response");
277 while (xmlTextReaderRead(reader
))
279 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
)
281 if (streq(xmlTextReaderConstName(reader
), "query"))
283 request_query(reader
, writer
);
288 /* </message> and close document */
289 xmlTextWriterEndDocument(writer
);
290 xmlFreeTextWriter(writer
);
294 * read from a opened connection and process it
296 static job_requeue_t
process(int *fdp
)
298 int oldstate
, fd
= *fdp
;
301 xmlTextReaderPtr reader
;
302 char *id
= NULL
, *type
= NULL
;
304 pthread_cleanup_push((void*)close
, (void*)fd
);
305 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
306 len
= read(fd
, buffer
, sizeof(buffer
));
307 pthread_setcancelstate(oldstate
, NULL
);
308 pthread_cleanup_pop(0);
312 DBG2(DBG_CFG
, "SMP XML connection closed");
313 return JOB_REQUEUE_NONE
;
315 DBG1(DBG_CFG
, "got XML request: %b", buffer
, len
);
317 reader
= xmlReaderForMemory(buffer
, len
, NULL
, NULL
, 0);
320 DBG1(DBG_CFG
, "opening SMP XML reader failed");
321 return JOB_REQUEUE_FAIR
;;
324 /* read message type and id */
325 while (xmlTextReaderRead(reader
))
327 if (xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
&&
328 streq(xmlTextReaderConstName(reader
), "message"))
330 id
= xmlTextReaderGetAttribute(reader
, "id");
331 type
= xmlTextReaderGetAttribute(reader
, "type");
336 /* process message */
339 if (streq(type
, "request"))
341 request(reader
, id
, fd
);
345 /* response(reader, id) */
348 xmlFreeTextReader(reader
);
349 return JOB_REQUEUE_FAIR
;;
353 * accept from XML socket and create jobs to process connections
355 static job_requeue_t
dispatch(private_xml_interface_t
*this)
357 struct sockaddr_un strokeaddr
;
358 int oldstate
, fd
, *fdp
, strokeaddrlen
= sizeof(strokeaddr
);
361 /* wait for connections, but allow thread to terminate */
362 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
363 fd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
364 pthread_setcancelstate(oldstate
, NULL
);
368 DBG1(DBG_CFG
, "accepting SMP XML socket failed: %s", strerror(errno
));
370 return JOB_REQUEUE_FAIR
;;
373 fdp
= malloc_thing(int);
375 job
= callback_job_create((callback_job_cb_t
)process
, fdp
, free
, this->job
);
376 charon
->processor
->queue_job(charon
->processor
, (job_t
*)job
);
378 return JOB_REQUEUE_DIRECT
;
381 struct sockaddr_un unix_addr
= { AF_UNIX
, "/var/run/charon.xml"};
384 * Implementation of itnerface_t.destroy.
386 static void destroy(private_xml_interface_t
*this)
388 this->job
->cancel(this->job
);
390 //unlink(unix_addr.sun_path);
395 * Described in header file
397 interface_t
*interface_create()
399 private_xml_interface_t
*this = malloc_thing(private_xml_interface_t
);
401 struct sockaddr_in tcp_addr
;
403 this->public.interface
.destroy
= (void (*)(interface_t
*))destroy
;
405 /* set up unix socket */
406 this->socket
= socket(AF_INET
, SOCK_STREAM
, 0);//socket(AF_UNIX, SOCK_STREAM, 0);
407 if (this->socket
== -1)
409 DBG1(DBG_CFG
, "could not create XML socket");
414 memset(&tcp_addr
, 0, sizeof(tcp_addr
));
415 tcp_addr
.sin_family
= AF_INET
;
416 tcp_addr
.sin_addr
.s_addr
= INADDR_ANY
;
417 tcp_addr
.sin_port
= htons(4502);
418 if (bind(this->socket
, (struct sockaddr
*)&tcp_addr
, sizeof(tcp_addr
)) < 0)
420 DBG1(DBG_CFG
, "could not bind XML socket: %s", strerror(errno
));
427 old = umask(~S_IRWXU);
428 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
430 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
437 if (listen(this->socket
, 5) < 0)
439 DBG1(DBG_CFG
, "could not listen on XML socket: %s", strerror(errno
));
445 this->job
= callback_job_create((callback_job_cb_t
)dispatch
, this, NULL
, NULL
);
446 charon
->processor
->queue_job(charon
->processor
, (job_t
*)this->job
);
448 return &this->public.interface
;