Annotation of embedaddon/strongswan/src/libcharon/plugins/load_tester/load_tester_control.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Martin Willi
3: * Copyright (C) 2012 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 "load_tester_control.h"
17:
18: #include <sys/types.h>
19: #include <sys/stat.h>
20: #include <sys/socket.h>
21: #include <sys/un.h>
22: #include <unistd.h>
23: #include <errno.h>
24:
25: #include <daemon.h>
26: #include <collections/hashtable.h>
27: #include <threading/thread.h>
28: #include <threading/mutex.h>
29: #include <threading/condvar.h>
30: #include <processing/jobs/callback_job.h>
31:
32: typedef struct private_load_tester_control_t private_load_tester_control_t;
33: typedef struct init_listener_t init_listener_t;
34:
35: /**
36: * Private data of an load_tester_control_t object.
37: */
38: struct private_load_tester_control_t {
39:
40: /**
41: * Public load_tester_control_t interface.
42: */
43: load_tester_control_t public;
44:
45: /**
46: * Load tester control stream service
47: */
48: stream_service_t *service;
49: };
50:
51: /**
52: * Listener to follow initiation progress
53: */
54: struct init_listener_t {
55:
56: /**
57: * implements listener_t
58: */
59: listener_t listener;
60:
61: /**
62: * Output stream to log to
63: */
64: FILE *stream;
65:
66: /**
67: * IKE_SAs we have started to initiate
68: */
69: hashtable_t *initiated;
70:
71: /**
72: * IKE_SAs we have completed to initiate (success or failure)
73: */
74: hashtable_t *completed;
75:
76: /**
77: * Mutex to lock IKE_SA tables
78: */
79: mutex_t *mutex;
80:
81: /**
82: * Condvar to wait for completion
83: */
84: condvar_t *condvar;
85: };
86:
87: /**
88: * Hashtable hash function
89: */
90: static u_int hash(uintptr_t id)
91: {
92: return id;
93: }
94:
95: /**
96: * Hashtable hash function
97: */
98: static bool equals(uintptr_t a, uintptr_t b)
99: {
100: return a == b;
101: }
102:
103: METHOD(listener_t, alert, bool,
104: init_listener_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
105: {
106: if (alert == ALERT_RETRANSMIT_SEND)
107: {
108: uintptr_t id;
109: bool match = FALSE;
110:
111: id = ike_sa->get_unique_id(ike_sa);
112: this->mutex->lock(this->mutex);
113: if (this->initiated->get(this->initiated, (void*)id))
114: {
115: match = TRUE;
116: }
117: this->mutex->unlock(this->mutex);
118:
119: if (match)
120: {
121: fprintf(this->stream, "*");
122: fflush(this->stream);
123: }
124: }
125: return TRUE;
126: }
127:
128: METHOD(listener_t, ike_state_change, bool,
129: init_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
130: {
131: if (state == IKE_ESTABLISHED || state == IKE_DESTROYING)
132: {
133: uintptr_t id;
134: bool match = FALSE;
135:
136: id = ike_sa->get_unique_id(ike_sa);
137: this->mutex->lock(this->mutex);
138: if (this->initiated->get(this->initiated, (void*)id))
139: {
140: match = !this->completed->put(this->completed, (void*)id, (void*)id);
141: }
142: this->mutex->unlock(this->mutex);
143:
144: if (match)
145: {
146: this->condvar->signal(this->condvar);
147: fprintf(this->stream, state == IKE_ESTABLISHED ? "+" : "-");
148: fflush(this->stream);
149: }
150: }
151: return TRUE;
152: }
153:
154: /**
155: * Logging callback function used during initiate
156: */
157: static bool initiate_cb(init_listener_t *this, debug_t group, level_t level,
158: ike_sa_t *ike_sa, const char *message)
159: {
160: uintptr_t id;
161:
162: if (ike_sa)
163: {
164: id = ike_sa->get_unique_id(ike_sa);
165: this->mutex->lock(this->mutex);
166: this->initiated->put(this->initiated, (void*)id, (void*)id);
167: this->mutex->unlock(this->mutex);
168:
169: return FALSE;
170: }
171:
172: return TRUE;
173: }
174:
175: /**
176: * Accept connections, initiate load-test, write progress to stream
177: */
178: static bool on_accept(private_load_tester_control_t *this, stream_t *io)
179: {
180: init_listener_t *listener;
181: enumerator_t *enumerator;
182: peer_cfg_t *peer_cfg;
183: child_cfg_t *child_cfg;
184: u_int i, count, failed = 0, delay = 0;
185: char buf[16] = "";
186: FILE *stream;
187:
188: stream = io->get_file(io);
189: if (!stream)
190: {
191: return FALSE;
192: }
193: fflush(stream);
194: if (fgets(buf, sizeof(buf), stream) == NULL)
195: {
196: fclose(stream);
197: return FALSE;
198: }
199: if (sscanf(buf, "%u %u", &count, &delay) < 1)
200: {
201: fclose(stream);
202: return FALSE;
203: }
204:
205: INIT(listener,
206: .listener = {
207: .ike_state_change = _ike_state_change,
208: .alert = _alert,
209: },
210: .stream = stream,
211: .initiated = hashtable_create((void*)hash, (void*)equals, count),
212: .completed = hashtable_create((void*)hash, (void*)equals, count),
213: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
214: .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
215: );
216:
217: charon->bus->add_listener(charon->bus, &listener->listener);
218:
219: for (i = 0; i < count; i++)
220: {
221: peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
222: "load-test");
223: if (!peer_cfg)
224: {
225: failed++;
226: fprintf(stream, "!");
227: continue;
228: }
229: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
230: if (!enumerator->enumerate(enumerator, &child_cfg))
231: {
232: enumerator->destroy(enumerator);
233: peer_cfg->destroy(peer_cfg);
234: failed++;
235: fprintf(stream, "!");
236: continue;
237: }
238: enumerator->destroy(enumerator);
239:
240: switch (charon->controller->initiate(charon->controller,
241: peer_cfg, child_cfg->get_ref(child_cfg),
242: (void*)initiate_cb, listener, 0, FALSE))
243: {
244: case NEED_MORE:
245: /* Callback returns FALSE once it got track of this IKE_SA.
246: * FALL */
247: case SUCCESS:
248: fprintf(stream, ".");
249: break;
250: default:
251: fprintf(stream, "!");
252: break;
253: }
254: if (delay)
255: {
256: usleep(delay * 1000);
257: }
258: fflush(stream);
259: }
260:
261: listener->mutex->lock(listener->mutex);
262: while (listener->completed->get_count(listener->completed) < count - failed)
263: {
264: listener->condvar->wait(listener->condvar, listener->mutex);
265: }
266: listener->mutex->unlock(listener->mutex);
267:
268: charon->bus->remove_listener(charon->bus, &listener->listener);
269:
270: listener->initiated->destroy(listener->initiated);
271: listener->completed->destroy(listener->completed);
272: listener->mutex->destroy(listener->mutex);
273: listener->condvar->destroy(listener->condvar);
274: free(listener);
275:
276: fprintf(stream, "\n");
277: fclose(stream);
278:
279: return FALSE;
280: }
281:
282: METHOD(load_tester_control_t, destroy, void,
283: private_load_tester_control_t *this)
284: {
285: DESTROY_IF(this->service);
286: free(this);
287: }
288:
289: /**
290: * See header
291: */
292: load_tester_control_t *load_tester_control_create()
293: {
294: private_load_tester_control_t *this;
295: char *uri;
296:
297: INIT(this,
298: .public = {
299: .destroy = _destroy,
300: },
301: );
302:
303: uri = lib->settings->get_str(lib->settings,
304: "%s.plugins.load-tester.socket", "unix://" LOAD_TESTER_SOCKET,
305: lib->ns);
306: this->service = lib->streams->create_service(lib->streams, uri, 10);
307: if (this->service)
308: {
309: this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
310: this, JOB_PRIO_CRITICAL, 0);
311: }
312: else
313: {
314: DBG1(DBG_CFG, "creating load-tester control socket failed");
315: }
316: return &this->public;
317: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>