a3be5703dcc2dcec8acbf938b2a95e06c8f1a625
[strongswan.git] / src / charon / control / interfaces / xml_interface.c
1 /**
2 * @file xml_interface.c
3 *
4 * @brief Implementation of xml_interface_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include <stdlib.h>
24
25 #include "xml_interface.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <pthread.h>
34 #include <signal.h>
35 #include <libxml/xmlreader.h>
36 #include <libxml/xmlwriter.h>
37
38 #include <library.h>
39 #include <daemon.h>
40 #include <processing/jobs/callback_job.h>
41
42
43 typedef struct private_xml_interface_t private_xml_interface_t;
44
45 /**
46 * Private data of an xml_interface_t object.
47 */
48 struct private_xml_interface_t {
49
50 /**
51 * Public part of xml_t object.
52 */
53 xml_interface_t public;
54
55 /**
56 * XML unix socket fd
57 */
58 int socket;
59
60 /**
61 * job accepting stroke messages
62 */
63 callback_job_t *job;
64 };
65
66 ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING,
67 "created",
68 "connecting",
69 "established",
70 "rekeying",
71 "deleting",
72 );
73
74 /**
75 * write a bool into element
76 */
77 static void write_bool(xmlTextWriterPtr writer, char *element, bool val)
78 {
79 xmlTextWriterWriteElement(writer, element, val ? "true" : "false");
80 }
81
82 /**
83 * write a identification_t into element
84 */
85 static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id)
86 {
87 xmlTextWriterStartElement(writer, element);
88 switch (id->get_type(id))
89 {
90 {
91 char *type = "";
92 while (TRUE)
93 {
94 case ID_IPV4_ADDR:
95 type = "ipv4";
96 break;
97 case ID_IPV6_ADDR:
98 type = "ipv6";
99 break;
100 case ID_FQDN:
101 type = "fqdn";
102 break;
103 case ID_RFC822_ADDR:
104 type = "email";
105 break;
106 case ID_DER_ASN1_DN:
107 type = "asn1dn";
108 break;
109 case ID_DER_ASN1_GN:
110 type = "asn1gn";
111 break;
112 }
113 xmlTextWriterWriteAttribute(writer, "type", type);
114 xmlTextWriterWriteFormatString(writer, "%D", id);
115 break;
116 }
117 case ID_ANY:
118 xmlTextWriterWriteAttribute(writer, "type", "any");
119 break;
120 default:
121 /* TODO: base64 keyid */
122 xmlTextWriterWriteAttribute(writer, "type", "keyid");
123 break;
124 }
125 xmlTextWriterEndElement(writer);
126 }
127
128 /**
129 * write a host_t address into an element
130 */
131 static void write_address(xmlTextWriterPtr writer, char *element, host_t *host)
132 {
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" : "::");
140 }
141 else
142 {
143 xmlTextWriterWriteFormatString(writer, "%H", host);
144 }
145 xmlTextWriterEndElement(writer);
146 }
147
148 /**
149 * write networks element
150 */
151 static void write_networks(xmlTextWriterPtr writer, char *element,
152 linked_list_t *list)
153 {
154 iterator_t *iterator;
155 traffic_selector_t *ts;
156
157 xmlTextWriterStartElement(writer, element);
158 iterator = list->create_iterator(list, TRUE);
159 while (iterator->iterate(iterator, (void**)&ts))
160 {
161 xmlTextWriterStartElement(writer, "network");
162 xmlTextWriterWriteAttribute(writer, "type",
163 ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6");
164 xmlTextWriterWriteFormatString(writer, "%R", ts);
165 xmlTextWriterEndElement(writer);
166 }
167 iterator->destroy(iterator);
168 xmlTextWriterEndElement(writer);
169 }
170
171 /**
172 * write a childEnd
173 */
174 static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local)
175 {
176 linked_list_t *list;
177
178 xmlTextWriterWriteFormatElement(writer, "spi", "%lx",
179 htonl(child->get_spi(child, local)));
180 list = child->get_traffic_selectors(child, local);
181 write_networks(writer, "networks", list);
182 }
183
184 /**
185 * write a child_sa_t
186 */
187 static void write_child(xmlTextWriterPtr writer, child_sa_t *child)
188 {
189 mode_t mode;
190 encryption_algorithm_t encr;
191 integrity_algorithm_t int_algo;
192 size_t encr_len, int_len;
193 u_int32_t rekey, use_in, use_out, use_fwd;
194 child_cfg_t *config;
195
196 config = child->get_config(child);
197 child->get_stats(child, &mode, &encr, &encr_len, &int_algo, &int_len,
198 &rekey, &use_in, &use_out, &use_fwd);
199
200 xmlTextWriterStartElement(writer, "childsa");
201 xmlTextWriterWriteFormatElement(writer, "reqid", "%d", child->get_reqid(child));
202 xmlTextWriterWriteFormatElement(writer, "childconfig", "%s",
203 config->get_name(config));
204 xmlTextWriterStartElement(writer, "local");
205 write_childend(writer, child, TRUE);
206 xmlTextWriterEndElement(writer);
207 xmlTextWriterStartElement(writer, "remote");
208 write_childend(writer, child, FALSE);
209 xmlTextWriterEndElement(writer);
210 xmlTextWriterEndElement(writer);
211 }
212
213 /**
214 * process a ikesalist query request message
215 */
216 static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
217 {
218 iterator_t *iterator;
219 ike_sa_t *ike_sa;
220
221 /* <ikesalist> */
222 xmlTextWriterStartElement(writer, "ikesalist");
223
224 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
225 while (iterator->iterate(iterator, (void**)&ike_sa))
226 {
227 ike_sa_id_t *id;
228 host_t *local, *remote;
229 iterator_t *children;
230 child_sa_t *child_sa;
231
232 id = ike_sa->get_id(ike_sa);
233
234 xmlTextWriterStartElement(writer, "ikesa");
235 xmlTextWriterWriteFormatElement(writer, "id", "%d",
236 ike_sa->get_unique_id(ike_sa));
237 xmlTextWriterWriteFormatElement(writer, "status", "%N",
238 ike_sa_state_lower_names, ike_sa->get_state(ike_sa));
239 xmlTextWriterWriteElement(writer, "role",
240 id->is_initiator(id) ? "initiator" : "responder");
241 xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa));
242
243 /* <local> */
244 local = ike_sa->get_my_host(ike_sa);
245 xmlTextWriterStartElement(writer, "local");
246 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
247 id->is_initiator(id) ? id->get_initiator_spi(id)
248 : id->get_responder_spi(id));
249 write_id(writer, "identification", ike_sa->get_my_id(ike_sa));
250 write_address(writer, "address", local);
251 xmlTextWriterWriteFormatElement(writer, "port", "%d",
252 local->get_port(local));
253 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
254 {
255 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE));
256 }
257 xmlTextWriterEndElement(writer);
258 /* </local> */
259
260 /* <remote> */
261 remote = ike_sa->get_other_host(ike_sa);
262 xmlTextWriterStartElement(writer, "remote");
263 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
264 id->is_initiator(id) ? id->get_responder_spi(id)
265 : id->get_initiator_spi(id));
266 write_id(writer, "identification", ike_sa->get_other_id(ike_sa));
267 write_address(writer, "address", remote);
268 xmlTextWriterWriteFormatElement(writer, "port", "%d",
269 remote->get_port(remote));
270 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
271 {
272 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE));
273 }
274 xmlTextWriterEndElement(writer);
275 /* </remote> */
276
277 /* <childsalist> */
278 xmlTextWriterStartElement(writer, "childsalist");
279 children = ike_sa->create_child_sa_iterator(ike_sa);
280 while (children->iterate(children, (void**)&child_sa))
281 {
282 write_child(writer, child_sa);
283 }
284 children->destroy(children);
285 /* </childsalist> */
286 xmlTextWriterEndElement(writer);
287
288 /* </ikesa> */
289 xmlTextWriterEndElement(writer);
290 }
291 iterator->destroy(iterator);
292
293 /* </ikesalist> */
294 xmlTextWriterEndElement(writer);
295 }
296
297 /**
298 * process a configlist query request message
299 */
300 static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
301 {
302 iterator_t *iterator;
303 peer_cfg_t *peer_cfg;
304
305 /* <configlist> */
306 xmlTextWriterStartElement(writer, "configlist");
307
308 iterator = charon->backends->create_iterator(charon->backends);
309 while (iterator->iterate(iterator, (void**)&peer_cfg))
310 {
311 iterator_t *children;
312 child_cfg_t *child_cfg;
313 ike_cfg_t *ike_cfg;
314 linked_list_t *list;
315
316 /* <peerconfig> */
317 xmlTextWriterStartElement(writer, "peerconfig");
318 xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg));
319 write_id(writer, "local", peer_cfg->get_my_id(peer_cfg));
320 write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg));
321
322 /* <ikeconfig> */
323 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
324 xmlTextWriterStartElement(writer, "ikeconfig");
325 write_address(writer, "local", ike_cfg->get_my_host(ike_cfg));
326 write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg));
327 xmlTextWriterEndElement(writer);
328 /* </ikeconfig> */
329
330 /* <childconfiglist> */
331 xmlTextWriterStartElement(writer, "childconfiglist");
332 children = peer_cfg->create_child_cfg_iterator(peer_cfg);
333 while (children->iterate(children, (void**)&child_cfg))
334 {
335 /* <childconfig> */
336 xmlTextWriterStartElement(writer, "childconfig");
337 xmlTextWriterWriteElement(writer, "name",
338 child_cfg->get_name(child_cfg));
339 list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
340 write_networks(writer, "local", list);
341 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
342 list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
343 write_networks(writer, "remote", list);
344 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
345 xmlTextWriterEndElement(writer);
346 /* </childconfig> */
347 }
348 children->destroy(children);
349 /* </childconfiglist> */
350 xmlTextWriterEndElement(writer);
351 /* </peerconfig> */
352 xmlTextWriterEndElement(writer);
353 }
354 iterator->destroy(iterator);
355 /* </configlist> */
356 xmlTextWriterEndElement(writer);
357 }
358
359 /**
360 * callback which logs to a XML writer
361 */
362 static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level,
363 ike_sa_t* ike_sa, char* format, va_list args)
364 {
365 if (level <= 1)
366 {
367 /* <item> */
368 xmlTextWriterStartElement(writer, "item");
369 xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level);
370 xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal);
371 xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self());
372 xmlTextWriterWriteVFormatString(writer, format, args);
373 xmlTextWriterEndElement(writer);
374 /* </item> */
375 }
376 return TRUE;
377 }
378
379 /**
380 * process a *terminate control request message
381 */
382 static void request_control_terminate(xmlTextReaderPtr reader,
383 xmlTextWriterPtr writer, bool ike)
384 {
385 if (xmlTextReaderRead(reader) &&
386 xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
387 {
388 const char *str;
389 u_int32_t id;
390 status_t status;
391
392 str = xmlTextReaderConstValue(reader);
393 if (str == NULL || !(id = atoi(str)))
394 {
395 DBG1(DBG_CFG, "error parsing XML id string");
396 return;
397 }
398 DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id);
399
400 /* <log> */
401 xmlTextWriterStartElement(writer, "log");
402 if (ike)
403 {
404 status = charon->interfaces->terminate_ike(
405 charon->interfaces, id,
406 (interface_manager_cb_t)xml_callback, writer);
407 }
408 else
409 {
410 status = charon->interfaces->terminate_child(
411 charon->interfaces, id,
412 (interface_manager_cb_t)xml_callback, writer);
413 }
414 /* </log> */
415 xmlTextWriterEndElement(writer);
416 xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
417 }
418 }
419
420 /**
421 * process a *initiate control request message
422 */
423 static void request_control_initiate(xmlTextReaderPtr reader,
424 xmlTextWriterPtr writer, bool ike)
425 {
426 if (xmlTextReaderRead(reader) &&
427 xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
428 {
429 const char *str;
430 status_t status = FAILED;
431 peer_cfg_t *peer;
432 child_cfg_t *child = NULL;
433 iterator_t *iterator;
434
435 str = xmlTextReaderConstValue(reader);
436 if (str == NULL)
437 {
438 DBG1(DBG_CFG, "error parsing XML config name string");
439 return;
440 }
441 DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str);
442
443 /* <log> */
444 xmlTextWriterStartElement(writer, "log");
445 peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str);
446 if (peer)
447 {
448 iterator = peer->create_child_cfg_iterator(peer);
449 if (ike)
450 {
451 if (!iterator->iterate(iterator, (void**)&child))
452 {
453 child = NULL;
454 }
455 child->get_ref(child);
456 }
457 else
458 {
459 while (iterator->iterate(iterator, (void**)&child))
460 {
461 if (streq(child->get_name(child), str))
462 {
463 child->get_ref(child);
464 break;
465 }
466 child = NULL;
467 }
468 }
469 iterator->destroy(iterator);
470 if (child)
471 {
472 status = charon->interfaces->initiate(charon->interfaces,
473 peer, child, (interface_manager_cb_t)xml_callback,
474 writer);
475 }
476 else
477 {
478 peer->destroy(peer);
479 }
480 }
481 /* </log> */
482 xmlTextWriterEndElement(writer);
483 xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
484 }
485 }
486
487 /**
488 * process a query request
489 */
490 static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
491 {
492 /* <query> */
493 xmlTextWriterStartElement(writer, "query");
494 while (xmlTextReaderRead(reader))
495 {
496 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
497 {
498 if (streq(xmlTextReaderConstName(reader), "ikesalist"))
499 {
500 request_query_ikesa(reader, writer);
501 break;
502 }
503 if (streq(xmlTextReaderConstName(reader), "configlist"))
504 {
505 request_query_config(reader, writer);
506 break;
507 }
508 }
509 }
510 /* </query> */
511 xmlTextWriterEndElement(writer);
512 }
513
514 /**
515 * process a control request
516 */
517 static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
518 {
519 /* <control> */
520 xmlTextWriterStartElement(writer, "control");
521 while (xmlTextReaderRead(reader))
522 {
523 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
524 {
525 if (streq(xmlTextReaderConstName(reader), "ikesaterminate"))
526 {
527 request_control_terminate(reader, writer, TRUE);
528 break;
529 }
530 if (streq(xmlTextReaderConstName(reader), "childsaterminate"))
531 {
532 request_control_terminate(reader, writer, FALSE);
533 break;
534 }
535 if (streq(xmlTextReaderConstName(reader), "ikesainitiate"))
536 {
537 request_control_initiate(reader, writer, TRUE);
538 break;
539 }
540 if (streq(xmlTextReaderConstName(reader), "childsainitiate"))
541 {
542 request_control_initiate(reader, writer, FALSE);
543 break;
544 }
545 }
546 }
547 /* </control> */
548 xmlTextWriterEndElement(writer);
549 }
550
551 /**
552 * process a request message
553 */
554 static void request(xmlTextReaderPtr reader, char *id, int fd)
555 {
556 xmlTextWriterPtr writer;
557
558 writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
559 if (writer == NULL)
560 {
561 DBG1(DBG_CFG, "opening SMP XML writer failed");
562 return;
563 }
564
565 xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
566 /* <message xmlns="http://www.strongswan.org/smp/1.0"
567 id="id" type="response"> */
568 xmlTextWriterStartElement(writer, "message");
569 xmlTextWriterWriteAttribute(writer, "xmlns",
570 "http://www.strongswan.org/smp/1.0");
571 xmlTextWriterWriteAttribute(writer, "id", id);
572 xmlTextWriterWriteAttribute(writer, "type", "response");
573
574 while (xmlTextReaderRead(reader))
575 {
576 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
577 {
578 if (streq(xmlTextReaderConstName(reader), "query"))
579 {
580 request_query(reader, writer);
581 break;
582 }
583 if (streq(xmlTextReaderConstName(reader), "control"))
584 {
585 request_control(reader, writer);
586 break;
587 }
588 }
589 }
590 /* </message> and close document */
591 xmlTextWriterEndDocument(writer);
592 xmlFreeTextWriter(writer);
593 }
594
595 /**
596 * cleanup helper function for open file descriptors
597 */
598 static void closefdp(int *fd)
599 {
600 close(*fd);
601 }
602
603 /**
604 * read from a opened connection and process it
605 */
606 static job_requeue_t process(int *fdp)
607 {
608 int oldstate, fd = *fdp;
609 char buffer[4096];
610 size_t len;
611 xmlTextReaderPtr reader;
612 char *id = NULL, *type = NULL;
613
614 pthread_cleanup_push((void*)closefdp, (void*)&fd);
615 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
616 len = read(fd, buffer, sizeof(buffer));
617 pthread_setcancelstate(oldstate, NULL);
618 pthread_cleanup_pop(0);
619 if (len <= 0)
620 {
621 close(fd);
622 DBG2(DBG_CFG, "SMP XML connection closed");
623 return JOB_REQUEUE_NONE;
624 }
625 DBG3(DBG_CFG, "got XML request: %b", buffer, len);
626
627 reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
628 if (reader == NULL)
629 {
630 DBG1(DBG_CFG, "opening SMP XML reader failed");
631 return JOB_REQUEUE_FAIR;;
632 }
633
634 /* read message type and id */
635 while (xmlTextReaderRead(reader))
636 {
637 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT &&
638 streq(xmlTextReaderConstName(reader), "message"))
639 {
640 id = xmlTextReaderGetAttribute(reader, "id");
641 type = xmlTextReaderGetAttribute(reader, "type");
642 break;
643 }
644 }
645
646 /* process message */
647 if (id && type)
648 {
649 if (streq(type, "request"))
650 {
651 request(reader, id, fd);
652 }
653 else
654 {
655 /* response(reader, id) */
656 }
657 }
658 xmlFreeTextReader(reader);
659 return JOB_REQUEUE_FAIR;;
660 }
661
662 /**
663 * accept from XML socket and create jobs to process connections
664 */
665 static job_requeue_t dispatch(private_xml_interface_t *this)
666 {
667 struct sockaddr_un strokeaddr;
668 int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr);
669 callback_job_t *job;
670
671 /* wait for connections, but allow thread to terminate */
672 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
673 fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
674 pthread_setcancelstate(oldstate, NULL);
675
676 if (fd < 0)
677 {
678 DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
679 sleep(1);
680 return JOB_REQUEUE_FAIR;;
681 }
682
683 fdp = malloc_thing(int);
684 *fdp = fd;
685 job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job);
686 charon->processor->queue_job(charon->processor, (job_t*)job);
687
688 return JOB_REQUEUE_DIRECT;
689 }
690
691 /**
692 * Implementation of itnerface_t.destroy.
693 */
694 static void destroy(private_xml_interface_t *this)
695 {
696 this->job->cancel(this->job);
697 close(this->socket);
698 free(this);
699 }
700
701 /*
702 * Described in header file
703 */
704 interface_t *interface_create()
705 {
706 struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
707 private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
708 mode_t old;
709
710 this->public.interface.destroy = (void (*)(interface_t*))destroy;
711
712 /* set up unix socket */
713 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
714 if (this->socket == -1)
715 {
716 DBG1(DBG_CFG, "could not create XML socket");
717 free(this);
718 return NULL;
719 }
720
721 unlink(unix_addr.sun_path);
722 old = umask(~(S_IRWXU | S_IRWXG));
723 if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0)
724 {
725 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
726 close(this->socket);
727 free(this);
728 return NULL;
729 }
730 umask(old);
731 if (chown(unix_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0)
732 {
733 DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno));
734 }
735
736 if (listen(this->socket, 5) < 0)
737 {
738 DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
739 close(this->socket);
740 free(this);
741 return NULL;
742 }
743
744 this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
745 charon->processor->queue_job(charon->processor, (job_t*)this->job);
746
747 return &this->public.interface;
748 }
749