extended interface_manager (more work needed here)
[strongswan.git] / src / charon / control / interface_manager.c
1 /**
2 * @file interface_manager.c
3 *
4 * @brief Implementation of interface_manager_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 "interface_manager.h"
24
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <dlfcn.h>
29
30 #include <daemon.h>
31 #include <library.h>
32 #include <control/interfaces/interface.h>
33 #include <processing/job_queue.h>
34 #include <processing/jobs/initiate_job.h>
35
36
37 typedef struct private_interface_manager_t private_interface_manager_t;
38 typedef struct interface_bus_listener_t interface_bus_listener_t;
39
40 /**
41 * Private data of an stroke_t object.
42 */
43 struct private_interface_manager_t {
44
45 /**
46 * Public part of stroke_t object.
47 */
48 interface_manager_t public;
49
50 /**
51 * a list of all loaded interfaces
52 */
53 linked_list_t *interfaces;
54
55 /**
56 * dlopen() handles of interfaces
57 */
58 linked_list_t *handles;
59 };
60
61 /**
62 * helper struct to map bus listener callbacks to interface callbacks
63 */
64 struct interface_bus_listener_t {
65
66 /**
67 * bus listener callback function (called)
68 */
69 bus_listener_t listener;
70
71 /**
72 * IKE_SA to use for message filtering
73 */
74 ike_sa_t *ike_sa;
75
76 /**
77 * interface callback (listener gets redirected to here)
78 */
79 interface_manager_cb_t callback;
80
81 /**
82 * user parameter to pass to callback
83 */
84 void *param;
85 };
86
87 /**
88 * Implementation of interface_manager_t.create_ike_sa_iterator.
89 */
90 static iterator_t* create_ike_sa_iterator(interface_manager_t *this)
91 {
92 return charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
93 }
94
95 /**
96 * Implementation of interface_manager_t.initiate.
97 */
98 static status_t initiate(private_interface_manager_t *this,
99 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
100 interface_manager_cb_t cb, void *param)
101 {
102 ike_sa_t *ours = NULL;
103 job_t *job;
104 status_t retval;
105
106 charon->bus->set_listen_state(charon->bus, TRUE);
107
108 job = (job_t*)initiate_job_create(peer_cfg, child_cfg);
109 charon->job_queue->add(charon->job_queue, job);
110
111 while (TRUE)
112 {
113 level_t level;
114 signal_t signal;
115 int thread;
116 ike_sa_t *ike_sa;
117 char* format;
118 va_list args;
119
120 signal = charon->bus->listen(charon->bus, &level, &thread,
121 &ike_sa, &format, &args);
122
123 if (cb && (ike_sa == ours || ours == NULL))
124 {
125 if (!cb(param, signal, level, ike_sa, format, args))
126 {
127 charon->bus->set_listen_state(charon->bus, FALSE);
128 return NEED_MORE;
129 }
130 }
131
132 switch (signal)
133 {
134 case CHILD_UP_SUCCESS:
135 if (ike_sa == ours)
136 {
137 retval = SUCCESS;
138 break;
139 }
140 continue;
141 case CHILD_UP_FAILED:
142 case IKE_UP_FAILED:
143 if (ike_sa == ours)
144 {
145 retval = FAILED;
146 break;
147 }
148 continue;
149 case CHILD_UP_START:
150 case IKE_UP_START:
151 if (ours == NULL)
152 {
153 ours = ike_sa;
154 }
155 continue;
156 default:
157 continue;
158 }
159 break;
160 }
161 charon->bus->set_listen_state(charon->bus, FALSE);
162 return retval;
163 }
164
165 /**
166 * listener function for terminate_ike
167 */
168 static bool terminate_listener(interface_bus_listener_t *this, signal_t signal,
169 level_t level, int thread, ike_sa_t *ike_sa,
170 char* format, va_list args)
171 {
172 if (this->ike_sa == ike_sa)
173 {
174 if (!this->callback(this->param, signal, level, ike_sa, format, args))
175 {
176 return FALSE;
177 }
178 switch (signal)
179 {
180 case IKE_DOWN_FAILED:
181 case IKE_DOWN_SUCCESS:
182 {
183 return FALSE;
184 }
185 default:
186 break;
187 }
188 }
189 return TRUE;
190 }
191
192 /**
193 * Implementation of interface_manager_t.terminate_ike.
194 */
195 static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
196 interface_manager_cb_t callback, void *param)
197 {
198 ike_sa_t *ike_sa;
199 status_t status;
200
201 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
202 unique_id, FALSE);
203 if (ike_sa == NULL)
204 {
205 return NOT_FOUND;
206 }
207
208 /* we listen passively first, to catch the signals we are raising */
209 if (callback)
210 {
211 interface_bus_listener_t listener;
212
213 listener.listener.signal = (void*)terminate_listener;
214 listener.callback = callback;
215 listener.ike_sa = ike_sa;
216 listener.param = param;
217 charon->bus->add_listener(charon->bus, &listener.listener);
218 }
219 charon->bus->set_listen_state(charon->bus, TRUE);
220 status = ike_sa->delete(ike_sa);
221 if (status == DESTROY_ME)
222 {
223 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
224 }
225 else
226 {
227 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
228
229 /* wait until IKE_SA is cleanly deleted using a delete message */
230 while (TRUE)
231 {
232 level_t level;
233 signal_t signal;
234 int thread;
235 ike_sa_t *current;
236 char* format;
237 va_list args;
238
239 signal = charon->bus->listen(charon->bus, &level, &thread,
240 &current, &format, &args);
241
242 if (ike_sa == current)
243 {
244 switch (signal)
245 {
246 case IKE_DOWN_FAILED:
247 case IKE_DOWN_SUCCESS:
248 {
249 break;
250 }
251 default:
252 continue;
253 }
254 break;
255 }
256 }
257 }
258 charon->bus->set_listen_state(charon->bus, FALSE);
259
260 return SUCCESS;
261 }
262
263 /**
264 * Implementation of interface_manager_t.terminate_child.
265 */
266 static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
267 interface_manager_cb_t callback, void *param)
268 {
269 return FAILED;
270 }
271
272 /**
273 * Implementation of interface_manager_t.route.
274 */
275 static status_t route(interface_manager_t *this,
276 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
277 interface_manager_cb_t callback, void *param)
278 {
279 return FAILED;
280 }
281
282 /**
283 * Implementation of interface_manager_t.unroute.
284 */
285 static status_t unroute(interface_manager_t *this, u_int32_t reqid,
286 interface_manager_cb_t callback, void *param)
287 {
288 return FAILED;
289 }
290
291 /**
292 * load the control interface modules
293 */
294 static void load_interfaces(private_interface_manager_t *this)
295 {
296 struct dirent* entry;
297 struct stat stb;
298 DIR* dir;
299
300 if (stat(IPSEC_INTERFACEDIR, &stb) == -1 || !(stb.st_mode & S_IFDIR))
301 {
302 DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
303 return;
304 }
305
306 dir = opendir(IPSEC_INTERFACEDIR);
307 if (dir == NULL)
308 {
309 DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
310 return;
311 }
312
313 DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'");
314
315 while ((entry = readdir(dir)) != NULL)
316 {
317 char file[256];
318 interface_t *interface;
319 interface_constructor_t constructor;
320 void *handle;
321 char *ending;
322
323 snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name);
324
325 if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
326 {
327 DBG2(DBG_CFG, " skipping %s, doesn't look like a file",
328 entry->d_name);
329 continue;
330 }
331 ending = entry->d_name + strlen(entry->d_name) - 3;
332 if (ending <= entry->d_name || !streq(ending, ".so"))
333 {
334 /* skip anything which does not look like a library */
335 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
336 entry->d_name);
337 continue;
338 }
339 /* try to load the library */
340 handle = dlopen(file, RTLD_LAZY);
341 if (handle == NULL)
342 {
343 DBG1(DBG_CFG, " opening control interface module %s failed: %s",
344 entry->d_name, dlerror());
345 continue;
346 }
347 constructor = dlsym(handle, "interface_create");
348 if (constructor == NULL)
349 {
350 DBG1(DBG_CFG, " interface module %s has no interface_create() "
351 "function, skipped", entry->d_name);
352 dlclose(handle);
353 continue;
354 }
355
356 interface = constructor();
357 if (interface == NULL)
358 {
359 DBG1(DBG_CFG, " unable to create instance of interface "
360 "module %s, skipped", entry->d_name);
361 dlclose(handle);
362 continue;
363 }
364 DBG1(DBG_CFG, " loaded control interface module successfully from %s", entry->d_name);
365 this->interfaces->insert_last(this->interfaces, interface);
366 this->handles->insert_last(this->handles, handle);
367 }
368 closedir(dir);
369 }
370
371
372 /**
373 * Implementation of stroke_t.destroy.
374 */
375 static void destroy(private_interface_manager_t *this)
376 {
377 this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy));
378 this->handles->destroy_function(this->handles, (void*)dlclose);
379 free(this);
380 }
381
382 /*
383 * Described in header-file
384 */
385 interface_manager_t *interface_manager_create(void)
386 {
387 private_interface_manager_t *this = malloc_thing(private_interface_manager_t);
388
389 this->public.create_ike_sa_iterator = (iterator_t*(*)(interface_manager_t*))create_ike_sa_iterator;
390 this->public.initiate = (status_t(*)(interface_manager_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate;
391 this->public.terminate_ike = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void*))terminate_ike;
392 this->public.terminate_child = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void *param))terminate_child;
393 this->public.route = (status_t(*)(interface_manager_t*,peer_cfg_t*, child_cfg_t*,interface_manager_cb_t,void*))route;
394 this->public.unroute = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t,void*))unroute;
395 this->public.destroy = (void (*)(interface_manager_t*))destroy;
396
397 this->interfaces = linked_list_create();
398 this->handles = linked_list_create();
399
400 load_interfaces(this);
401
402 return &this->public;
403 }
404