8de243daa237245f45e6ea412c9f672dc28b42ed
[strongswan.git] / src / libstrongswan / networking / streams / stream_manager.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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 "stream_manager.h"
17
18 #include "stream_tcp.h"
19 #include "stream_service_tcp.h"
20 #ifndef WIN32
21 # include "stream_unix.h"
22 # include "stream_service_unix.h"
23 #endif
24
25 #include <threading/rwlock.h>
26
27 typedef struct private_stream_manager_t private_stream_manager_t;
28
29 /**
30 * Private data of an stream_manager_t object.
31 */
32 struct private_stream_manager_t {
33
34 /**
35 * Public stream_manager_t interface.
36 */
37 stream_manager_t public;
38
39 /**
40 * List of registered stream constructors, as stream_entry_t
41 */
42 linked_list_t *streams;
43
44 /**
45 * List of registered service constructors, as service_entry_t
46 */
47 linked_list_t *services;
48
49 /**
50 * Lock for all lists
51 */
52 rwlock_t *lock;
53 };
54
55 /**
56 * Registered stream backend
57 */
58 typedef struct {
59 /** URI prefix */
60 char *prefix;
61 /** constructor function */
62 stream_constructor_t create;
63 } stream_entry_t;
64
65 /**
66 * Registered service backend
67 */
68 typedef struct {
69 /** URI prefix */
70 char *prefix;
71 /** constructor function */
72 stream_service_constructor_t create;
73 } service_entry_t;
74
75 METHOD(stream_manager_t, connect_, stream_t*,
76 private_stream_manager_t *this, char *uri)
77 {
78 enumerator_t *enumerator;
79 stream_entry_t *entry;
80 stream_t *stream = NULL;
81
82 this->lock->read_lock(this->lock);
83 enumerator = this->streams->create_enumerator(this->streams);
84 while (enumerator->enumerate(enumerator, &entry))
85 {
86 if (strpfx(uri, entry->prefix))
87 {
88 stream = entry->create(uri);
89 if (stream)
90 {
91 break;
92 }
93 }
94 }
95 enumerator->destroy(enumerator);
96 this->lock->unlock(this->lock);
97
98 return stream;
99 }
100
101 METHOD(stream_manager_t, create_service, stream_service_t*,
102 private_stream_manager_t *this, char *uri, int backlog)
103 {
104 enumerator_t *enumerator;
105 service_entry_t *entry;
106 stream_service_t *service = NULL;
107
108 this->lock->read_lock(this->lock);
109 enumerator = this->services->create_enumerator(this->services);
110 while (enumerator->enumerate(enumerator, &entry))
111 {
112 if (strpfx(uri, entry->prefix))
113 {
114 service = entry->create(uri, backlog);
115 if (service)
116 {
117 break;
118 }
119 }
120 }
121 enumerator->destroy(enumerator);
122 this->lock->unlock(this->lock);
123
124 return service;
125 }
126
127 METHOD(stream_manager_t, add_stream, void,
128 private_stream_manager_t *this, char *prefix, stream_constructor_t create)
129 {
130 stream_entry_t *entry;
131
132 INIT(entry,
133 .prefix = strdup(prefix),
134 .create = create,
135 );
136
137 this->lock->write_lock(this->lock);
138 this->streams->insert_last(this->streams, entry);
139 this->lock->unlock(this->lock);
140 }
141
142 METHOD(stream_manager_t, remove_stream, void,
143 private_stream_manager_t *this, stream_constructor_t create)
144 {
145 enumerator_t *enumerator;
146 stream_entry_t *entry;
147
148 this->lock->write_lock(this->lock);
149 enumerator = this->streams->create_enumerator(this->streams);
150 while (enumerator->enumerate(enumerator, &entry))
151 {
152 if (entry->create == create)
153 {
154 this->streams->remove_at(this->streams, enumerator);
155 free(entry->prefix);
156 free(entry);
157 }
158 }
159 enumerator->destroy(enumerator);
160 this->lock->unlock(this->lock);
161 }
162
163 METHOD(stream_manager_t, add_service, void,
164 private_stream_manager_t *this, char *prefix,
165 stream_service_constructor_t create)
166 {
167 service_entry_t *entry;
168
169 INIT(entry,
170 .prefix = strdup(prefix),
171 .create = create,
172 );
173
174 this->lock->write_lock(this->lock);
175 this->services->insert_last(this->services, entry);
176 this->lock->unlock(this->lock);
177 }
178
179 METHOD(stream_manager_t, remove_service, void,
180 private_stream_manager_t *this, stream_service_constructor_t create)
181 {
182 enumerator_t *enumerator;
183 service_entry_t *entry;
184
185 this->lock->write_lock(this->lock);
186 enumerator = this->services->create_enumerator(this->services);
187 while (enumerator->enumerate(enumerator, &entry))
188 {
189 if (entry->create == create)
190 {
191 this->services->remove_at(this->services, enumerator);
192 free(entry->prefix);
193 free(entry);
194 }
195 }
196 enumerator->destroy(enumerator);
197 this->lock->unlock(this->lock);
198 }
199
200 METHOD(stream_manager_t, destroy, void,
201 private_stream_manager_t *this)
202 {
203 remove_stream(this, stream_create_tcp);
204 remove_service(this, stream_service_create_tcp);
205 #ifndef WIN32
206 remove_stream(this, stream_create_unix);
207 remove_service(this, stream_service_create_unix);
208 #endif
209
210 this->streams->destroy(this->streams);
211 this->services->destroy(this->services);
212 this->lock->destroy(this->lock);
213 free(this);
214 }
215
216 /**
217 * See header
218 */
219 stream_manager_t *stream_manager_create()
220 {
221 private_stream_manager_t *this;
222
223 INIT(this,
224 .public = {
225 .connect = _connect_,
226 .create_service = _create_service,
227 .add_stream = _add_stream,
228 .remove_stream = _remove_stream,
229 .add_service = _add_service,
230 .remove_service = _remove_service,
231 .destroy = _destroy,
232 },
233 .streams = linked_list_create(),
234 .services = linked_list_create(),
235 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
236 );
237
238 add_stream(this, "tcp://", stream_create_tcp);
239 add_service(this, "tcp://", stream_service_create_tcp);
240 #ifndef WIN32
241 add_stream(this, "unix://", stream_create_unix);
242 add_service(this, "unix://", stream_service_create_unix);
243 #endif
244
245 return &this->public;
246 }