Annotation of embedaddon/strongswan/src/libcharon/plugins/counters/counters_listener.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2017 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2012 Martin Willi
! 6: * Copyright (C) 2012 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include "counters_listener.h"
! 20: #include "counters_query.h"
! 21:
! 22: #include <threading/spinlock.h>
! 23: #include <collections/hashtable.h>
! 24: #include <collections/array.h>
! 25:
! 26: typedef struct private_counters_listener_t private_counters_listener_t;
! 27: typedef struct private_counters_query_t private_counters_query_t;
! 28:
! 29: /**
! 30: * Query interface
! 31: */
! 32: struct private_counters_query_t {
! 33:
! 34: /**
! 35: * Public interface
! 36: */
! 37: counters_query_t public;
! 38:
! 39: /**
! 40: * Reference to this
! 41: */
! 42: private_counters_listener_t *this;
! 43: };
! 44:
! 45: /**
! 46: * Private data
! 47: */
! 48: struct private_counters_listener_t {
! 49:
! 50: /**
! 51: * Public interface
! 52: */
! 53: counters_listener_t public;
! 54:
! 55: /**
! 56: * Query interface
! 57: */
! 58: private_counters_query_t query;
! 59:
! 60: /**
! 61: * Global counter values
! 62: */
! 63: uint64_t counters[COUNTER_MAX];
! 64:
! 65: /**
! 66: * Counters for specific connection names, char* => entry_t
! 67: */
! 68: hashtable_t *conns;
! 69:
! 70: /**
! 71: * Lock for counter values
! 72: */
! 73: spinlock_t *lock;
! 74: };
! 75:
! 76: /**
! 77: * Counters for a specific connection name
! 78: */
! 79: typedef struct {
! 80: /** connection name */
! 81: char *name;
! 82: /** counter values for connection */
! 83: uint64_t counters[COUNTER_MAX];
! 84: } entry_t;
! 85:
! 86: /**
! 87: * Destroy named entry
! 88: */
! 89: static void destroy_entry(entry_t *this)
! 90: {
! 91: free(this->name);
! 92: free(this);
! 93: }
! 94:
! 95: /**
! 96: * Hashtable hash function
! 97: */
! 98: static u_int hash(char *name)
! 99: {
! 100: return chunk_hash(chunk_from_str(name));
! 101: }
! 102:
! 103: /**
! 104: * Hashtable equals function
! 105: */
! 106: static bool equals(char *a, char *b)
! 107: {
! 108: return streq(a, b);
! 109: }
! 110:
! 111: /**
! 112: * Get the name of an IKE_SA, but return NULL if it is not known yet
! 113: */
! 114: static char *get_ike_sa_name(ike_sa_t *ike_sa)
! 115: {
! 116: peer_cfg_t *peer_cfg;
! 117:
! 118: if (ike_sa)
! 119: {
! 120: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 121: if (peer_cfg)
! 122: {
! 123: return peer_cfg->get_name(peer_cfg);
! 124: }
! 125: }
! 126: return NULL;
! 127: }
! 128:
! 129: /**
! 130: * Increase a counter for a named entry
! 131: */
! 132: static void count_named(private_counters_listener_t *this,
! 133: ike_sa_t *ike_sa, counter_type_t type)
! 134: {
! 135: entry_t *entry;
! 136: char *name;
! 137:
! 138: name = get_ike_sa_name(ike_sa);
! 139: if (name)
! 140: {
! 141: entry = this->conns->get(this->conns, name);
! 142: if (!entry)
! 143: {
! 144: INIT(entry,
! 145: .name = strdup(name),
! 146: );
! 147: this->conns->put(this->conns, entry->name, entry);
! 148: }
! 149: entry->counters[type]++;
! 150: }
! 151: }
! 152:
! 153: METHOD(listener_t, alert, bool,
! 154: private_counters_listener_t *this, ike_sa_t *ike_sa,
! 155: alert_t alert, va_list args)
! 156: {
! 157: counter_type_t type;
! 158:
! 159: switch (alert)
! 160: {
! 161: case ALERT_INVALID_IKE_SPI:
! 162: type = COUNTER_IN_INVALID_IKE_SPI;
! 163: break;
! 164: case ALERT_PARSE_ERROR_HEADER:
! 165: case ALERT_PARSE_ERROR_BODY:
! 166: type = COUNTER_IN_INVALID;
! 167: break;
! 168: default:
! 169: return TRUE;
! 170: }
! 171:
! 172: this->lock->lock(this->lock);
! 173: this->counters[type]++;
! 174: count_named(this, ike_sa, type);
! 175: this->lock->unlock(this->lock);
! 176:
! 177: return TRUE;
! 178: }
! 179:
! 180: METHOD(listener_t, ike_rekey, bool,
! 181: private_counters_listener_t *this, ike_sa_t *old, ike_sa_t *new)
! 182: {
! 183: counter_type_t type;
! 184: ike_sa_id_t *id;
! 185:
! 186: id = new->get_id(new);
! 187: if (id->is_initiator(id))
! 188: {
! 189: type = COUNTER_INIT_IKE_SA_REKEY;
! 190: }
! 191: else
! 192: {
! 193: type = COUNTER_RESP_IKE_SA_REKEY;
! 194: }
! 195:
! 196: this->lock->lock(this->lock);
! 197: this->counters[type]++;
! 198: count_named(this, old, type);
! 199: this->lock->unlock(this->lock);
! 200:
! 201: return TRUE;
! 202: }
! 203:
! 204: METHOD(listener_t, child_rekey, bool,
! 205: private_counters_listener_t *this, ike_sa_t *ike_sa,
! 206: child_sa_t *old, child_sa_t *new)
! 207: {
! 208: this->lock->lock(this->lock);
! 209: this->counters[COUNTER_CHILD_SA_REKEY]++;
! 210: count_named(this, ike_sa, COUNTER_CHILD_SA_REKEY);
! 211: this->lock->unlock(this->lock);
! 212:
! 213: return TRUE;
! 214: }
! 215:
! 216: METHOD(listener_t, message_hook, bool,
! 217: private_counters_listener_t *this, ike_sa_t *ike_sa, message_t *message,
! 218: bool incoming, bool plain)
! 219: {
! 220: counter_type_t type;
! 221: bool request;
! 222:
! 223: if ((incoming && !plain) || (!incoming && !plain))
! 224: { /* handle each message only once */
! 225: return TRUE;
! 226: }
! 227:
! 228: request = message->get_request(message);
! 229: switch (message->get_exchange_type(message))
! 230: {
! 231: case IKE_SA_INIT:
! 232: if (incoming)
! 233: {
! 234: type = request ? COUNTER_IN_IKE_SA_INIT_REQ
! 235: : COUNTER_IN_IKE_SA_INIT_RSP;
! 236: }
! 237: else
! 238: {
! 239: type = request ? COUNTER_OUT_IKE_SA_INIT_REQ
! 240: : COUNTER_OUT_IKE_SA_INIT_RES;
! 241: }
! 242: break;
! 243: case IKE_AUTH:
! 244: if (incoming)
! 245: {
! 246: type = request ? COUNTER_IN_IKE_AUTH_REQ
! 247: : COUNTER_IN_IKE_AUTH_RSP;
! 248: }
! 249: else
! 250: {
! 251: type = request ? COUNTER_OUT_IKE_AUTH_REQ
! 252: : COUNTER_OUT_IKE_AUTH_RSP;
! 253: }
! 254: break;
! 255: case CREATE_CHILD_SA:
! 256: if (incoming)
! 257: {
! 258: type = request ? COUNTER_IN_CREATE_CHILD_SA_REQ
! 259: : COUNTER_IN_CREATE_CHILD_SA_RSP;
! 260: }
! 261: else
! 262: {
! 263: type = request ? COUNTER_OUT_CREATE_CHILD_SA_REQ
! 264: : COUNTER_OUT_CREATE_CHILD_SA_RSP;
! 265: }
! 266: break;
! 267: case INFORMATIONAL:
! 268: if (incoming)
! 269: {
! 270: type = request ? COUNTER_IN_INFORMATIONAL_REQ
! 271: : COUNTER_IN_INFORMATIONAL_RSP;
! 272: }
! 273: else
! 274: {
! 275: type = request ? COUNTER_OUT_INFORMATIONAL_REQ
! 276: : COUNTER_OUT_INFORMATIONAL_RSP;
! 277: }
! 278: break;
! 279: default:
! 280: return TRUE;
! 281: }
! 282:
! 283: this->lock->lock(this->lock);
! 284: this->counters[type]++;
! 285: count_named(this, ike_sa, type);
! 286: this->lock->unlock(this->lock);
! 287:
! 288: return TRUE;
! 289: }
! 290:
! 291: CALLBACK(free_names, void,
! 292: array_t * names)
! 293: {
! 294: array_destroy_function(names, (void*)free, NULL);
! 295: }
! 296:
! 297: METHOD(counters_query_t, get_names, enumerator_t*,
! 298: private_counters_query_t *query)
! 299: {
! 300: private_counters_listener_t *this = query->this;
! 301: enumerator_t *enumerator;
! 302: array_t *names;
! 303: char *name;
! 304:
! 305: this->lock->lock(this->lock);
! 306: names = array_create(0, this->conns->get_count(this->conns));
! 307: enumerator = this->conns->create_enumerator(this->conns);
! 308: while (enumerator->enumerate(enumerator, &name, NULL))
! 309: {
! 310: array_insert(names, ARRAY_TAIL, strdup(name));
! 311: }
! 312: enumerator->destroy(enumerator);
! 313: this->lock->unlock(this->lock);
! 314:
! 315: array_sort(names, (void*)strcmp, NULL);
! 316:
! 317: return enumerator_create_cleaner(array_create_enumerator(names),
! 318: free_names, names);
! 319: }
! 320:
! 321: METHOD(counters_query_t, get, bool,
! 322: private_counters_query_t *query, counter_type_t type, char *name,
! 323: uint64_t *value)
! 324: {
! 325: private_counters_listener_t *this = query->this;
! 326: uint64_t *counters = this->counters;
! 327:
! 328: this->lock->lock(this->lock);
! 329: if (name)
! 330: {
! 331: entry_t *entry;
! 332:
! 333: entry = this->conns->get(this->conns, name);
! 334: if (!entry)
! 335: {
! 336: this->lock->unlock(this->lock);
! 337: return FALSE;
! 338: }
! 339: counters = entry->counters;
! 340: }
! 341: if (value)
! 342: {
! 343: *value = counters[type];
! 344: }
! 345: this->lock->unlock(this->lock);
! 346: return TRUE;
! 347: }
! 348:
! 349: METHOD(counters_query_t, get_all, uint64_t*,
! 350: private_counters_query_t *query, char *name)
! 351: {
! 352: private_counters_listener_t *this = query->this;
! 353: entry_t *entry;
! 354: uint64_t *result, *counters = this->counters;
! 355: counter_type_t i;
! 356:
! 357: result = calloc(COUNTER_MAX, sizeof(uint64_t));
! 358:
! 359: this->lock->lock(this->lock);
! 360: if (name)
! 361: {
! 362: entry = this->conns->get(this->conns, name);
! 363: if (!entry)
! 364: {
! 365: this->lock->unlock(this->lock);
! 366: free(result);
! 367: return NULL;
! 368: }
! 369: counters = &entry->counters[0];
! 370: }
! 371: for (i = 0; i < countof(this->counters); i++)
! 372: {
! 373: result[i] = counters[i];
! 374: }
! 375: this->lock->unlock(this->lock);
! 376: return result;
! 377: }
! 378:
! 379: METHOD(counters_query_t, reset, void,
! 380: private_counters_query_t *query, char *name)
! 381: {
! 382: private_counters_listener_t *this = query->this;
! 383: entry_t *entry = NULL;
! 384:
! 385: this->lock->lock(this->lock);
! 386: if (name)
! 387: {
! 388: entry = this->conns->remove(this->conns, name);
! 389: }
! 390: else
! 391: {
! 392: memset(&this->counters, 0, sizeof(this->counters));
! 393: }
! 394: this->lock->unlock(this->lock);
! 395:
! 396: if (entry)
! 397: {
! 398: destroy_entry(entry);
! 399: }
! 400: }
! 401:
! 402: METHOD(counters_query_t, reset_all, void,
! 403: private_counters_query_t *query)
! 404: {
! 405: private_counters_listener_t *this = query->this;
! 406: hashtable_t *new_conns, *conns;
! 407:
! 408: new_conns = hashtable_create((hashtable_hash_t)hash,
! 409: (hashtable_equals_t)equals, 4);
! 410:
! 411: this->lock->lock(this->lock);
! 412: conns = this->conns;
! 413: this->conns = new_conns;
! 414: this->lock->unlock(this->lock);
! 415:
! 416: conns->destroy_function(conns, (void*)destroy_entry);
! 417: }
! 418:
! 419: METHOD(counters_listener_t, destroy, void,
! 420: private_counters_listener_t *this)
! 421: {
! 422: lib->set(lib, "counters", NULL);
! 423:
! 424: this->conns->destroy_function(this->conns, (void*)destroy_entry);
! 425: this->lock->destroy(this->lock);
! 426: free(this);
! 427: }
! 428:
! 429: /*
! 430: * Described in header
! 431: */
! 432: counters_listener_t *counters_listener_create()
! 433: {
! 434: private_counters_listener_t *this;
! 435:
! 436: INIT(this,
! 437: .public = {
! 438: .listener = {
! 439: .alert = _alert,
! 440: .ike_rekey = _ike_rekey,
! 441: .child_rekey = _child_rekey,
! 442: .message = _message_hook,
! 443: },
! 444: .destroy = _destroy,
! 445: },
! 446: .query = {
! 447: .public = {
! 448: .get_names = _get_names,
! 449: .get = _get,
! 450: .get_all = _get_all,
! 451: .reset = _reset,
! 452: .reset_all = _reset_all,
! 453: },
! 454: },
! 455: .conns = hashtable_create((hashtable_hash_t)hash,
! 456: (hashtable_equals_t)equals, 4),
! 457: .lock = spinlock_create(),
! 458: );
! 459: this->query.this = this;
! 460:
! 461: lib->set(lib, "counters", &this->query);
! 462:
! 463: return &this->public;
! 464: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>