Asterisk - The Open Source Telephony Project  21.4.1
res_hep.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2014, Digium, Inc.
5  *
6  * Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
7  * Matt Jordan <mjordan@digium.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*!
21  * \file
22  * \brief Routines for integration with Homer using HEPv3
23  *
24  * \author Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
25  * \author Matt Jordan <mjordan@digium.com>
26  *
27  */
28 
29 /*!
30  * \li \ref res_hep.c uses the configuration file \ref hep.conf
31  * \addtogroup configuration_file Configuration Files
32  */
33 
34 /*!
35  * \page hep.conf hep.conf
36  * \verbinclude hep.conf.sample
37  */
38 
39 /*** MODULEINFO
40  <support_level>extended</support_level>
41  ***/
42 
43 /*** DOCUMENTATION
44  <configInfo name="res_hep" language="en_US">
45  <synopsis>Resource for integration with Homer using HEPv3</synopsis>
46  <configFile name="hep.conf">
47  <configObject name="general">
48  <synopsis>General settings.</synopsis>
49  <description><para>
50  The <emphasis>general</emphasis> settings section contains information
51  to configure Asterisk as a Homer capture agent.
52  </para>
53  </description>
54  <configOption name="enabled" default="yes">
55  <synopsis>Enable or disable packet capturing.</synopsis>
56  <description>
57  <enumlist>
58  <enum name="no" />
59  <enum name="yes" />
60  </enumlist>
61  </description>
62  </configOption>
63  <configOption name="uuid_type" default="call-id">
64  <synopsis>The preferred type of UUID to pass to Homer.</synopsis>
65  <description>
66  <enumlist>
67  <enum name="call-id"><para>Use the PJSIP Call-Id</para></enum>
68  <enum name="channel"><para>Use the Asterisk channel name</para></enum>
69  </enumlist>
70  </description>
71  </configOption>
72  <configOption name="capture_address">
73  <synopsis>The address and port of the Homer server to send packets to.</synopsis>
74  </configOption>
75  <configOption name="capture_password">
76  <synopsis>If set, the authentication password to send to Homer.</synopsis>
77  </configOption>
78  <configOption name="capture_id" default="0">
79  <synopsis>The ID for this capture agent.</synopsis>
80  </configOption>
81  <configOption name="capture_name" default="">
82  <synopsis>The name for this capture agent.</synopsis>
83  </configOption>
84  </configObject>
85  </configFile>
86  </configInfo>
87 ***/
88 
89 #include "asterisk.h"
90 
91 #include "asterisk/module.h"
92 #include "asterisk/astobj2.h"
94 #include "asterisk/taskprocessor.h"
95 #include "asterisk/res_hep.h"
96 
97 #include <netinet/ip.h>
98 #include <netinet/tcp.h>
99 #include <netinet/udp.h>
100 #include <netinet/ip6.h>
101 
102 /*! Generic vendor ID. Used for HEPv3 standard packets */
103 #define GENERIC_VENDOR_ID 0x0000
104 
105 /*! Asterisk vendor ID. Used for custom data to send to a capture node */
106 #define ASTERISK_VENDOR_ID 0x0004
107 
108 /*! Chunk types from the HEPv3 Spec */
110 
111  /*! THE IP PROTOCOL FAMILY */
113 
114  /*! THE IP PROTOCOL ID (UDP, TCP, ETC.) */
116 
117  /*! IF IPV4, THE SOURCE ADDRESS */
119 
120  /*! IF IPV4, THE DESTINATION ADDRESS */
122 
123  /*! IF IPV6, THE SOURCE ADDRESS */
125 
126  /*! IF IPV6, THE DESTINATION ADDRESS */
128 
129  /*! THE SOURCE PORT */
131 
132  /*! THE DESTINATION PORT */
134 
135  /*! THE CAPTURE TIME (SECONDS) */
137 
138  /*! THE CAPTURE TIME (MICROSECONDS) */
140 
141  /*! THE PROTOCOL PACKET TYPE. SEE /REF HEPV3_CAPTURE_TYPE */
143 
144  /*! OUR CAPTURE AGENT ID */
146 
147  /*! A KEEP ALIVE TIMER */
149 
150  /*! THE CAPTURE_PASSWORD IF DEFINED */
152 
153  /*! THE ONE AND ONLY PAYLOAD */
155 
156  /*! THE ONE AND ONLY (ZIPPED) PAYLOAD */
158 
159  /*! THE UUID FOR THIS PACKET */
160  CHUNK_TYPE_UUID = 0X0011,
161 
162  /*! THE CAPTURE AGENT NAME */
164 };
165 
166 #define INITIALIZE_GENERIC_HEP_IDS(hep_chunk, type) do { \
167  (hep_chunk)->vendor_id = htons(GENERIC_VENDOR_ID); \
168  (hep_chunk)->type_id = htons((type)); \
169  } while (0)
170 
171 #define INITIALIZE_GENERIC_HEP_IDS_VAR(hep_chunk, type, len) do { \
172  INITIALIZE_GENERIC_HEP_IDS((hep_chunk), (type)); \
173  (hep_chunk)->length = htons(sizeof(*(hep_chunk)) + len); \
174  } while (0)
175 
176 #define INITIALIZE_GENERIC_HEP_CHUNK(hep_item, type) do { \
177  INITIALIZE_GENERIC_HEP_IDS(&(hep_item)->chunk, (type)); \
178  (hep_item)->chunk.length = htons(sizeof(*(hep_item))); \
179  } while (0)
180 
181 #define INITIALIZE_GENERIC_HEP_CHUNK_DATA(hep_item, type, value) do { \
182  INITIALIZE_GENERIC_HEP_CHUNK((hep_item), (type)); \
183  (hep_item)->data = (value); \
184  } while (0)
185 
186 /*
187  * HEPv3 Types.
188  * Note that the content in these is stored in network byte order.
189  */
190 
191 struct hep_chunk {
192  u_int16_t vendor_id;
193  u_int16_t type_id;
194  u_int16_t length;
195 } __attribute__((packed));
196 
198  struct hep_chunk chunk;
199  u_int8_t data;
200 } __attribute__((packed));
201 
203  struct hep_chunk chunk;
204  u_int16_t data;
205 } __attribute__((packed));
206 
208  struct hep_chunk chunk;
209  u_int32_t data;
210 } __attribute__((packed));
211 
213  struct hep_chunk chunk;
214  struct in_addr data;
215 } __attribute__((packed));
216 
218  struct hep_chunk chunk;
219  struct in6_addr data;
220 } __attribute__((packed));
221 
222 struct hep_ctrl {
223  char id[4];
224  u_int16_t length;
225 } __attribute__((packed));
226 
227 /* HEP structures */
228 
229 struct hep_generic {
230  struct hep_ctrl header;
231  struct hep_chunk_uint8 ip_family;
232  struct hep_chunk_uint8 ip_proto;
233  struct hep_chunk_uint16 src_port;
234  struct hep_chunk_uint16 dst_port;
235  struct hep_chunk_uint32 time_sec;
236  struct hep_chunk_uint32 time_usec;
237  struct hep_chunk_uint8 proto_t;
238  struct hep_chunk_uint32 capt_id;
239 } __attribute__((packed));
240 
241 /*! \brief Global configuration for the module */
243  unsigned int enabled; /*!< Whether or not sending is enabled */
244  unsigned int capture_id; /*!< Capture ID for this agent */
245  enum hep_uuid_type uuid_type; /*!< The preferred type of the UUID */
247  AST_STRING_FIELD(capture_address); /*!< Address to send to */
248  AST_STRING_FIELD(capture_password); /*!< Password for Homer server */
249  AST_STRING_FIELD(capture_name); /*!< Capture name for this agent */
250  );
251 };
252 
253 /*! \brief The actual module config */
254 struct module_config {
255  struct hepv3_global_config *general; /*!< The general config settings */
256 };
257 
258 /*! \brief Run-time data derived from \ref hepv3_global_config */
260  struct ast_sockaddr remote_addr; /*!< The address to send to */
261  int sockfd; /*!< The socket file descriptor */
262 };
263 
264 static struct aco_type global_option = {
265  .type = ACO_GLOBAL,
266  .name = "general",
267  .item_offset = offsetof(struct module_config, general),
268  .category_match = ACO_WHITELIST_EXACT,
269  .category = "general",
270 };
271 
272 struct aco_type *global_options[] = ACO_TYPES(&global_option);
273 
274 struct aco_file hepv3_conf = {
275  .filename = "hep.conf",
276  .types = ACO_TYPES(&global_option),
277 };
278 
279 /*! \brief The module configuration container */
281 
282 /*! \brief Current module data */
283 static AO2_GLOBAL_OBJ_STATIC(global_data);
284 
285 static struct ast_taskprocessor *hep_queue_tp;
286 
287 static void *module_config_alloc(void);
288 static int hepv3_config_pre_apply(void);
289 static void hepv3_config_post_apply(void);
290 
291 /*! \brief Register information about the configs being processed by this module */
293  .files = ACO_FILES(&hepv3_conf),
294  .pre_apply_config = hepv3_config_pre_apply,
295  .post_apply_config = hepv3_config_post_apply,
296 );
297 
298 static void hepv3_config_dtor(void *obj)
299 {
300  struct hepv3_global_config *config = obj;
301 
303 }
304 
305 /*! \brief HEPv3 configuration object allocation */
306 static void *hepv3_config_alloc(void)
307 {
308  struct hepv3_global_config *config;
309 
310  config = ao2_alloc(sizeof(*config), hepv3_config_dtor);
311  if (!config || ast_string_field_init(config, 32)) {
312  return NULL;
313  }
314 
315  return config;
316 }
317 
318 /*! \brief Configuration object destructor */
319 static void module_config_dtor(void *obj)
320 {
321  struct module_config *config = obj;
322 
323  if (config->general) {
324  ao2_ref(config->general, -1);
325  }
326 }
327 
328 /*! \brief Module config constructor */
329 static void *module_config_alloc(void)
330 {
331  struct module_config *config;
332 
333  config = ao2_alloc(sizeof(*config), module_config_dtor);
334  if (!config) {
335  return NULL;
336  }
337 
338  config->general = hepv3_config_alloc();
339  if (!config->general) {
340  ao2_ref(config, -1);
341  config = NULL;
342  }
343 
344  return config;
345 }
346 
347 /*! \brief Handler for the uuid_type attribute */
348 static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
349 {
350  struct hepv3_global_config *global_config = obj;
351 
352  if (strcasecmp(var->name, "uuid_type")) {
353  return -1;
354  }
355 
356  if (!strcasecmp(var->value, "channel")) {
357  global_config->uuid_type = HEP_UUID_TYPE_CHANNEL;
358  } else if (!strcasecmp(var->value, "call-id")) {
359  global_config->uuid_type = HEP_UUID_TYPE_CALL_ID;
360  } else {
361  return -1;
362  }
363  return 0;
364 }
365 
366 /*! \brief HEPv3 run-time data destructor */
367 static void hepv3_data_dtor(void *obj)
368 {
369  struct hepv3_runtime_data *data = obj;
370 
371  if (data->sockfd > -1) {
372  close(data->sockfd);
373  data->sockfd = -1;
374  }
375 }
376 
377 /*! \brief Allocate the HEPv3 run-time data */
379 {
380  struct hepv3_runtime_data *data;
381 
382  data = ao2_alloc(sizeof(*data), hepv3_data_dtor);
383  if (!data) {
384  return NULL;
385  }
386 
387  data->sockfd = -1;
388 
389  if (ast_sockaddr_resolve_first_af(&data->remote_addr, config->capture_address, PARSE_PORT_REQUIRE, AST_AF_UNSPEC)) {
390  ast_log(AST_LOG_WARNING, "Failed to create address from %s\n", config->capture_address);
391  ao2_ref(data, -1);
392  return NULL;
393 
394  }
395 
396  data->sockfd = socket(ast_sockaddr_is_ipv6(&data->remote_addr) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
397  if (data->sockfd < 0) {
398  ast_log(AST_LOG_WARNING, "Failed to create socket for address %s: %s\n",
399  config->capture_address, strerror(errno));
400  ao2_ref(data, -1);
401  return NULL;
402  }
403 
404  return data;
405 }
406 
407 /*! \brief Destructor for a \ref hepv3_capture_info object */
408 static void capture_info_dtor(void *obj)
409 {
410  struct hepv3_capture_info *info = obj;
411 
412  ast_free(info->uuid);
413  ast_free(info->payload);
414 }
415 
416 enum hep_uuid_type hepv3_get_uuid_type(void)
417 {
418  RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
419 
420  if (!config) {
421  /* Well, that's unfortunate. Return something. */
422  return HEP_UUID_TYPE_CALL_ID;
423  }
424 
425  return config->general->uuid_type;
426 }
427 
429 {
430  RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
431 
432  return config && config->general->enabled;
433 }
434 
436 {
437  struct hepv3_capture_info *info;
438 
439  info = ao2_alloc(sizeof(*info), capture_info_dtor);
440  if (!info) {
441  return NULL;
442  }
443 
444  info->payload = ast_malloc(len);
445  if (!info->payload) {
446  ao2_ref(info, -1);
447  return NULL;
448  }
449  memcpy(info->payload, payload, len);
450  info->len = len;
451 
452  /* Set a reasonable default */
453  info->protocol_id = IPPROTO_UDP;
454 
455  return info;
456 }
457 
458 /*! \brief Callback function for the \ref hep_queue_tp taskprocessor */
459 static int hep_queue_cb(void *data)
460 {
461  RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
462  RAII_VAR(struct hepv3_runtime_data *, hepv3_data, ao2_global_obj_ref(global_data), ao2_cleanup);
463  RAII_VAR(struct hepv3_capture_info *, capture_info, data, ao2_cleanup);
464  struct hep_generic hg_pkt;
465  unsigned int packet_len = 0, sock_buffer_len;
466  struct hep_chunk_ip4 ipv4_src, ipv4_dst;
467  struct hep_chunk_ip6 ipv6_src, ipv6_dst;
468  struct hep_chunk auth_key, payload, uuid, capturename;
469  void *sock_buffer;
470  int res;
471 
472  if (!capture_info || !config || !hepv3_data) {
473  return 0;
474  }
475 
476  if (ast_sockaddr_is_ipv4(&capture_info->src_addr) != ast_sockaddr_is_ipv4(&capture_info->dst_addr)) {
477  ast_log(AST_LOG_NOTICE, "Unable to send packet: Address Family mismatch between source/destination\n");
478  return -1;
479  }
480 
481  packet_len = sizeof(hg_pkt);
482 
483  /* Build HEPv3 header, capture info, and calculate the total packet size */
484  memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4);
485 
486  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, capture_info->protocol_id);
487  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr)));
488  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr)));
489  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec));
490  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_usec, CHUNK_TYPE_TIMESTAMP_USEC, htonl(capture_info->capture_time.tv_usec));
491  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.proto_t, CHUNK_TYPE_PROTOCOL_TYPE, capture_info->capture_type);
492  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.capt_id, CHUNK_TYPE_CAPTURE_AGENT_ID, htonl(config->general->capture_id));
493 
494  if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
495  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
497 
498  INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_src, CHUNK_TYPE_IPV4_SRC_ADDR);
499  inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv4_src.data);
500 
501  INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_dst, CHUNK_TYPE_IPV4_DST_ADDR);
502  inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv4_dst.data);
503 
504  packet_len += (sizeof(ipv4_src) + sizeof(ipv4_dst));
505  } else {
506  INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
508 
509  INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_src, CHUNK_TYPE_IPV6_SRC_ADDR);
510  inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv6_src.data);
511 
512  INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_dst, CHUNK_TYPE_IPV6_DST_ADDR);
513  inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv6_dst.data);
514 
515  packet_len += (sizeof(ipv6_src) + sizeof(ipv6_dst));
516  }
517 
518  if (!ast_strlen_zero(config->general->capture_password)) {
519  INITIALIZE_GENERIC_HEP_IDS_VAR(&auth_key, CHUNK_TYPE_AUTH_KEY, strlen(config->general->capture_password));
520  packet_len += (sizeof(auth_key) + strlen(config->general->capture_password));
521  }
522  if (!ast_strlen_zero(config->general->capture_name)) {
523  INITIALIZE_GENERIC_HEP_IDS_VAR(&capturename, CHUNK_TYPE_CAPTURE_AGENT_NAME, strlen(config->general->capture_name));
524  packet_len += (sizeof(capturename) + strlen(config->general->capture_name));
525  }
526  INITIALIZE_GENERIC_HEP_IDS_VAR(&uuid, CHUNK_TYPE_UUID, strlen(capture_info->uuid));
527  packet_len += (sizeof(uuid) + strlen(capture_info->uuid));
528  INITIALIZE_GENERIC_HEP_IDS_VAR(&payload,
529  capture_info->zipped ? CHUNK_TYPE_PAYLOAD_ZIP : CHUNK_TYPE_PAYLOAD, capture_info->len);
530  packet_len += (sizeof(payload) + capture_info->len);
531  hg_pkt.header.length = htons(packet_len);
532 
533  /* Build the buffer to send */
534  sock_buffer = ast_malloc(packet_len);
535  if (!sock_buffer) {
536  return -1;
537  }
538 
539  /* Copy in the header */
540  memcpy(sock_buffer, &hg_pkt, sizeof(hg_pkt));
541  sock_buffer_len = sizeof(hg_pkt);
542 
543  /* Addresses */
544  if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
545  memcpy(sock_buffer + sock_buffer_len, &ipv4_src, sizeof(ipv4_src));
546  sock_buffer_len += sizeof(ipv4_src);
547  memcpy(sock_buffer + sock_buffer_len, &ipv4_dst, sizeof(ipv4_dst));
548  sock_buffer_len += sizeof(ipv4_dst);
549  } else {
550  memcpy(sock_buffer + sock_buffer_len, &ipv6_src, sizeof(ipv6_src));
551  sock_buffer_len += sizeof(ipv6_src);
552  memcpy(sock_buffer + sock_buffer_len, &ipv6_dst, sizeof(ipv6_dst));
553  sock_buffer_len += sizeof(ipv6_dst);
554  }
555 
556  /* Auth Key */
557  if (!ast_strlen_zero(config->general->capture_password)) {
558  memcpy(sock_buffer + sock_buffer_len, &auth_key, sizeof(auth_key));
559  sock_buffer_len += sizeof(auth_key);
560  memcpy(sock_buffer + sock_buffer_len, config->general->capture_password, strlen(config->general->capture_password));
561  sock_buffer_len += strlen(config->general->capture_password);
562  }
563 
564  /* UUID */
565  memcpy(sock_buffer + sock_buffer_len, &uuid, sizeof(uuid));
566  sock_buffer_len += sizeof(uuid);
567  memcpy(sock_buffer + sock_buffer_len, capture_info->uuid, strlen(capture_info->uuid));
568  sock_buffer_len += strlen(capture_info->uuid);
569 
570  /* Capture Agent Name */
571  if (!ast_strlen_zero(config->general->capture_name)) {
572  memcpy(sock_buffer + sock_buffer_len, &capturename, sizeof(capturename));
573  sock_buffer_len += sizeof(capturename);
574  memcpy(sock_buffer + sock_buffer_len, config->general->capture_name, strlen(config->general->capture_name));
575  sock_buffer_len += strlen(config->general->capture_name);
576  }
577 
578  /* Packet! */
579  memcpy(sock_buffer + sock_buffer_len, &payload, sizeof(payload));
580  sock_buffer_len += sizeof(payload);
581  memcpy(sock_buffer + sock_buffer_len, capture_info->payload, capture_info->len);
582  sock_buffer_len += capture_info->len;
583 
584  ast_assert(sock_buffer_len == packet_len);
585 
586  res = ast_sendto(hepv3_data->sockfd, sock_buffer, sock_buffer_len, 0, &hepv3_data->remote_addr);
587  if (res < 0) {
588  ast_log(AST_LOG_ERROR, "Error [%d] while sending packet to HEPv3 server: %s\n",
589  errno, strerror(errno));
590  } else if (res != sock_buffer_len) {
591  ast_log(AST_LOG_WARNING, "Failed to send complete packet to HEPv3 server: %d of %u sent\n",
592  res, sock_buffer_len);
593  res = -1;
594  }
595 
596  ast_free(sock_buffer);
597  return res;
598 }
599 
600 int hepv3_send_packet(struct hepv3_capture_info *capture_info)
601 {
602  RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
603  int res;
604 
605  if (!config || !config->general->enabled) {
606  ao2_ref(capture_info, -1);
607  return 0;
608  }
609 
610  res = ast_taskprocessor_push(hep_queue_tp, hep_queue_cb, capture_info);
611  if (res == -1) {
612  ao2_ref(capture_info, -1);
613  }
614 
615  return res;
616 }
617 
618 /*!
619  * \brief Pre-apply callback for the config framework.
620  *
621  * This validates that required fields exist and are populated.
622  */
623 static int hepv3_config_pre_apply(void)
624 {
625  struct module_config *config = aco_pending_config(&cfg_info);
626 
627  if (!config->general->enabled) {
628  /* If we're not enabled, we don't care about anything else */
629  return 0;
630  }
631 
632  if (ast_strlen_zero(config->general->capture_address)) {
633  ast_log(AST_LOG_ERROR, "Missing required configuration option 'capture_address'\n");
634  return -1;
635  }
636 
637  return 0;
638 }
639 
640 /*!
641  * \brief Post-apply callback for the config framework.
642  *
643  * This will create the run-time information from the supplied
644  * configuration.
645  */
646 static void hepv3_config_post_apply(void)
647 {
648  RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(global_config), ao2_cleanup);
649  struct hepv3_runtime_data *data;
650 
651  data = hepv3_data_alloc(mod_cfg->general);
652  if (!data) {
653  return;
654  }
655 
656  ao2_global_obj_replace_unref(global_data, data);
657  ao2_ref(data, -1);
658 }
659 
660 /*!
661  * \brief Reload the module
662  */
663 static int reload_module(void)
664 {
665  if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
666  return -1;
667  }
668  return 0;
669 }
670 
671 /*!
672  * \brief Unload the module
673  */
674 static int unload_module(void)
675 {
676  hep_queue_tp = ast_taskprocessor_unreference(hep_queue_tp);
677 
679  ao2_global_obj_release(global_data);
680  aco_info_destroy(&cfg_info);
681 
682  return 0;
683 }
684 
685 /*!
686  * \brief Load the module
687  */
688 static int load_module(void)
689 {
690  if (aco_info_init(&cfg_info)) {
691  goto error;
692  }
693 
694  hep_queue_tp = ast_taskprocessor_get("hep_queue_tp", TPS_REF_DEFAULT);
695  if (!hep_queue_tp) {
696  goto error;
697  }
698 
699  aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct hepv3_global_config, enabled));
700  aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct hepv3_global_config, capture_address));
701  aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password));
702  aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id));
703  aco_option_register(&cfg_info, "capture_name", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_name));
704  aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0);
705 
706  if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
707  goto error;
708  }
709 
711 
712 error:
713  aco_info_destroy(&cfg_info);
715 }
716 
717 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HEPv3 API",
718  .support_level = AST_MODULE_SUPPORT_EXTENDED,
719  .load = load_module,
720  .unload = unload_module,
721  .reload = reload_module,
722  .load_pri = AST_MODPRI_APP_DEPEND,
723 );
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:286
static int load_module(void)
Load the module.
Definition: res_hep.c:688
ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, const struct ast_sockaddr *dest_addr)
Wrapper around sendto(2) that uses ast_sockaddr.
Definition: netsock2.c:614
Asterisk main include file. File version handling, generic pbx functions.
Run-time data derived from hepv3_global_config.
Definition: res_hep.c:259
const ast_string_field capture_name
Definition: res_hep.c:250
int hepv3_send_packet(struct hepv3_capture_info *capture_info)
Send a generic packet capture to HEPv3.
Definition: res_hep.c:600
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
unsigned int enabled
Definition: res_hep.c:243
const ast_string_field capture_password
Definition: res_hep.c:250
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
Structure for variables, used for configurations and for channel variables.
hepv3_chunk_types
Definition: res_hep.c:109
return a reference to a taskprocessor, create one if it does not exist
Definition: taskprocessor.h:76
Routines for integration with Homer using HEPv3.
static int hepv3_config_pre_apply(void)
Pre-apply callback for the config framework.
Definition: res_hep.c:623
enum hep_uuid_type hepv3_get_uuid_type(void)
Get the preferred UUID type.
Definition: res_hep.c:416
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
static int reload_module(void)
Reload the module.
Definition: res_hep.c:663
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
static int unload_module(void)
Unload the module.
Definition: res_hep.c:674
The representation of a single configuration file to be processed.
enum aco_type_t type
Socket address structure.
Definition: netsock2.h:97
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
struct hepv3_capture_info * hepv3_create_capture_info(const void *payload, size_t len)
Create a hepv3_capture_info object.
Definition: res_hep.c:435
HEPv3 Capture Info.
Definition: res_hep.h:57
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
static void * hepv3_config_alloc(void)
HEPv3 configuration object allocation.
Definition: res_hep.c:306
struct hepv3_global_config * general
Definition: res_hep.c:255
static AO2_GLOBAL_OBJ_STATIC(global_config)
The module configuration container.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
Type for default option handler for unsigned integers.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
enum hep_uuid_type uuid_type
Definition: res_hep.c:245
int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, const char *name, int flag, int family)
Return the first entry from ast_sockaddr_resolve filtered by address family.
Definition: netsock2.c:337
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
The configuration settings for this module.
Definition: cdr.c:264
static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Handler for the uuid_type attribute.
Definition: res_hep.c:348
static struct hepv3_runtime_data * hepv3_data_alloc(struct hepv3_global_config *config)
Allocate the HEPv3 run-time data.
Definition: res_hep.c:378
struct ast_sockaddr remote_addr
Definition: res_hep.c:260
Their was an error and no changes were applied.
Configuration option-handling.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
Type for default option handler for bools (ast_true/ast_false)
static void capture_info_dtor(void *obj)
Destructor for a hepv3_capture_info object.
Definition: res_hep.c:408
static void module_config_dtor(void *obj)
Configuration object destructor.
Definition: res_hep.c:319
int hepv3_is_loaded(void)
Return whether or not we're currently loaded and active.
Definition: res_hep.c:428
static void * module_config_alloc(void)
Module config constructor.
Definition: res_hep.c:329
unsigned int capture_id
Definition: res_hep.c:244
Global configuration for the module.
Definition: res_hep.c:242
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct aco_type global_option
An aco_type structure to link the "general" category to the skel_global_config type.
Definition: app_skel.c:241
An API for managing task processing threads that can be shared across modules.
static void hepv3_data_dtor(void *obj)
HEPv3 run-time data destructor.
Definition: res_hep.c:367
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
Type information about a category-level configurable object.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
const char * filename
int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
Determine if the address is an IPv4 address.
Definition: netsock2.c:497
CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc,.files=ACO_FILES(&hepv3_conf),.pre_apply_config=hepv3_config_pre_apply,.post_apply_config=hepv3_config_post_apply,)
Register information about the configs being processed by this module.
Type for default option handler for stringfields.
static void hepv3_config_post_apply(void)
Post-apply callback for the config framework.
Definition: res_hep.c:646
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_cdr_config * general
Definition: cdr.c:265
Asterisk module definitions.
static int hep_queue_cb(void *data)
Callback function for the hep_queue_tp taskprocessor.
Definition: res_hep.c:459
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
void * payload
Definition: res_hep.h:65
const ast_string_field capture_address
Definition: res_hep.c:250