Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
A
asterisk
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Issue analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Voice
asterisk
Commits
057ed940
Commit
057ed940
authored
8 years ago
by
zuul
Committed by
Gerrit Code Review
8 years ago
Browse files
Options
Downloads
Plain Diff
Merge "res_pjsip_exten_state: Add config support for exten state publishers."
parents
9309a96a
81ea80b7
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
res/res_pjsip_exten_state.c
+294
-9
294 additions, 9 deletions
res/res_pjsip_exten_state.c
with
294 additions
and
9 deletions
res/res_pjsip_exten_state.c
+
294
−
9
View file @
057ed940
...
...
@@ -20,16 +20,20 @@
<depend>pjproject</depend>
<depend>res_pjsip</depend>
<depend>res_pjsip_pubsub</depend>
<depend>res_pjsip_outbound_publish</depend>
<support_level>core</support_level>
***/
#include
"asterisk.h"
#include
<regex.h>
#include
<pjsip.h>
#include
<pjsip_simple.h>
#include
<pjlib.h>
#include
"asterisk/res_pjsip.h"
#include
"asterisk/res_pjsip_outbound_publish.h"
#include
"asterisk/res_pjsip_pubsub.h"
#include
"asterisk/res_pjsip_body_generator_types.h"
#include
"asterisk/module.h"
...
...
@@ -42,6 +46,16 @@
#define BODY_SIZE 1024
#define EVENT_TYPE_SIZE 50
/*!
* \brief The number of buckets to use for storing publishers
*/
#define PUBLISHER_BUCKETS 31
/*!
* \brief Container of active outbound extension state publishers
*/
static
struct
ao2_container
*
publishers
;
/*!
* \brief A subscription for extension state
*
...
...
@@ -68,6 +82,29 @@ struct exten_state_subscription {
enum
ast_presence_state
last_presence_state
;
};
/*!
* \brief An extension state publisher
*
*/
struct
exten_state_publisher
{
/*! Regular expression for context filtering */
regex_t
context_regex
;
/*! Regular expression for extension filtering */
regex_t
exten_regex
;
/*! Publish client to use for sending publish messages */
struct
ast_sip_outbound_publish_client
*
client
;
/*! Whether context filtering is active */
unsigned
int
context_filter
;
/*! Whether extension filtering is active */
unsigned
int
exten_filter
;
/*! The body type to use for this publisher - stored after the name */
char
*
body_type
;
/*! The body subtype to use for this publisher - stored after the body type */
char
*
body_subtype
;
/*! The name of this publisher */
char
name
[
0
];
};
#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
#define DEFAULT_DIALOG_BODY "application/dialog-info+xml"
...
...
@@ -77,6 +114,9 @@ static int subscription_established(struct ast_sip_subscription *sub);
static
void
*
get_notify_data
(
struct
ast_sip_subscription
*
sub
);
static
void
to_ami
(
struct
ast_sip_subscription
*
sub
,
struct
ast_str
**
buf
);
static
int
publisher_start
(
struct
ast_sip_outbound_publish
*
configuration
,
struct
ast_sip_outbound_publish_client
*
client
);
static
int
publisher_stop
(
struct
ast_sip_outbound_publish_client
*
client
);
struct
ast_sip_notifier
presence_notifier
=
{
.
default_accept
=
DEFAULT_PRESENCE_BODY
,
...
...
@@ -101,6 +141,12 @@ struct ast_sip_subscription_handler presence_handler = {
.
notifier
=
&
presence_notifier
,
};
struct
ast_sip_event_publisher_handler
presence_publisher
=
{
.
event_name
=
"presence"
,
.
start_publishing
=
publisher_start
,
.
stop_publishing
=
publisher_stop
,
};
struct
ast_sip_subscription_handler
dialog_handler
=
{
.
event_name
=
"dialog"
,
.
body_type
=
AST_SIP_EXTEN_STATE_DATA
,
...
...
@@ -110,6 +156,12 @@ struct ast_sip_subscription_handler dialog_handler = {
.
notifier
=
&
dialog_notifier
,
};
struct
ast_sip_event_publisher_handler
dialog_publisher
=
{
.
event_name
=
"dialog"
,
.
start_publishing
=
publisher_start
,
.
stop_publishing
=
publisher_stop
,
};
static
void
exten_state_subscription_destructor
(
void
*
obj
)
{
struct
exten_state_subscription
*
sub
=
obj
;
...
...
@@ -490,31 +542,264 @@ static void to_ami(struct ast_sip_subscription *sub,
exten_state_sub
->
last_exten_state
));
}
/*!
* \brief Global extension state callback function
*/
static
int
exten_state_publisher_state_cb
(
const
char
*
context
,
const
char
*
exten
,
struct
ast_state_cb_info
*
info
,
void
*
data
)
{
struct
ao2_iterator
publisher_iter
;
struct
exten_state_publisher
*
publisher
;
publisher_iter
=
ao2_iterator_init
(
publishers
,
0
);
for
(;
(
publisher
=
ao2_iterator_next
(
&
publisher_iter
));
ao2_ref
(
publisher
,
-
1
))
{
if
((
publisher
->
context_filter
&&
regexec
(
&
publisher
->
context_regex
,
context
,
0
,
NULL
,
0
))
||
(
publisher
->
exten_filter
&&
regexec
(
&
publisher
->
exten_regex
,
exten
,
0
,
NULL
,
0
)))
{
continue
;
}
/* This is a placeholder for additional code to come */
}
ao2_iterator_destroy
(
&
publisher_iter
);
return
0
;
}
/*!
* \brief Hashing function for extension state publisher
*/
static
int
exten_state_publisher_hash
(
const
void
*
obj
,
const
int
flags
)
{
const
struct
exten_state_publisher
*
object
;
const
char
*
key
;
switch
(
flags
&
OBJ_SEARCH_MASK
)
{
case
OBJ_SEARCH_KEY
:
key
=
obj
;
break
;
case
OBJ_SEARCH_OBJECT
:
object
=
obj
;
key
=
object
->
name
;
break
;
default:
ast_assert
(
0
);
return
0
;
}
return
ast_str_hash
(
key
);
}
/*!
* \brief Comparator function for extension state publisher
*/
static
int
exten_state_publisher_cmp
(
void
*
obj
,
void
*
arg
,
int
flags
)
{
const
struct
exten_state_publisher
*
object_left
=
obj
;
const
struct
exten_state_publisher
*
object_right
=
arg
;
const
char
*
right_key
=
arg
;
int
cmp
;
switch
(
flags
&
OBJ_SEARCH_MASK
)
{
case
OBJ_SEARCH_OBJECT
:
right_key
=
object_right
->
name
;
/* Fall through */
case
OBJ_SEARCH_KEY
:
cmp
=
strcmp
(
object_left
->
name
,
right_key
);
break
;
case
OBJ_SEARCH_PARTIAL_KEY
:
/* Not supported by container. */
ast_assert
(
0
);
return
0
;
default:
cmp
=
0
;
break
;
}
if
(
cmp
)
{
return
0
;
}
return
CMP_MATCH
;
}
/*!
* \brief Destructor for extension state publisher
*/
static
void
exten_state_publisher_destroy
(
void
*
obj
)
{
struct
exten_state_publisher
*
publisher
=
obj
;
if
(
publisher
->
context_filter
)
{
regfree
(
&
publisher
->
context_regex
);
}
if
(
publisher
->
exten_filter
)
{
regfree
(
&
publisher
->
exten_regex
);
}
ao2_cleanup
(
publisher
->
client
);
}
static
int
build_regex
(
regex_t
*
regex
,
const
char
*
text
)
{
int
res
;
if
((
res
=
regcomp
(
regex
,
text
,
REG_EXTENDED
|
REG_ICASE
|
REG_NOSUB
)))
{
size_t
len
=
regerror
(
res
,
regex
,
NULL
,
0
);
char
buf
[
len
];
regerror
(
res
,
regex
,
buf
,
len
);
ast_log
(
LOG_ERROR
,
"Could not compile regex '%s': %s
\n
"
,
text
,
buf
);
return
-
1
;
}
return
0
;
}
static
int
publisher_start
(
struct
ast_sip_outbound_publish
*
configuration
,
struct
ast_sip_outbound_publish_client
*
client
)
{
struct
exten_state_publisher
*
publisher
;
size_t
name_size
;
size_t
body_type_size
;
size_t
body_subtype_size
;
char
*
body_subtype
;
const
char
*
body_full
;
const
char
*
body_type
;
const
char
*
name
;
const
char
*
context
;
const
char
*
exten
;
name
=
ast_sorcery_object_get_id
(
configuration
);
body_full
=
ast_sorcery_object_get_extended
(
configuration
,
"body"
);
if
(
ast_strlen_zero
(
body_full
))
{
ast_log
(
LOG_ERROR
,
"Outbound extension state publisher '%s': Body not set
\n
"
,
name
);
return
-
1
;
}
body_subtype
=
ast_strdupa
(
body_full
);
body_type
=
strsep
(
&
body_subtype
,
"/"
);
if
(
ast_strlen_zero
(
body_type
)
||
ast_strlen_zero
(
body_subtype
))
{
ast_log
(
LOG_ERROR
,
"Outbound extension state publisher '%s': Body '%s' missing type or subtype
\n
"
,
name
,
body_full
);
return
-
1
;
}
name_size
=
strlen
(
name
)
+
1
;
body_type_size
=
strlen
(
body_type
)
+
1
;
body_subtype_size
=
strlen
(
body_subtype
)
+
1
;
publisher
=
ao2_alloc_options
(
sizeof
(
*
publisher
)
+
name_size
+
body_type_size
+
body_subtype_size
,
exten_state_publisher_destroy
,
AO2_ALLOC_OPT_LOCK_NOLOCK
);
if
(
!
publisher
)
{
return
-
1
;
}
ast_copy_string
(
publisher
->
name
,
name
,
name_size
);
publisher
->
body_type
=
publisher
->
name
+
name_size
;
ast_copy_string
(
publisher
->
body_type
,
body_type
,
body_type_size
);
publisher
->
body_subtype
=
publisher
->
body_type
+
body_type_size
;
ast_copy_string
(
publisher
->
body_subtype
,
body_subtype
,
body_subtype_size
);
context
=
ast_sorcery_object_get_extended
(
configuration
,
"context"
);
if
(
!
ast_strlen_zero
(
context
))
{
if
(
build_regex
(
&
publisher
->
context_regex
,
context
))
{
ast_log
(
LOG_ERROR
,
"Outbound extension state publisher '%s': Could not build context filter '%s'
\n
"
,
name
,
context
);
ao2_ref
(
publisher
,
-
1
);
return
-
1
;
}
publisher
->
context_filter
=
1
;
}
exten
=
ast_sorcery_object_get_extended
(
configuration
,
"exten"
);
if
(
!
ast_strlen_zero
(
exten
))
{
if
(
build_regex
(
&
publisher
->
exten_regex
,
exten
))
{
ast_log
(
LOG_ERROR
,
"Outbound extension state publisher '%s': Could not build exten filter '%s'
\n
"
,
name
,
exten
);
ao2_ref
(
publisher
,
-
1
);
return
-
1
;
}
publisher
->
exten_filter
=
1
;
}
publisher
->
client
=
ao2_bump
(
client
);
ao2_lock
(
publishers
);
if
(
!
ao2_container_count
(
publishers
))
{
ast_extension_state_add
(
NULL
,
NULL
,
exten_state_publisher_state_cb
,
NULL
);
}
ao2_link_flags
(
publishers
,
publisher
,
OBJ_NOLOCK
);
ao2_unlock
(
publishers
);
ao2_ref
(
publisher
,
-
1
);
return
0
;
}
static
int
publisher_stop
(
struct
ast_sip_outbound_publish_client
*
client
)
{
ao2_find
(
publishers
,
ast_sorcery_object_get_id
(
client
),
OBJ_SEARCH_KEY
|
OBJ_UNLINK
|
OBJ_NODATA
);
return
0
;
}
static
int
unload_module
(
void
)
{
ast_sip_unregister_event_publisher_handler
(
&
dialog_publisher
);
ast_sip_unregister_subscription_handler
(
&
dialog_handler
);
ast_sip_unregister_event_publisher_handler
(
&
presence_publisher
);
ast_sip_unregister_subscription_handler
(
&
presence_handler
);
ast_extension_state_del
(
0
,
exten_state_publisher_state_cb
);
ao2_cleanup
(
publishers
);
publishers
=
NULL
;
return
0
;
}
static
int
load_module
(
void
)
{
CHECK_PJSIP_MODULE_LOADED
();
CHECK_PJSIP_PUBSUB_MODULE_LOADED
();
if
(
!
ast_module_check
(
"res_pjsip_outbound_publish.so"
))
{
ast_log
(
LOG_WARNING
,
"This module requires the 'res_pjsip_outbound_publish.so' module to be loaded
\n
"
);
return
AST_MODULE_LOAD_DECLINE
;
}
publishers
=
ao2_container_alloc
(
PUBLISHER_BUCKETS
,
exten_state_publisher_hash
,
exten_state_publisher_cmp
);
if
(
!
publishers
)
{
ast_log
(
LOG_WARNING
,
"Unable to create container to store extension state publishers
\n
"
);
return
AST_MODULE_LOAD_DECLINE
;
}
if
(
ast_sip_register_subscription_handler
(
&
presence_handler
))
{
ast_log
(
LOG_WARNING
,
"Unable to register subscription handler %s
\n
"
,
presence_handler
.
event_name
);
unload_module
();
return
AST_MODULE_LOAD_DECLINE
;
}
if
(
ast_sip_register_event_publisher_handler
(
&
presence_publisher
))
{
ast_log
(
LOG_WARNING
,
"Unable to register presence publisher %s
\n
"
,
presence_publisher
.
event_name
);
unload_module
();
return
AST_MODULE_LOAD_DECLINE
;
}
if
(
ast_sip_register_subscription_handler
(
&
dialog_handler
))
{
ast_log
(
LOG_WARNING
,
"Unable to register subscription handler %s
\n
"
,
dialog_handler
.
event_name
);
ast_sip_unregister_subscription_handler
(
&
presence_hand
le
r
);
unload_modu
le
(
);
return
AST_MODULE_LOAD_DECLINE
;
}
return
AST_MODULE_LOAD_SUCCESS
;
}
if
(
ast_sip_register_event_publisher_handler
(
&
dialog_publisher
))
{
ast_log
(
LOG_WARNING
,
"Unable to register presence publisher %s
\n
"
,
dialog_publisher
.
event_name
);
unload_module
();
return
AST_MODULE_LOAD_DECLINE
;
}
static
int
unload_module
(
void
)
{
ast_sip_unregister_subscription_handler
(
&
dialog_handler
);
ast_sip_unregister_subscription_handler
(
&
presence_handler
);
return
0
;
return
AST_MODULE_LOAD_SUCCESS
;
}
AST_MODULE_INFO
(
ASTERISK_GPL_KEY
,
AST_MODFLAG_LOAD_ORDER
,
"PJSIP Extension State Notifications"
,
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment