Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_attribute.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2014-2016 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2014 Martin Willi
! 6: * Copyright (C) 2014 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 "vici_attribute.h"
! 20: #include "vici_builder.h"
! 21:
! 22: #include <daemon.h>
! 23: #include <collections/hashtable.h>
! 24: #include <collections/array.h>
! 25: #include <threading/rwlock.h>
! 26: #include <attributes/mem_pool.h>
! 27:
! 28: typedef struct private_vici_attribute_t private_vici_attribute_t;
! 29:
! 30: /**
! 31: * private data of vici_attribute
! 32: */
! 33: struct private_vici_attribute_t {
! 34:
! 35: /**
! 36: * public functions
! 37: */
! 38: vici_attribute_t public;
! 39:
! 40: /**
! 41: * vici connection dispatcher
! 42: */
! 43: vici_dispatcher_t *dispatcher;
! 44:
! 45: /**
! 46: * Configured pools, as char* => pool_t
! 47: */
! 48: hashtable_t *pools;
! 49:
! 50: /**
! 51: * rwlock to lock access to pools
! 52: */
! 53: rwlock_t *lock;
! 54: };
! 55:
! 56: /**
! 57: * Single configuration attribute with type
! 58: */
! 59: typedef struct {
! 60: /** type of attribute */
! 61: configuration_attribute_type_t type;
! 62: /** attribute value */
! 63: chunk_t value;
! 64: } attribute_t;
! 65:
! 66: /**
! 67: * Clean up an attribute
! 68: */
! 69: static void attribute_destroy(attribute_t *attr)
! 70: {
! 71: free(attr->value.ptr);
! 72: free(attr);
! 73: }
! 74:
! 75: /**
! 76: * Pool instances with associated attributes
! 77: */
! 78: typedef struct {
! 79: /** in-memory virtual IP pool */
! 80: mem_pool_t *vips;
! 81: /** configuration attributes, as attribute_t */
! 82: array_t *attrs;
! 83: } pool_t;
! 84:
! 85: /**
! 86: * Clean up a pool instance
! 87: */
! 88: static void pool_destroy(pool_t *pool)
! 89: {
! 90: DESTROY_IF(pool->vips);
! 91: array_destroy_function(pool->attrs, (void*)attribute_destroy, NULL);
! 92: free(pool);
! 93: }
! 94:
! 95: /**
! 96: * Find an existing or not yet existing lease
! 97: */
! 98: static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
! 99: identification_t *id, host_t *requested,
! 100: mem_pool_op_t op, host_t *peer)
! 101: {
! 102: enumerator_t *enumerator;
! 103: host_t *addr = NULL;
! 104: pool_t *pool;
! 105: char *name;
! 106:
! 107: enumerator = pools->create_enumerator(pools);
! 108: while (enumerator->enumerate(enumerator, &name))
! 109: {
! 110: pool = this->pools->get(this->pools, name);
! 111: if (pool)
! 112: {
! 113: addr = pool->vips->acquire_address(pool->vips, id, requested,
! 114: op, peer);
! 115: if (addr)
! 116: {
! 117: break;
! 118: }
! 119: }
! 120: }
! 121: enumerator->destroy(enumerator);
! 122:
! 123: return addr;
! 124: }
! 125:
! 126: METHOD(attribute_provider_t, acquire_address, host_t*,
! 127: private_vici_attribute_t *this, linked_list_t *pools, ike_sa_t *ike_sa,
! 128: host_t *requested)
! 129: {
! 130: identification_t *id;
! 131: host_t *addr, *peer;
! 132:
! 133: id = ike_sa->get_other_eap_id(ike_sa);
! 134: peer = ike_sa->get_other_host(ike_sa);
! 135:
! 136: this->lock->read_lock(this->lock);
! 137:
! 138: addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
! 139: if (!addr)
! 140: {
! 141: addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
! 142: if (!addr)
! 143: {
! 144: addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
! 145: }
! 146: }
! 147:
! 148: this->lock->unlock(this->lock);
! 149:
! 150: return addr;
! 151: }
! 152:
! 153: METHOD(attribute_provider_t, release_address, bool,
! 154: private_vici_attribute_t *this, linked_list_t *pools, host_t *address,
! 155: ike_sa_t *ike_sa)
! 156: {
! 157: enumerator_t *enumerator;
! 158: identification_t *id;
! 159: bool found = FALSE;
! 160: pool_t *pool;
! 161: char *name;
! 162:
! 163: id = ike_sa->get_other_eap_id(ike_sa);
! 164:
! 165: this->lock->read_lock(this->lock);
! 166:
! 167: enumerator = pools->create_enumerator(pools);
! 168: while (enumerator->enumerate(enumerator, &name))
! 169: {
! 170: pool = this->pools->get(this->pools, name);
! 171: if (pool)
! 172: {
! 173: found = pool->vips->release_address(pool->vips, address, id);
! 174: if (found)
! 175: {
! 176: break;
! 177: }
! 178: }
! 179: }
! 180: enumerator->destroy(enumerator);
! 181:
! 182: this->lock->unlock(this->lock);
! 183:
! 184: return found;
! 185: }
! 186:
! 187: CALLBACK(attr_filter, bool,
! 188: void *data, enumerator_t *orig, va_list args)
! 189: {
! 190: attribute_t *attr;
! 191: configuration_attribute_type_t *type;
! 192: chunk_t *value;
! 193:
! 194: VA_ARGS_VGET(args, type, value);
! 195:
! 196: if (orig->enumerate(orig, &attr))
! 197: {
! 198: *type = attr->type;
! 199: *value = attr->value;
! 200: return TRUE;
! 201: }
! 202: return FALSE;
! 203: }
! 204:
! 205: /**
! 206: * Create nested inner enumerator over pool attributes
! 207: */
! 208: CALLBACK(create_nested, enumerator_t*,
! 209: pool_t *pool, void *this)
! 210: {
! 211: return enumerator_create_filter(array_create_enumerator(pool->attrs),
! 212: attr_filter, NULL, NULL);
! 213: }
! 214:
! 215: /**
! 216: * Data associated to nested enumerator cleanup
! 217: */
! 218: typedef struct {
! 219: private_vici_attribute_t *this;
! 220: linked_list_t *list;
! 221: } nested_data_t;
! 222:
! 223: /**
! 224: * Clean up nested enumerator data
! 225: */
! 226: CALLBACK(nested_cleanup, void,
! 227: nested_data_t *data)
! 228: {
! 229: data->this->lock->unlock(data->this->lock);
! 230: data->list->destroy(data->list);
! 231: free(data);
! 232: }
! 233:
! 234: /**
! 235: * Check if any of vips is from pool
! 236: */
! 237: static bool have_vips_from_pool(mem_pool_t *pool, linked_list_t *vips)
! 238: {
! 239: enumerator_t *enumerator;
! 240: host_t *host;
! 241: chunk_t start, end, current;
! 242: uint32_t size;
! 243: bool found = FALSE;
! 244:
! 245: host = pool->get_base(pool);
! 246: start = host->get_address(host);
! 247:
! 248: if (start.len >= sizeof(size))
! 249: {
! 250: end = chunk_clone(start);
! 251:
! 252: /* mem_pool is currently limited to 2^31 addresses, so 32-bit
! 253: * calculations should be sufficient. */
! 254: size = untoh32(start.ptr + start.len - sizeof(size));
! 255: htoun32(end.ptr + end.len - sizeof(size), size + pool->get_size(pool));
! 256:
! 257: enumerator = vips->create_enumerator(vips);
! 258: while (enumerator->enumerate(enumerator, &host))
! 259: {
! 260: current = host->get_address(host);
! 261: if (chunk_compare(current, start) >= 0 &&
! 262: chunk_compare(current, end) < 0)
! 263: {
! 264: found = TRUE;
! 265: break;
! 266: }
! 267: }
! 268: enumerator->destroy(enumerator);
! 269:
! 270: free(end.ptr);
! 271: }
! 272: return found;
! 273: }
! 274:
! 275: METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
! 276: private_vici_attribute_t *this, linked_list_t *pools,
! 277: ike_sa_t *ike_sa, linked_list_t *vips)
! 278: {
! 279: enumerator_t *enumerator;
! 280: nested_data_t *data;
! 281: pool_t *pool;
! 282: char *name;
! 283:
! 284: INIT(data,
! 285: .this = this,
! 286: .list = linked_list_create(),
! 287: );
! 288:
! 289: this->lock->read_lock(this->lock);
! 290:
! 291: enumerator = pools->create_enumerator(pools);
! 292: while (enumerator->enumerate(enumerator, &name))
! 293: {
! 294: pool = this->pools->get(this->pools, name);
! 295: if (pool && have_vips_from_pool(pool->vips, vips))
! 296: {
! 297: data->list->insert_last(data->list, pool);
! 298: }
! 299: }
! 300: enumerator->destroy(enumerator);
! 301:
! 302: return enumerator_create_nested(data->list->create_enumerator(data->list),
! 303: create_nested, data, nested_cleanup);
! 304: }
! 305:
! 306: /**
! 307: * Merge a pool configuration with existing ones
! 308: */
! 309: static bool merge_pool(private_vici_attribute_t *this, pool_t *new)
! 310: {
! 311: mem_pool_t *tmp;
! 312: host_t *base;
! 313: pool_t *old;
! 314: const char *name;
! 315: u_int size;
! 316:
! 317: name = new->vips->get_name(new->vips);
! 318: base = new->vips->get_base(new->vips);
! 319: size = new->vips->get_size(new->vips);
! 320:
! 321: old = this->pools->remove(this->pools, name);
! 322: if (!old)
! 323: {
! 324: this->pools->put(this->pools, name, new);
! 325: DBG1(DBG_CFG, "added vici pool %s: %H, %u entries", name, base, size);
! 326: return TRUE;
! 327: }
! 328:
! 329: if (base->ip_equals(base, old->vips->get_base(old->vips)) &&
! 330: size == old->vips->get_size(old->vips))
! 331: {
! 332: /* no changes in pool, so keep existing, but use new attributes */
! 333: DBG1(DBG_CFG, "updated vici pool %s: %H, %u entries", name, base, size);
! 334: tmp = new->vips;
! 335: new->vips = old->vips;
! 336: old->vips = tmp;
! 337: this->pools->put(this->pools, new->vips->get_name(new->vips), new);
! 338: pool_destroy(old);
! 339: return TRUE;
! 340: }
! 341: if (old->vips->get_online(old->vips) == 0)
! 342: {
! 343: /* can replace old pool, no online leases */
! 344: DBG1(DBG_CFG, "replaced vici pool %s: %H, %u entries", name, base, size);
! 345: this->pools->put(this->pools, name, new);
! 346: pool_destroy(old);
! 347: return TRUE;
! 348: }
! 349: /* have online leases, unable to replace, TODO: migrate leases? */
! 350: DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to replace",
! 351: name, old->vips->get_online(old->vips));
! 352: this->pools->put(this->pools, old->vips->get_name(old->vips), old);
! 353: return FALSE;
! 354: }
! 355:
! 356: /**
! 357: * Create a (error) reply message
! 358: */
! 359: static vici_message_t* create_reply(char *fmt, ...)
! 360: {
! 361: vici_builder_t *builder;
! 362: va_list args;
! 363:
! 364: builder = vici_builder_create();
! 365: builder->add_kv(builder, "success", fmt ? "no" : "yes");
! 366: if (fmt)
! 367: {
! 368: va_start(args, fmt);
! 369: builder->vadd_kv(builder, "errmsg", fmt, args);
! 370: va_end(args);
! 371: }
! 372: return builder->finalize(builder);
! 373: }
! 374:
! 375: /**
! 376: * Parse a range definition of an address pool
! 377: */
! 378: static mem_pool_t *create_pool_range(char *name, char *buf)
! 379: {
! 380: mem_pool_t *pool;
! 381: host_t *from, *to;
! 382:
! 383: if (!host_create_from_range(buf, &from, &to))
! 384: {
! 385: return NULL;
! 386: }
! 387: pool = mem_pool_create_range(name, from, to);
! 388: from->destroy(from);
! 389: to->destroy(to);
! 390: return pool;
! 391: }
! 392:
! 393: /**
! 394: * Parse callback data, passed to each callback
! 395: */
! 396: typedef struct {
! 397: private_vici_attribute_t *this;
! 398: vici_message_t *reply;
! 399: } request_data_t;
! 400:
! 401: /**
! 402: * Data associated to a pool load
! 403: */
! 404: typedef struct {
! 405: request_data_t *request;
! 406: char *name;
! 407: pool_t *pool;
! 408: } load_data_t;
! 409:
! 410: CALLBACK(pool_li, bool,
! 411: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
! 412: {
! 413: struct {
! 414: char *name;
! 415: configuration_attribute_type_t v4;
! 416: configuration_attribute_type_t v6;
! 417: } keys[] = {
! 418: {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS },
! 419: {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS },
! 420: {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS },
! 421: {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP },
! 422: {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK },
! 423: {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER },
! 424: {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET },
! 425: {"split_include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE },
! 426: {"split_exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN },
! 427: };
! 428: char buf[256];
! 429: int i, index = -1, mask = -1, type = 0;
! 430: chunk_t encoding;
! 431: attribute_t *attr;
! 432: host_t *host = NULL;
! 433:
! 434: for (i = 0; i < countof(keys); i++)
! 435: {
! 436: if (streq(name, keys[i].name))
! 437: {
! 438: index = i;
! 439: break;
! 440: }
! 441: }
! 442: if (index == -1)
! 443: {
! 444: type = atoi(name);
! 445: if (!type)
! 446: {
! 447: data->request->reply = create_reply("invalid attribute: %s", name);
! 448: return FALSE;
! 449: }
! 450: }
! 451:
! 452: if (vici_stringify(value, buf, sizeof(buf)))
! 453: {
! 454: if (strchr(buf, '/'))
! 455: {
! 456: host = host_create_from_subnet(buf, &mask);
! 457: }
! 458: else
! 459: {
! 460: host = host_create_from_string(buf, 0);
! 461: }
! 462: }
! 463: if (host)
! 464: {
! 465: if (index != -1)
! 466: {
! 467: switch (host->get_family(host))
! 468: {
! 469: case AF_INET:
! 470: type = keys[index].v4;
! 471: break;
! 472: case AF_INET6:
! 473: default:
! 474: type = keys[index].v6;
! 475: break;
! 476: }
! 477: }
! 478: if (mask == -1)
! 479: {
! 480: encoding = chunk_clone(host->get_address(host));
! 481: }
! 482: else
! 483: {
! 484: if (host->get_family(host) == AF_INET)
! 485: { /* IPv4 attributes contain a subnet mask */
! 486: uint32_t netmask = 0;
! 487:
! 488: if (mask)
! 489: { /* shifting uint32_t by 32 or more is undefined */
! 490: mask = 32 - mask;
! 491: netmask = htonl((0xFFFFFFFF >> mask) << mask);
! 492: }
! 493: encoding = chunk_cat("cc", host->get_address(host),
! 494: chunk_from_thing(netmask));
! 495: }
! 496: else
! 497: { /* IPv6 addresses the prefix only */
! 498: encoding = chunk_cat("cc", host->get_address(host),
! 499: chunk_from_chars(mask));
! 500: }
! 501: }
! 502: host->destroy(host);
! 503: }
! 504: else
! 505: {
! 506: if (index != -1)
! 507: {
! 508: data->request->reply = create_reply("invalid attribute value "
! 509: "for %s", name);
! 510: return FALSE;
! 511: }
! 512: /* use raw binary data for numbered attributes */
! 513: encoding = chunk_clone(value);
! 514: }
! 515: INIT(attr,
! 516: .type = type,
! 517: .value = encoding,
! 518: );
! 519: array_insert_create(&data->pool->attrs, ARRAY_TAIL, attr);
! 520: return TRUE;
! 521: }
! 522:
! 523: CALLBACK(pool_kv, bool,
! 524: load_data_t *data, vici_message_t *message, char *name, chunk_t value)
! 525: {
! 526: if (streq(name, "addrs"))
! 527: {
! 528: char buf[128];
! 529: mem_pool_t *pool;
! 530: host_t *base = NULL;
! 531: int bits;
! 532:
! 533: if (data->pool->vips)
! 534: {
! 535: data->request->reply = create_reply("multiple addrs defined");
! 536: return FALSE;
! 537: }
! 538: if (!vici_stringify(value, buf, sizeof(buf)))
! 539: {
! 540: data->request->reply = create_reply("invalid addrs value");
! 541: return FALSE;
! 542: }
! 543: pool = create_pool_range(data->name, buf);
! 544: if (!pool)
! 545: {
! 546: base = host_create_from_subnet(buf, &bits);
! 547: if (base)
! 548: {
! 549: pool = mem_pool_create(data->name, base, bits);
! 550: base->destroy(base);
! 551: }
! 552: }
! 553: if (!pool)
! 554: {
! 555: data->request->reply = create_reply("invalid addrs value: %s", buf);
! 556: return FALSE;
! 557: }
! 558: data->pool->vips = pool;
! 559: return TRUE;
! 560: }
! 561: data->request->reply = create_reply("invalid attribute: %s", name);
! 562: return FALSE;
! 563: }
! 564:
! 565: CALLBACK(pool_sn, bool,
! 566: request_data_t *request, vici_message_t *message,
! 567: vici_parse_context_t *ctx, char *name)
! 568: {
! 569: load_data_t data = {
! 570: .request = request,
! 571: .name = name,
! 572: };
! 573: bool merged;
! 574:
! 575: INIT(data.pool);
! 576:
! 577: if (!message->parse(message, ctx, NULL, pool_kv, pool_li, &data))
! 578: {
! 579: pool_destroy(data.pool);
! 580: return FALSE;
! 581: }
! 582:
! 583: if (!data.pool->vips)
! 584: {
! 585: request->reply = create_reply("missing addrs for pool '%s'", name);
! 586: pool_destroy(data.pool);
! 587: return FALSE;
! 588: }
! 589:
! 590: request->this->lock->write_lock(request->this->lock);
! 591: merged = merge_pool(request->this, data.pool);
! 592: request->this->lock->unlock(request->this->lock);
! 593:
! 594: if (!merged)
! 595: {
! 596: request->reply = create_reply("vici pool %s has online leases, "
! 597: "unable to replace", name);
! 598: pool_destroy(data.pool);
! 599: }
! 600: return merged;
! 601: }
! 602:
! 603: CALLBACK(load_pool, vici_message_t*,
! 604: private_vici_attribute_t *this, char *name, u_int id,
! 605: vici_message_t *message)
! 606: {
! 607: request_data_t request = {
! 608: .this = this,
! 609: };
! 610:
! 611: if (!message->parse(message, NULL, pool_sn, NULL, NULL, &request))
! 612: {
! 613: if (request.reply)
! 614: {
! 615: return request.reply;
! 616: }
! 617: return create_reply("parsing request failed");
! 618: }
! 619: return create_reply(NULL);
! 620: }
! 621:
! 622: CALLBACK(unload_pool, vici_message_t*,
! 623: private_vici_attribute_t *this, char *name, u_int id,
! 624: vici_message_t *message)
! 625: {
! 626: vici_message_t *reply;
! 627: u_int online;
! 628: pool_t *pool;
! 629:
! 630: name = message->get_str(message, NULL, "name");
! 631: if (!name)
! 632: {
! 633: return create_reply("missing pool name to unload");
! 634: }
! 635:
! 636: this->lock->write_lock(this->lock);
! 637:
! 638: pool = this->pools->remove(this->pools, name);
! 639: if (pool)
! 640: {
! 641: online = pool->vips->get_online(pool->vips);
! 642: if (online)
! 643: {
! 644: DBG1(DBG_CFG, "vici pool %s has %u online leases, unable to unload",
! 645: name, online);
! 646: reply = create_reply("%s has online leases, unable to unload", name);
! 647: this->pools->put(this->pools, pool->vips->get_name(pool->vips), pool);
! 648: }
! 649: else
! 650: {
! 651: DBG1(DBG_CFG, "unloaded vici pool %s", name);
! 652: reply = create_reply(NULL);
! 653: pool_destroy(pool);
! 654: }
! 655: }
! 656: else
! 657: {
! 658: reply = create_reply("%s not found", name);
! 659: }
! 660:
! 661: this->lock->unlock(this->lock);
! 662:
! 663: return reply;
! 664: }
! 665:
! 666: CALLBACK(get_pools, vici_message_t*,
! 667: private_vici_attribute_t *this, char *name, u_int id,
! 668: vici_message_t *message)
! 669: {
! 670: vici_builder_t *builder;
! 671: enumerator_t *enumerator, *leases;
! 672: mem_pool_t *vips;
! 673: pool_t *pool;
! 674: identification_t *uid;
! 675: host_t *lease;
! 676: bool list_leases, on;
! 677: char buf[32], *filter;
! 678: int i;
! 679:
! 680: list_leases = message->get_bool(message, FALSE, "leases");
! 681: filter = message->get_str(message, NULL, "name");
! 682:
! 683: builder = vici_builder_create();
! 684:
! 685: this->lock->read_lock(this->lock);
! 686: enumerator = this->pools->create_enumerator(this->pools);
! 687: while (enumerator->enumerate(enumerator, &name, &pool))
! 688: {
! 689: if (filter && !streq(name, filter))
! 690: {
! 691: continue;
! 692: }
! 693:
! 694: vips = pool->vips;
! 695:
! 696: builder->begin_section(builder, name);
! 697:
! 698: builder->add_kv(builder, "base", "%H", vips->get_base(vips));
! 699: builder->add_kv(builder, "size", "%u", vips->get_size(vips));
! 700: builder->add_kv(builder, "online", "%u", vips->get_online(vips));
! 701: builder->add_kv(builder, "offline", "%u", vips->get_offline(vips));
! 702:
! 703: if (list_leases)
! 704: {
! 705: i = 0;
! 706: builder->begin_section(builder, "leases");
! 707: leases = vips->create_lease_enumerator(vips);
! 708: while (leases->enumerate(leases, &uid, &lease, &on))
! 709: {
! 710: snprintf(buf, sizeof(buf), "%d", i++);
! 711: builder->begin_section(builder, buf);
! 712: builder->add_kv(builder, "address", "%H", lease);
! 713: builder->add_kv(builder, "identity", "%Y", uid);
! 714: builder->add_kv(builder, "status", on ? "online" : "offline");
! 715: builder->end_section(builder);
! 716: }
! 717: leases->destroy(leases);
! 718: builder->end_section(builder);
! 719: }
! 720: builder->end_section(builder);
! 721: }
! 722: enumerator->destroy(enumerator);
! 723: this->lock->unlock(this->lock);
! 724:
! 725: return builder->finalize(builder);
! 726: }
! 727:
! 728: static void manage_command(private_vici_attribute_t *this,
! 729: char *name, vici_command_cb_t cb, bool reg)
! 730: {
! 731: this->dispatcher->manage_command(this->dispatcher, name,
! 732: reg ? cb : NULL, this);
! 733: }
! 734:
! 735: /**
! 736: * (Un-)register dispatcher functions
! 737: */
! 738: static void manage_commands(private_vici_attribute_t *this, bool reg)
! 739: {
! 740: manage_command(this, "load-pool", load_pool, reg);
! 741: manage_command(this, "unload-pool", unload_pool, reg);
! 742: manage_command(this, "get-pools", get_pools, reg);
! 743: }
! 744:
! 745: METHOD(vici_attribute_t, destroy, void,
! 746: private_vici_attribute_t *this)
! 747: {
! 748: enumerator_t *enumerator;
! 749: pool_t *pool;
! 750:
! 751: manage_commands(this, FALSE);
! 752:
! 753: enumerator = this->pools->create_enumerator(this->pools);
! 754: while (enumerator->enumerate(enumerator, NULL, &pool))
! 755: {
! 756: pool_destroy(pool);
! 757: }
! 758: enumerator->destroy(enumerator);
! 759: this->pools->destroy(this->pools);
! 760: this->lock->destroy(this->lock);
! 761: free(this);
! 762: }
! 763:
! 764: /*
! 765: * see header file
! 766: */
! 767: vici_attribute_t *vici_attribute_create(vici_dispatcher_t *dispatcher)
! 768: {
! 769: private_vici_attribute_t *this;
! 770:
! 771: INIT(this,
! 772: .public = {
! 773: .provider = {
! 774: .acquire_address = _acquire_address,
! 775: .release_address = _release_address,
! 776: .create_attribute_enumerator = _create_attribute_enumerator,
! 777: },
! 778: .destroy = _destroy,
! 779: },
! 780: .dispatcher = dispatcher,
! 781: .pools = hashtable_create(hashtable_hash_str, hashtable_equals_str, 4),
! 782: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
! 783: );
! 784:
! 785: manage_commands(this, TRUE);
! 786:
! 787: return &this->public;
! 788: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>