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