Asterisk - The Open Source Telephony Project GIT-master-590b490
Loading...
Searching...
No Matches
Enumerations | Functions | Variables
res_pjsip_maintenance.c File Reference

PJSIP Endpoint Maintenance Mode. More...

#include "asterisk.h"
#include <pjsip.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/sorcery.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
Include dependency graph for res_pjsip_maintenance.c:

Go to the source code of this file.

Enumerations

enum  { MAINT_HASH_BUCKETS = 53 }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int ami_maint_entry_cb (void *obj, void *arg, int flags)
 ao2_callback used to emit one PJSIPMaintenanceStatus AMI list entry
 
static int ami_set_maintenance (struct mansession *s, const struct message *m)
 
static int ami_show_maintenance (struct mansession *s, const struct message *m)
 
static int apply_maintenance_state (const char *endpoint_name, int enable)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static char * cli_complete_endpoint (const char *word)
 
static int cli_maint_entry_cb (void *obj, void *arg, int flags)
 ao2_callback used to print one maintenance entry to the CLI
 
static char * handle_cli_pjsip_set_maintenance (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_cli_pjsip_show_maintenance (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static void maint_endpoint_deleted (const void *obj)
 
static int maint_session_create (struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology)
 
static int maint_set_add (const char *endpoint_name)
 
static int maint_set_remove (const char *endpoint_name)
 
static pj_bool_t maintenance_on_rx_request (pjsip_rx_data *rdata)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Endpoint Maintenance Mode" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_maintenance []
 
static const struct ast_sorcery_observer endpoint_observer
 
static struct pjsip_module maintenance_pjsip_mod
 
static struct ast_sip_session_supplement maintenance_session_supplement
 
static struct ao2_containermaintenance_set
 

Detailed Description

PJSIP Endpoint Maintenance Mode.

Provides a runtime toggle to place individual PJSIP endpoints into maintenance mode. While an endpoint is in maintenance mode:

CLI: pjsip set maintenance <on|off> <endpoint|all> pjsip show maintenance [endpoint]

AMI actions: PJSIPSetMaintenance, PJSIPShowMaintenance

Definition in file res_pjsip_maintenance.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
MAINT_HASH_BUCKETS 

Definition at line 154 of file res_pjsip_maintenance.c.

154 {
156};
@ MAINT_HASH_BUCKETS

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 754 of file res_pjsip_maintenance.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 754 of file res_pjsip_maintenance.c.

◆ ami_maint_entry_cb()

static int ami_maint_entry_cb ( void *  obj,
void *  arg,
int  flags 
)
static

ao2_callback used to emit one PJSIPMaintenanceStatus AMI list entry

Definition at line 654 of file res_pjsip_maintenance.c.

655{
656 const char *name = obj;
657 struct ast_sip_ami *ami = arg;
658 struct ast_str *buf;
659
660 buf = ast_sip_create_ami_event("PJSIPMaintenanceStatus", ami);
661 if (!buf) {
662 return 0;
663 }
664 ast_str_append(&buf, 0, "Endpoint: %s\r\nStatus: enabled\r\n", name);
665 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
666 ast_free(buf);
667 ++ami->count;
668
669 return 0;
670}
#define ast_free(a)
Definition astmm.h:180
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static const char name[]
Definition format_mp3.c:68
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1909
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
AMI variable container.
Definition res_pjsip.h:3225
struct mansession * s
Definition res_pjsip.h:3227
Support for dynamic strings.
Definition strings.h:623

References ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_str_append(), ast_str_buffer(), astman_append(), buf, ast_sip_ami::count, name, and ast_sip_ami::s.

Referenced by ami_show_maintenance().

◆ ami_set_maintenance()

static int ami_set_maintenance ( struct mansession s,
const struct message m 
)
static

Definition at line 562 of file res_pjsip_maintenance.c.

563{
564 const char *endpoint_name;
565 const char *state_str;
566 struct ast_sip_endpoint *endpoint;
567 struct ao2_container *all_endpoints;
568 struct ao2_iterator it;
569 int enable;
570 int rc;
571
572 endpoint_name = astman_get_header(m, "Endpoint");
573 state_str = astman_get_header(m, "State");
574
575 if (ast_strlen_zero(endpoint_name)) {
576 astman_send_error(s, m, "Endpoint parameter missing");
577 return 0;
578 }
579 if (ast_strlen_zero(state_str)) {
580 astman_send_error(s, m, "State parameter missing");
581 return 0;
582 }
583
584 if (!strcasecmp(state_str, "on")) {
585 enable = 1;
586 } else if (!strcasecmp(state_str, "off")) {
587 enable = 0;
588 } else {
589 astman_send_error(s, m, "State must be 'on' or 'off'");
590 return 0;
591 }
592
593 if (!strcasecmp(endpoint_name, "all")) {
594 int count = 0;
595
596 all_endpoints = ast_sip_get_endpoints();
597 if (!all_endpoints) {
598 astman_send_error(s, m, "Failed to retrieve endpoint list");
599 return 0;
600 }
601 it = ao2_iterator_init(all_endpoints, 0);
602 while ((endpoint = ao2_iterator_next(&it))) {
603 if (apply_maintenance_state(ast_sorcery_object_get_id(endpoint), enable) > 0) {
604 count++;
605 }
606 ao2_ref(endpoint, -1);
607 }
609 ao2_ref(all_endpoints, -1);
610 if (count > 0) {
611 manager_event(EVENT_FLAG_SYSTEM, "PJSIPMaintenanceStatus",
612 "Endpoint: all\r\n"
613 "Status: %s\r\n",
614 enable ? "enabled" : "disabled");
615 ast_log(LOG_NOTICE, "PJSIP: Maintenance mode %s for all endpoints "
616 "(%d endpoint%s affected)\n",
617 enable ? "enabled" : "disabled",
618 count, count == 1 ? "" : "s");
619 }
620 astman_send_ack(s, m,
621 enable ? "Maintenance mode enabled for all endpoints"
622 : "Maintenance mode disabled for all endpoints");
623 return 0;
624 }
625
626 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
627 if (!endpoint) {
628 astman_send_error_va(s, m, "Endpoint '%s' not found", endpoint_name);
629 return 0;
630 }
631 ao2_ref(endpoint, -1);
632
633 rc = apply_maintenance_state(endpoint_name, enable);
634 if (rc < 0) {
635 astman_send_error_va(s, m, "Failed to %s maintenance mode for endpoint '%s'",
636 enable ? "enable" : "disable", endpoint_name);
637 } else {
638 if (rc > 0) {
639 manager_event(EVENT_FLAG_SYSTEM, "PJSIPMaintenanceStatus",
640 "Endpoint: %s\r\n"
641 "Status: %s\r\n",
642 endpoint_name, enable ? "enabled" : "disabled");
643 ast_log(LOG_NOTICE, "PJSIP: Maintenance mode %s for endpoint '%s'\n",
644 enable ? "enabled" : "disabled", endpoint_name);
645 }
646 astman_send_ack(s, m,
647 enable ? "Maintenance mode enabled" : "Maintenance mode disabled");
648 }
649
650 return 0;
651}
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1988
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition manager.c:1993
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2020
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1649
#define LOG_NOTICE
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition manager.h:255
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
struct ao2_container * ast_sip_get_endpoints(void)
Retrieve any endpoints available to sorcery.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int apply_maintenance_state(const char *endpoint_name, int enable)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
An entity with which Asterisk communicates.
Definition res_pjsip.h:1061

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, apply_maintenance_state(), ast_log, ast_sip_get_endpoints(), ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), astman_send_error_va(), EVENT_FLAG_SYSTEM, LOG_NOTICE, and manager_event.

Referenced by load_module().

◆ ami_show_maintenance()

static int ami_show_maintenance ( struct mansession s,
const struct message m 
)
static

Definition at line 672 of file res_pjsip_maintenance.c.

673{
674 const char *endpoint_name;
675 struct ast_sip_ami ami;
676 char *entry;
677 struct ast_str *buf;
678
679 endpoint_name = astman_get_header(m, "Endpoint");
680
681 ami.s = s;
682 ami.m = m;
683 ami.action_id = astman_get_header(m, "ActionID");
684 ami.arg = NULL;
685 ami.count = 0;
686
687 astman_send_listack(s, m, "Maintenance status events follow", "start");
688
689 if (!ast_strlen_zero(endpoint_name)) {
690 buf = ast_sip_create_ami_event("PJSIPMaintenanceStatus", &ami);
691 if (buf) {
692 entry = ao2_find(maintenance_set, endpoint_name, OBJ_SEARCH_KEY);
693 ast_str_append(&buf, 0, "Endpoint: %s\r\nStatus: %s\r\n",
694 endpoint_name, entry ? "enabled" : "disabled");
695 if (entry) {
696 ao2_ref(entry, -1);
697 }
698 astman_append(s, "%s\r\n", ast_str_buffer(buf));
699 ast_free(buf);
700 }
701 ami.count = 1;
702 } else {
704 }
705
706 astman_send_list_complete_start(s, m, "PJSIPMaintenanceStatusComplete", ami.count);
708
709 return 0;
710}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2030
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2066
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2074
static int ami_maint_entry_cb(void *obj, void *arg, int flags)
ao2_callback used to emit one PJSIPMaintenanceStatus AMI list entry
static struct ao2_container * maintenance_set
#define NULL
Definition resample.c:96

References ast_sip_ami::action_id, ami_maint_entry_cb(), ao2_callback, ao2_find, ao2_ref, ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_str_append(), ast_str_buffer(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), buf, ast_sip_ami::count, ast_sip_ami::m, maintenance_set, NULL, OBJ_NODATA, OBJ_SEARCH_KEY, and ast_sip_ami::s.

Referenced by load_module().

◆ apply_maintenance_state()

static int apply_maintenance_state ( const char *  endpoint_name,
int  enable 
)
static

Definition at line 212 of file res_pjsip_maintenance.c.

213{
214 return enable ? maint_set_add(endpoint_name) : maint_set_remove(endpoint_name);
215}
static int maint_set_remove(const char *endpoint_name)
static int maint_set_add(const char *endpoint_name)

References maint_set_add(), and maint_set_remove().

Referenced by ami_set_maintenance(), and handle_cli_pjsip_set_maintenance().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 754 of file res_pjsip_maintenance.c.

◆ cli_complete_endpoint()

static char * cli_complete_endpoint ( const char *  word)
static

Definition at line 348 of file res_pjsip_maintenance.c.

349{
350 int wordlen = strlen(word);
351 struct ao2_container *endpoints;
352 struct ast_sip_endpoint *endpoint;
353 struct ao2_iterator i;
354
356 "endpoint", word, wordlen);
357 if (!endpoints) {
358 return NULL;
359 }
360
362 while ((endpoint = ao2_iterator_next(&i))) {
364 ao2_cleanup(endpoint);
365 }
367 ao2_ref(endpoints, -1);
368
369 return NULL;
370}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ao2_cleanup(obj)
Definition astobj2.h:1934
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition main/cli.c:2845
short word
static struct ao2_container * endpoints
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition sorcery.c:2053

References ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_completion_add(), ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_prefix(), ast_strdup, endpoints, and NULL.

Referenced by handle_cli_pjsip_set_maintenance(), and handle_cli_pjsip_show_maintenance().

◆ cli_maint_entry_cb()

static int cli_maint_entry_cb ( void *  obj,
void *  arg,
int  flags 
)
static

ao2_callback used to print one maintenance entry to the CLI

Definition at line 495 of file res_pjsip_maintenance.c.

496{
497 const char *name = obj;
498 int fd = *(int *)arg;
499 ast_cli(fd, " %-40s ON\n", name);
500 return 0;
501}
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6

References ast_cli(), and name.

Referenced by handle_cli_pjsip_show_maintenance().

◆ handle_cli_pjsip_set_maintenance()

static char * handle_cli_pjsip_set_maintenance ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 374 of file res_pjsip_maintenance.c.

376{
377 struct ast_sip_endpoint *endpoint;
378 struct ao2_container *all_endpoints;
379 struct ao2_iterator it;
380 const char *endpoint_name;
381 int enable;
382 int rc;
383 int count;
384 int failed;
385
386 switch (cmd) {
387 case CLI_INIT:
388 e->command = "pjsip set maintenance";
389 e->usage =
390 "Usage: pjsip set maintenance <on|off> <endpoint|all>\n"
391 " Place a PJSIP endpoint into or out of maintenance mode.\n"
392 " Use 'all' to toggle maintenance mode for every endpoint.\n"
393 " While in maintenance mode new inbound out-of-dialog requests\n"
394 " to that endpoint are rejected with 503 (except SUBSCRIBE/\n"
395 " REGISTER with Expires: 0), and outbound originations are\n"
396 " refused.\n";
397 return NULL;
398 case CLI_GENERATE:
399 if (a->pos == 3) {
400 static const char * const opts[] = { "on", "off", NULL };
401 return ast_cli_complete(a->word, opts, a->n);
402 }
403 if (a->pos == 4) {
404 if (!strncasecmp("all", a->word, strlen(a->word))) {
406 }
407 return cli_complete_endpoint(a->word);
408 }
409 return NULL;
410 }
411
412 if (a->argc != 5) {
413 return CLI_SHOWUSAGE;
414 }
415
416 if (!strcasecmp(a->argv[3], "on")) {
417 enable = 1;
418 } else if (!strcasecmp(a->argv[3], "off")) {
419 enable = 0;
420 } else {
421 return CLI_SHOWUSAGE;
422 }
423
424 endpoint_name = a->argv[4];
425
426 if (!strcasecmp(endpoint_name, "all")) {
427 all_endpoints = ast_sip_get_endpoints();
428 if (!all_endpoints) {
429 ast_cli(a->fd, "Failed to retrieve endpoint list\n");
430 return CLI_SUCCESS;
431 }
432 count = 0;
433 failed = 0;
434 it = ao2_iterator_init(all_endpoints, 0);
435 while ((endpoint = ao2_iterator_next(&it))) {
437 if (rc > 0) {
438 count++;
439 } else if (rc < 0) {
440 failed++;
441 }
442 ao2_ref(endpoint, -1);
443 }
445 ao2_ref(all_endpoints, -1);
446 if (count > 0) {
447 manager_event(EVENT_FLAG_SYSTEM, "PJSIPMaintenanceStatus",
448 "Endpoint: all\r\n"
449 "Status: %s\r\n",
450 enable ? "enabled" : "disabled");
451 ast_log(LOG_NOTICE, "PJSIP: Maintenance mode %s for all endpoints "
452 "(%d endpoint%s affected)\n",
453 enable ? "enabled" : "disabled",
454 count, count == 1 ? "" : "s");
455 }
456 ast_cli(a->fd, "Maintenance mode %s for %d endpoint%s%s\n",
457 enable ? "ENABLED" : "DISABLED",
458 count, count == 1 ? "" : "s",
459 failed ? " (some failed)" : "");
460 return CLI_SUCCESS;
461 }
462
463 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
464 if (!endpoint) {
465 ast_cli(a->fd, "Endpoint '%s' not found\n", endpoint_name);
466 return CLI_SUCCESS;
467 }
468 ao2_ref(endpoint, -1);
469
470 rc = apply_maintenance_state(endpoint_name, enable);
471 if (rc > 0) {
472 manager_event(EVENT_FLAG_SYSTEM, "PJSIPMaintenanceStatus",
473 "Endpoint: %s\r\n"
474 "Status: %s\r\n",
475 endpoint_name, enable ? "enabled" : "disabled");
476 ast_log(LOG_NOTICE, "PJSIP: Maintenance mode %s for endpoint '%s'\n",
477 enable ? "enabled" : "disabled", endpoint_name);
478 ast_cli(a->fd, "Maintenance mode %s for endpoint '%s'\n",
479 enable ? "ENABLED" : "DISABLED", endpoint_name);
480 } else if (rc == 0 && enable) {
481 ast_cli(a->fd, "Endpoint '%s' is already in maintenance mode\n", endpoint_name);
482 } else if (rc == 0) {
483 ast_cli(a->fd, "Endpoint '%s' was not in maintenance mode\n", endpoint_name);
484 } else {
485 ast_cli(a->fd, "Failed to %s maintenance mode for endpoint '%s'\n",
486 enable ? "enable" : "disable", endpoint_name);
487 }
488
489 return CLI_SUCCESS;
490}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition main/cli.c:1931
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
static char * cli_complete_endpoint(const char *word)
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
static struct test_val a

References a, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, apply_maintenance_state(), ast_cli(), ast_cli_complete(), ast_cli_completion_add(), ast_log, ast_sip_get_endpoints(), ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), ast_strdup, cli_complete_endpoint(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, EVENT_FLAG_SYSTEM, LOG_NOTICE, manager_event, NULL, and ast_cli_entry::usage.

◆ handle_cli_pjsip_show_maintenance()

static char * handle_cli_pjsip_show_maintenance ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 503 of file res_pjsip_maintenance.c.

505{
506 const char *endpoint_name;
507 char *entry;
508 int fd;
509 int count;
510
511 switch (cmd) {
512 case CLI_INIT:
513 e->command = "pjsip show maintenance";
514 e->usage =
515 "Usage: pjsip show maintenance [endpoint]\n"
516 " Display endpoints currently in maintenance mode.\n"
517 " If [endpoint] is given, show the status for that endpoint only.\n";
518 return NULL;
519 case CLI_GENERATE:
520 if (a->pos == 3) {
521 return cli_complete_endpoint(a->word);
522 }
523 return NULL;
524 }
525
526 if (a->argc == 4) {
527 endpoint_name = a->argv[3];
528 entry = ao2_find(maintenance_set, endpoint_name, OBJ_SEARCH_KEY);
529 if (entry) {
530 ast_cli(a->fd, "Endpoint '%s' is in maintenance mode\n", endpoint_name);
531 ao2_ref(entry, -1);
532 } else {
533 ast_cli(a->fd, "Endpoint '%s' is NOT in maintenance mode\n", endpoint_name);
534 }
535 return CLI_SUCCESS;
536 }
537
538 if (a->argc != 3) {
539 return CLI_SHOWUSAGE;
540 }
541
542 ast_cli(a->fd, "\n");
543 ast_cli(a->fd, " %-40s %s\n", "Endpoint", "State");
544 ast_cli(a->fd, " %-40s -----\n", "----------------------------------------");
545 fd = a->fd;
547
549 ast_cli(a->fd, "\n %d endpoint%s in maintenance mode\n\n",
550 count, count == 1 ? "" : "s");
551
552 return CLI_SUCCESS;
553}
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static int cli_maint_entry_cb(void *obj, void *arg, int flags)
ao2_callback used to print one maintenance entry to the CLI

References a, ao2_callback, ao2_container_count(), ao2_find, ao2_ref, ast_cli(), cli_complete_endpoint(), CLI_GENERATE, CLI_INIT, cli_maint_entry_cb(), CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, maintenance_set, NULL, OBJ_NODATA, OBJ_SEARCH_KEY, and ast_cli_entry::usage.

◆ load_module()

static int load_module ( void  )
static

Definition at line 714 of file res_pjsip_maintenance.c.

715{
718 if (!maintenance_set) {
719 ast_log(LOG_ERROR, "res_pjsip_maintenance: failed to allocate maintenance set\n");
721 }
722
726 ast_manager_register_xml("PJSIPSetMaintenance",
728 ast_manager_register_xml("PJSIPShowMaintenance",
731
733}
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
#define LOG_ERROR
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:111
static struct pjsip_module maintenance_pjsip_mod
static int ami_set_maintenance(struct mansession *s, const struct message *m)
static struct ast_sip_session_supplement maintenance_session_supplement
static struct ast_cli_entry cli_maintenance[]
static int ami_show_maintenance(struct mansession *s, const struct message *m)
static const struct ast_sorcery_observer endpoint_observer
#define ast_sip_session_register_supplement(supplement)
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition sorcery.c:2455
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition strings.c:200
#define ARRAY_LEN(a)
Definition utils.h:706

References ami_set_maintenance(), ami_show_maintenance(), AO2_ALLOC_OPT_LOCK_RWLOCK, ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sip_get_sorcery(), ast_sip_register_service(), ast_sip_session_register_supplement, ast_sorcery_observer_add(), ast_str_container_alloc_options(), cli_maintenance, endpoint_observer, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, LOG_ERROR, MAINT_HASH_BUCKETS, maintenance_pjsip_mod, maintenance_session_supplement, and maintenance_set.

◆ maint_endpoint_deleted()

static void maint_endpoint_deleted ( const void *  obj)
static

◆ maint_session_create()

static int maint_session_create ( struct ast_sip_endpoint endpoint,
struct ast_sip_contact contact,
const char *  location,
const char *  request_user,
struct ast_stream_topology req_topology 
)
static

Definition at line 226 of file res_pjsip_maintenance.c.

229{
230 const char *endpoint_name = ast_sorcery_object_get_id(endpoint);
231 char *entry = ao2_find(maintenance_set, endpoint_name, OBJ_SEARCH_KEY);
232
233 if (entry) {
234 ao2_ref(entry, -1);
235 ast_log(LOG_NOTICE, "PJSIP: Refusing outbound call to endpoint '%s': maintenance mode active\n",
236 endpoint_name);
237 return 1;
238 }
239 return 0;
240}

References ao2_find, ao2_ref, ast_log, ast_sorcery_object_get_id(), LOG_NOTICE, maintenance_set, and OBJ_SEARCH_KEY.

◆ maint_set_add()

static int maint_set_add ( const char *  endpoint_name)
static

Definition at line 171 of file res_pjsip_maintenance.c.

172{
173 char *entry;
174
175 entry = ao2_find(maintenance_set, endpoint_name, OBJ_SEARCH_KEY);
176 if (entry) {
177 ao2_ref(entry, -1);
178 return 0; /* already in maintenance */
179 }
180 return ast_str_container_add(maintenance_set, endpoint_name) ? -1 : 1;
181}
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition strings.c:205

References ao2_find, ao2_ref, ast_str_container_add(), maintenance_set, and OBJ_SEARCH_KEY.

Referenced by apply_maintenance_state().

◆ maint_set_remove()

static int maint_set_remove ( const char *  endpoint_name)
static

Definition at line 189 of file res_pjsip_maintenance.c.

190{
191 char *entry;
192
193 entry = ao2_find(maintenance_set, endpoint_name, OBJ_SEARCH_KEY | OBJ_UNLINK);
194 if (!entry) {
195 return 0;
196 }
197 ao2_ref(entry, -1);
198 return 1;
199}
@ OBJ_UNLINK
Definition astobj2.h:1039

References ao2_find, ao2_ref, maintenance_set, OBJ_SEARCH_KEY, and OBJ_UNLINK.

Referenced by apply_maintenance_state(), and maint_endpoint_deleted().

◆ maintenance_on_rx_request()

static pj_bool_t maintenance_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 254 of file res_pjsip_maintenance.c.

255{
256 pjsip_msg *msg = rdata->msg_info.msg;
257 const pjsip_method *method = &msg->line.req.method;
258 pjsip_to_hdr *to;
259 pjsip_expires_hdr *expires_hdr;
260 struct ast_sip_endpoint *endpoint;
261 char *entry;
262 pjsip_hdr hdr_list;
263 pjsip_generic_int_hdr *retry_after;
264 static const pj_str_t str_retry_after = { "Retry-After", 11 };
265 int is_subscribe;
266 int is_register;
267
268 is_subscribe = pjsip_method_cmp(method, pjsip_get_subscribe_method()) == 0;
269 is_register = pjsip_method_cmp(method, pjsip_get_register_method()) == 0;
270
271 /* Any in-dialog request is always allowed through. */
272 to = rdata->msg_info.to;
273 if (to->tag.slen > 0) {
274 return PJ_FALSE;
275 }
276
277 /* SUBSCRIBE or REGISTER with Expires: 0: allow un-subscribe / de-register. */
278 if (is_subscribe || is_register) {
279 expires_hdr = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
280 if (expires_hdr && expires_hdr->ivalue == 0) {
281 return PJ_FALSE;
282 }
283 }
284
285 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
286 if (!endpoint) {
287 return PJ_FALSE;
288 }
289
291 if (!entry) {
292 ao2_ref(endpoint, -1);
293 return PJ_FALSE;
294 }
295 ao2_ref(entry, -1);
296
297 ast_log(LOG_NOTICE, "PJSIP: Endpoint '%s' is in maintenance mode; rejecting new %.*s from %s\n",
299 (int)method->name.slen, method->name.ptr,
300 rdata->pkt_info.src_name);
301
302 ao2_ref(endpoint, -1);
303
304 pj_list_init(&hdr_list);
305 retry_after = pjsip_generic_int_hdr_create(rdata->tp_info.pool,
306 &str_retry_after, 300);
307 if (retry_after) {
308 pj_list_push_back(&hdr_list, retry_after);
309 }
310
311 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL,
312 retry_after ? &hdr_list : NULL, NULL);
313
314 return PJ_TRUE;
315}
const char * method
Definition res_pjsip.c:1273
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:514
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.

References ao2_find, ao2_ref, ast_log, ast_pjsip_rdata_get_endpoint(), ast_sip_get_pjsip_endpoint(), ast_sorcery_object_get_id(), LOG_NOTICE, maintenance_set, method, NULL, and OBJ_SEARCH_KEY.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 735 of file res_pjsip_maintenance.c.

736{
738 ast_manager_unregister("PJSIPShowMaintenance");
739 ast_manager_unregister("PJSIPSetMaintenance");
745 return 0;
746}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7704
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:127
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition sorcery.c:2487

References ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_sip_get_sorcery(), ast_sip_session_unregister_supplement(), ast_sip_unregister_service(), ast_sorcery_observer_remove(), cli_maintenance, endpoint_observer, maintenance_pjsip_mod, maintenance_session_supplement, maintenance_set, and NULL.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Endpoint Maintenance Mode" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip,res_pjsip_session", }
static

Definition at line 754 of file res_pjsip_maintenance.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 754 of file res_pjsip_maintenance.c.

◆ cli_maintenance

struct ast_cli_entry cli_maintenance[]
static
Initial value:
= {
{ .handler = handle_cli_pjsip_set_maintenance , .summary = "Set PJSIP endpoint maintenance mode" ,},
{ .handler = handle_cli_pjsip_show_maintenance , .summary = "Show PJSIP endpoint maintenance status" ,},
}
static char * handle_cli_pjsip_show_maintenance(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_pjsip_set_maintenance(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 555 of file res_pjsip_maintenance.c.

555 {
556 AST_CLI_DEFINE(handle_cli_pjsip_set_maintenance, "Set PJSIP endpoint maintenance mode"),
557 AST_CLI_DEFINE(handle_cli_pjsip_show_maintenance, "Show PJSIP endpoint maintenance status"),
558};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ endpoint_observer

const struct ast_sorcery_observer endpoint_observer
static
Initial value:
= {
}
static void maint_endpoint_deleted(const void *obj)

Definition at line 338 of file res_pjsip_maintenance.c.

338 {
339 .deleted = maint_endpoint_deleted,
340};

Referenced by load_module(), and unload_module().

◆ maintenance_pjsip_mod

struct pjsip_module maintenance_pjsip_mod
static

Definition at line 317 of file res_pjsip_maintenance.c.

317 {
318 .name = { "Maintenance Module", 18 },
319 /*
320 * Run after endpoint identification (endpoint_mod,
321 * PJSIP_MOD_PRIORITY_TSX_LAYER - 3) so that
322 * ast_pjsip_rdata_get_endpoint() returns the identified endpoint,
323 * but before the request authenticator
324 * (PJSIP_MOD_PRIORITY_APPLICATION - 2) so that a maintenance
325 * endpoint receives 503 rather than a 401 challenge.
326 */
327 .priority = PJSIP_MOD_PRIORITY_APPLICATION - 3,
328 .on_rx_request = maintenance_on_rx_request,
329};
static pj_bool_t maintenance_on_rx_request(pjsip_rx_data *rdata)

Referenced by load_module(), and unload_module().

◆ maintenance_session_supplement

struct ast_sip_session_supplement maintenance_session_supplement
static
Initial value:
= {
.session_create = maint_session_create,
}
@ AST_SIP_SUPPLEMENT_PRIORITY_FIRST
Definition res_pjsip.h:3359
static int maint_session_create(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, const char *location, const char *request_user, struct ast_stream_topology *req_topology)

Definition at line 242 of file res_pjsip_maintenance.c.

242 {
243 .session_create = maint_session_create,
245};

Referenced by load_module(), and unload_module().

◆ maintenance_set

struct ao2_container* maintenance_set
static

Endpoints currently in maintenance mode. Protected by the container's own internal RWLOCK. No other locks are ever held simultaneously with this container.

Definition at line 162 of file res_pjsip_maintenance.c.

Referenced by ami_show_maintenance(), handle_cli_pjsip_show_maintenance(), load_module(), maint_session_create(), maint_set_add(), maint_set_remove(), maintenance_on_rx_request(), and unload_module().