Annotation of embedaddon/strongswan/src/libcharon/plugins/load_tester/load_tester_control.c, revision 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>