implemented separate protocol and connection rwlocks
[strongswan.git] / src / libcharon / tnc / tnccs / tnccs_manager.c
1 /*
2 * Copyright (C) 2010 Andreas Steffen
3 * HSR 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 #include "tnccs_manager.h"
17
18 #include <debug.h>
19 #include <utils/linked_list.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_tnccs_manager_t private_tnccs_manager_t;
23 typedef struct tnccs_entry_t tnccs_entry_t;
24 typedef struct tnccs_connection_entry_t tnccs_connection_entry_t;
25
26 /**
27 * TNCCS constructor entry
28 */
29 struct tnccs_entry_t {
30
31 /**
32 * TNCCS protocol type
33 */
34 tnccs_type_t type;
35
36 /**
37 * constructor function to create instance
38 */
39 tnccs_constructor_t constructor;
40 };
41
42 /**
43 * TNCCS connection entry
44 */
45 struct tnccs_connection_entry_t {
46
47 /**
48 * TNCCS connection ID
49 */
50 TNC_ConnectionID id;
51
52 /**
53 * TNCCS instance
54 */
55 tnccs_t *tnccs;
56
57 /** TNCCS send message function
58 *
59 */
60 tnccs_send_message_t send_message;
61
62 /** TNCS provide recommendation function
63 *
64 */
65 tnccs_provide_recommendation_t provide_recommendation;
66 };
67
68 /**
69 * private data of tnccs_manager
70 */
71 struct private_tnccs_manager_t {
72
73 /**
74 * public functions
75 */
76 tnccs_manager_t public;
77
78 /**
79 * list of TNCCS protocol entries
80 */
81 linked_list_t *protocols;
82
83 /**
84 * rwlock to lock the TNCCS protocol entries
85 */
86 rwlock_t *protocol_lock;
87
88 /**
89 * connection ID counter
90 */
91 TNC_ConnectionID connection_id;
92
93 /**
94 * list of TNCCS connection entries
95 */
96 linked_list_t *connections;
97
98 /**
99 * rwlock to lock TNCCS connection entries
100 */
101 rwlock_t *connection_lock;
102
103 };
104
105 METHOD(tnccs_manager_t, add_method, void,
106 private_tnccs_manager_t *this, tnccs_type_t type,
107 tnccs_constructor_t constructor)
108 {
109 tnccs_entry_t *entry;
110
111 entry = malloc_thing(tnccs_entry_t);
112 entry->type = type;
113 entry->constructor = constructor;
114
115 this->protocol_lock->write_lock(this->protocol_lock);
116 this->protocols->insert_last(this->protocols, entry);
117 this->protocol_lock->unlock(this->protocol_lock);
118 }
119
120 METHOD(tnccs_manager_t, remove_method, void,
121 private_tnccs_manager_t *this, tnccs_constructor_t constructor)
122 {
123 enumerator_t *enumerator;
124 tnccs_entry_t *entry;
125
126 this->protocol_lock->write_lock(this->protocol_lock);
127 enumerator = this->protocols->create_enumerator(this->protocols);
128 while (enumerator->enumerate(enumerator, &entry))
129 {
130 if (constructor == entry->constructor)
131 {
132 this->protocols->remove_at(this->protocols, enumerator);
133 free(entry);
134 }
135 }
136 enumerator->destroy(enumerator);
137 this->protocol_lock->unlock(this->protocol_lock);
138 }
139
140 METHOD(tnccs_manager_t, create_instance, tnccs_t*,
141 private_tnccs_manager_t *this, tnccs_type_t type, bool is_server)
142 {
143 enumerator_t *enumerator;
144 tnccs_entry_t *entry;
145 tnccs_t *protocol = NULL;
146
147 this->protocol_lock->read_lock(this->protocol_lock);
148 enumerator = this->protocols->create_enumerator(this->protocols);
149 while (enumerator->enumerate(enumerator, &entry))
150 {
151 if (type == entry->type)
152 {
153 protocol = entry->constructor(is_server);
154 if (protocol)
155 {
156 break;
157 }
158 }
159 }
160 enumerator->destroy(enumerator);
161 this->protocol_lock->unlock(this->protocol_lock);
162
163 return protocol;
164 }
165
166 METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
167 private_tnccs_manager_t *this, tnccs_t *tnccs,
168 tnccs_send_message_t send_message,
169 tnccs_provide_recommendation_t provide_recommendation)
170 {
171 tnccs_connection_entry_t *entry;
172
173 entry = malloc_thing(tnccs_connection_entry_t);
174 entry->tnccs = tnccs;
175 entry->send_message = send_message;
176 entry->provide_recommendation = provide_recommendation;
177
178 this->connection_lock->write_lock(this->connection_lock);
179 entry->id = ++this->connection_id;
180 this->connections->insert_last(this->connections, entry);
181 this->connection_lock->unlock(this->connection_lock);
182
183 DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
184 return entry->id;
185 }
186
187 METHOD(tnccs_manager_t, remove_connection, void,
188 private_tnccs_manager_t *this, TNC_ConnectionID id)
189 {
190 enumerator_t *enumerator;
191 tnccs_connection_entry_t *entry;
192
193 this->connection_lock->write_lock(this->connection_lock);
194 enumerator = this->connections->create_enumerator(this->connections);
195 while (enumerator->enumerate(enumerator, &entry))
196 {
197 if (id == entry->id)
198 {
199 this->connections->remove_at(this->connections, enumerator);
200 free(entry);
201 DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
202 }
203 }
204 enumerator->destroy(enumerator);
205 this->connection_lock->unlock(this->connection_lock);
206 }
207
208 METHOD(tnccs_manager_t, send_message, TNC_Result,
209 private_tnccs_manager_t *this, TNC_ConnectionID id,
210 TNC_BufferReference message,
211 TNC_UInt32 message_len,
212 TNC_MessageType message_type)
213 {
214 enumerator_t *enumerator;
215 tnccs_connection_entry_t *entry;
216 tnccs_send_message_t send_message = NULL;
217 tnccs_t *tnccs = NULL;
218
219 this->connection_lock->read_lock(this->connection_lock);
220 enumerator = this->connections->create_enumerator(this->connections);
221 while (enumerator->enumerate(enumerator, &entry))
222 {
223 if (id == entry->id)
224 {
225 tnccs = entry->tnccs;
226 send_message = entry->send_message;
227 break;
228 }
229 }
230 enumerator->destroy(enumerator);
231 this->connection_lock->unlock(this->connection_lock);
232
233 if (tnccs && send_message)
234 {
235 send_message(tnccs, message, message_len, message_type);
236 return TNC_RESULT_SUCCESS;
237 }
238 return TNC_RESULT_FATAL;
239 }
240
241 METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
242 private_tnccs_manager_t *this, TNC_IMVID imv_id,
243 TNC_ConnectionID id,
244 TNC_IMV_Action_Recommendation recommendation,
245 TNC_IMV_Evaluation_Result evaluation)
246 {
247 enumerator_t *enumerator;
248 tnccs_connection_entry_t *entry;
249 tnccs_provide_recommendation_t provide_recommendation = NULL;
250 tnccs_t *tnccs = NULL;
251
252 this->connection_lock->read_lock(this->connection_lock);
253 enumerator = this->connections->create_enumerator(this->connections);
254 while (enumerator->enumerate(enumerator, &entry))
255 {
256 if (id == entry->id)
257 {
258 tnccs = entry->tnccs;
259 provide_recommendation = entry->provide_recommendation;
260 break;
261 }
262 }
263 enumerator->destroy(enumerator);
264 this->connection_lock->unlock(this->connection_lock);
265
266 if (tnccs && provide_recommendation)
267 {
268 provide_recommendation(tnccs, imv_id, recommendation, evaluation);
269 return TNC_RESULT_SUCCESS;
270 }
271 return TNC_RESULT_FATAL;
272 }
273
274 METHOD(tnccs_manager_t, destroy, void,
275 private_tnccs_manager_t *this)
276 {
277 this->protocols->destroy_function(this->protocols, free);
278 this->protocol_lock->destroy(this->protocol_lock);
279 this->connections->destroy_function(this->connections, free);
280 this->connection_lock->destroy(this->connection_lock);
281 free(this);
282 }
283
284 /*
285 * See header
286 */
287 tnccs_manager_t *tnccs_manager_create()
288 {
289 private_tnccs_manager_t *this;
290
291 INIT(this,
292 .public = {
293 .add_method = _add_method,
294 .remove_method = _remove_method,
295 .create_instance = _create_instance,
296 .create_connection = _create_connection,
297 .remove_connection = _remove_connection,
298 .send_message = _send_message,
299 .provide_recommendation = _provide_recommendation,
300 .destroy = _destroy,
301 },
302 .protocols = linked_list_create(),
303 .connections = linked_list_create(),
304 .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
305 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
306 );
307
308 return &this->public;
309 }
310