bridging using libbridge
[strongswan.git] / src / dumm / dumm.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17
18 #include <sys/types.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <dirent.h>
22
23 #include <debug.h>
24
25 #include "dumm.h"
26
27 typedef struct private_dumm_t private_dumm_t;
28
29 struct private_dumm_t {
30 /** public dumm interface */
31 dumm_t public;
32 /** working dir */
33 char *dir;
34 /** list of managed guests */
35 linked_list_t *guests;
36 /** list of managed bridges */
37 linked_list_t *bridges;
38 /** do not catch signals if we are destroying */
39 bool destroying;
40 };
41
42 /**
43 * Implementation of dumm_t.create_guest.
44 */
45 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
46 char *master, int mem)
47 {
48 guest_t *guest;
49
50 guest = guest_create(this->dir, name, kernel, master, mem);
51 if (guest)
52 {
53 this->guests->insert_last(this->guests, guest);
54 }
55 return guest;
56 }
57
58 /**
59 * Implementation of dumm_t.create_guest_iterator.
60 */
61 static iterator_t* create_guest_iterator(private_dumm_t *this)
62 {
63 return this->guests->create_iterator(this->guests, TRUE);
64 }
65
66 /**
67 * Implementation of dumm_t.create_bridge.
68 */
69 static bridge_t* create_bridge(private_dumm_t *this, char *name)
70 {
71 bridge_t *bridge;
72
73 bridge = bridge_create(name);
74 if (bridge)
75 {
76 this->bridges->insert_last(this->bridges, bridge);
77 }
78 return bridge;
79 }
80
81 /**
82 * Implementation of dumm_t.create_bridge_iterator.
83 */
84 static iterator_t* create_bridge_iterator(private_dumm_t *this)
85 {
86 return this->bridges->create_iterator(this->bridges, TRUE);
87 }
88
89 /**
90 * Implementation of dumm_t.sigchild_handler.
91 */
92 static void sigchild_handler(private_dumm_t *this, siginfo_t *info)
93 {
94 if (this->destroying)
95 {
96 return;
97 }
98 switch (info->si_code)
99 {
100 case CLD_EXITED:
101 case CLD_KILLED:
102 case CLD_DUMPED:
103 {
104 iterator_t *iterator;
105 guest_t *guest;
106
107 iterator = this->guests->create_iterator(this->guests, TRUE);
108 while (iterator->iterate(iterator, (void**)&guest))
109 {
110 if (guest->get_pid(guest) == info->si_pid)
111 {
112 guest->sigchild(guest);
113 break;
114 }
115 }
116 iterator->destroy(iterator);
117 break;
118 }
119 default:
120 break;
121 }
122 }
123
124 /**
125 * Implementation of dumm_t.destroy
126 */
127 static void destroy(private_dumm_t *this)
128 {
129 iterator_t *iterator;
130 guest_t *guest;
131
132 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
133
134 iterator = this->guests->create_iterator(this->guests, TRUE);
135 while (iterator->iterate(iterator, (void**)&guest))
136 {
137 guest->stop(guest);
138 }
139 iterator->destroy(iterator);
140
141 this->destroying = TRUE;
142 this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
143 free(this->dir);
144 free(this);
145 }
146
147 /**
148 * load all guests in our working dir
149 */
150 static void load_guests(private_dumm_t *this)
151 {
152 DIR *dir;
153 struct dirent *ent;
154 guest_t *guest;
155
156 dir = opendir(this->dir);
157 if (dir == NULL)
158 {
159 return;
160 }
161
162 while ((ent = readdir(dir)))
163 {
164 if (streq(ent->d_name, ".") || streq(ent->d_name, ".."))
165 {
166 continue;
167 }
168 guest = guest_load(this->dir, ent->d_name);
169 if (guest)
170 {
171 this->guests->insert_last(this->guests, guest);
172 }
173 else
174 {
175 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
176 }
177 }
178 closedir(dir);
179 }
180
181 /**
182 * create a dumm instance
183 */
184 dumm_t *dumm_create(char *dir)
185 {
186 char cwd[PATH_MAX];
187 private_dumm_t *this = malloc_thing(private_dumm_t);
188
189 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest;
190 this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator;
191 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
192 this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator;
193 this->public.sigchild_handler = (void(*)(dumm_t*, siginfo_t *info))sigchild_handler;
194 this->public.destroy = (void(*)(dumm_t*))destroy;
195
196 this->destroying = FALSE;
197 if (*dir == '/' || getcwd(cwd, sizeof(cwd)) == 0)
198 {
199 this->dir = strdup(dir);
200 }
201 else
202 {
203 asprintf(&this->dir, "%s/%s", cwd, dir);
204 }
205 this->guests = linked_list_create();
206 this->bridges = linked_list_create();
207
208 load_guests(this);
209 return &this->public;
210 }
211