8dd614493f0f38c46d674b1c37042350fc5f6a69
[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
41
42 static struct sockaddr_un socket_addr = { AF_UNIX, "/var/run/charon.xml"};
43
44
45 typedef struct private_xml_interface_t private_xml_interface_t;
46
47 /**
48 * Private data of an xml_interface_t object.
49 */
50 struct private_xml_interface_t {
51
52 /**
53 * Public part of xml_t object.
54 */
55 xml_interface_t public;
56
57 /**
58 * XML unix socket fd
59 */
60 int socket;
61
62 /**
63 * thread receiving messages
64 */
65 pthread_t thread;
66 };
67
68 static void get(private_xml_interface_t *this,
69 xmlTextReaderPtr reader, xmlTextWriterPtr writer)
70 {
71
72 if (/* <GetResponse> */
73 xmlTextWriterStartElement(writer, "GetResponse") < 0 ||
74 /* <Status Code="200"><Message/></Status> */
75 xmlTextWriterStartElement(writer, "Status") < 0 ||
76 xmlTextWriterWriteAttribute(writer, "Code", "200") < 0 ||
77 xmlTextWriterStartElement(writer, "Message") < 0 ||
78 xmlTextWriterEndElement(writer) < 0 ||
79 xmlTextWriterEndElement(writer) < 0 ||
80 /* <ConnectionList/> */
81 xmlTextWriterStartElement(writer, "ConnectionList") < 0 ||
82 xmlTextWriterEndElement(writer) < 0 ||
83 /* </GetResponse> */
84 xmlTextWriterEndElement(writer) < 0)
85 {
86 DBG1(DBG_CFG, "error writing XML document (GetResponse)");
87 }
88
89
90 /*
91 DBG1(DBG_CFG, "%d %d %s %d %d %s",
92 xmlTextReaderDepth(reader),
93 ,
94 xmlTextReaderConstName(reader),
95 xmlTextReaderIsEmptyElement(reader),
96 xmlTextReaderHasValue(reader),
97 xmlTextReaderConstValue(reader));
98 */
99 }
100
101 static void receive(private_xml_interface_t *this)
102 {
103 charon->drop_capabilities(charon, TRUE);
104
105 /* disable cancellation by default */
106 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
107
108 while (TRUE)
109 {
110 struct sockaddr_un strokeaddr;
111 int strokeaddrlen = sizeof(strokeaddr);
112 int oldstate;
113 int fd;
114 char buffer[4096];
115 size_t len;
116
117 /* wait for connections, but allow thread to terminate */
118 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
119 fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
120 pthread_setcancelstate(oldstate, NULL);
121
122 if (fd < 0)
123 {
124 DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
125 continue;
126 }
127 DBG2(DBG_CFG, "SMP XML connection opened");
128 while (TRUE)
129 {
130 xmlTextReaderPtr reader;
131 xmlTextWriterPtr writer;
132
133 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
134 len = read(fd, buffer, sizeof(buffer));
135 pthread_setcancelstate(oldstate, NULL);
136 if (len <= 0)
137 {
138 close(fd);
139 DBG2(DBG_CFG, "SMP XML connection closed");
140 break;
141 }
142
143 reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
144 if (reader == NULL)
145 {
146 DBG1(DBG_CFG, "opening SMP XML reader failed");
147 continue;
148 }
149
150 writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
151 if (writer == NULL)
152 {
153 xmlFreeTextReader(reader);
154 DBG1(DBG_CFG, "opening SMP XML writer failed");
155 continue;
156 }
157
158 /* create the standard message parts */
159 if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) < 0 ||
160 /* <SMPMessage xmlns="http://www.strongswan.org/smp/1.0"> */
161 xmlTextWriterStartElement(writer, "SMPMessage") < 0 ||
162 xmlTextWriterWriteAttribute(writer, "xmlns",
163 "http://www.strongswan.org/smp/1.0") < 0 ||
164 /* <Body> */
165 xmlTextWriterStartElement(writer, "Body") < 0)
166 {
167 xmlFreeTextReader(reader);
168 xmlFreeTextWriter(writer);
169 DBG1(DBG_CFG, "creating SMP XML message failed");
170 continue;
171 }
172
173 while (TRUE)
174 {
175 switch (xmlTextReaderRead(reader))
176 {
177 case 1:
178 {
179 if (xmlTextReaderNodeType(reader) ==
180 XML_READER_TYPE_ELEMENT)
181 {
182 if (streq(xmlTextReaderConstName(reader), "GetRequest"))
183 {
184 get(this, reader, writer);
185 break;
186 }
187 }
188 continue;
189 }
190 case 0:
191 /* end of XML */
192 break;
193 default:
194 DBG1(DBG_CFG, "parsing SMP XML message failed");
195 break;
196 }
197 xmlFreeTextReader(reader);
198 break;
199 }
200 /* write </Body></SMPMessage> and close document */
201 if (xmlTextWriterEndDocument(writer) < 0)
202 {
203 DBG1(DBG_CFG, "completing SMP XML message failed");
204 }
205 xmlFreeTextWriter(writer);
206 /* write a newline to indicate end of xml */
207 write(fd, "\n", 1);
208 }
209 }
210 }
211
212 /**
213 * Implementation of itnerface_t.destroy.
214 */
215 static void destroy(private_xml_interface_t *this)
216 {
217 pthread_cancel(this->thread);
218 pthread_join(this->thread, NULL);
219 close(this->socket);
220 unlink(socket_addr.sun_path);
221 free(this);
222 }
223
224 /*
225 * Described in header file
226 */
227 interface_t *interface_create()
228 {
229 private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
230 mode_t old;
231
232 this->public.interface.destroy = (void (*)(interface_t*))destroy;
233
234 /* set up unix socket */
235 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
236 if (this->socket == -1)
237 {
238 DBG1(DBG_CFG, "could not create XML socket");
239 free(this);
240 return NULL;
241 }
242
243 old = umask(~S_IRWXU);
244 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
245 {
246 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
247 close(this->socket);
248 free(this);
249 return NULL;
250 }
251 umask(old);
252
253 if (listen(this->socket, 0) < 0)
254 {
255 DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
256 close(this->socket);
257 free(this);
258 return NULL;
259 }
260
261 if (pthread_create(&this->thread, NULL, (void*(*)(void*))receive, this) != 0)
262 {
263 DBG1(DBG_CFG, "could not create XML socket thread: %s", strerror(errno));
264 close(this->socket);
265 unlink(socket_addr.sun_path);
266 free(this);
267 return NULL;
268 }
269
270 return &this->public.interface;
271 }
272