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