Skip to content
GitLab
Explore
Sign in
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
a10bc3e2
Commit
a10bc3e2
authored
8 years ago
by
George Joseph
Committed by
Gerrit Code Review
8 years ago
Browse files
Options
Downloads
Plain Diff
Merge "pjsip_distributor.c: Fix deadlock with TCP type transports."
parents
16f0fa52
b485f6c5
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
res/res_pjsip/pjsip_distributor.c
+174
-42
174 additions, 42 deletions
res/res_pjsip/pjsip_distributor.c
with
174 additions
and
42 deletions
res/res_pjsip/pjsip_distributor.c
+
174
−
42
View file @
a10bc3e2
...
...
@@ -150,62 +150,189 @@ static struct ast_taskprocessor *find_request_serializer(pjsip_rx_data *rdata)
/*! Dialog-specific information the distributor uses */
struct
distributor_dialog_data
{
/*! dialog_associations ao2 container key */
pjsip_dialog
*
dlg
;
/*! Serializer to distribute tasks to for this dialog */
struct
ast_taskprocessor
*
serializer
;
/*! Endpoint associated with this dialog */
struct
ast_sip_endpoint
*
endpoint
;
};
#define DIALOG_ASSOCIATIONS_BUCKETS 251
static
struct
ao2_container
*
dialog_associations
;
/*!
* \internal
* \brief Compute a hash value on an arbitrary buffer.
* \since 13.17.0
*
* \param[in] pos The buffer to add to the hash
* \param[in] len The buffer length to add to the hash
* \param[in] hash The hash value to add to
*
* \details
* This version of the function is for when you need to compute a
* hash of more than one buffer.
*
* This famous hash algorithm was written by Dan Bernstein and is
* commonly used.
*
* \
note Call this with the dialog locked
* \
sa http://www.cse.yorku.ca/~oz/hash.html
*/
static
struct
distributor_dialog_data
*
distributor_dialog_data_alloc
(
pjsip_dialog
*
dlg
)
static
int
buf_hash_add
(
const
char
*
pos
,
size_t
len
,
int
hash
)
{
struct
distributor_dialog_data
*
dist
;
while
(
len
--
)
{
hash
=
hash
*
33
^
*
pos
++
;
}
return
hash
;
}
/*!
* \internal
* \brief Compute a hash value on an arbitrary buffer.
* \since 13.17.0
*
* \param[in] pos The buffer to add to the hash
* \param[in] len The buffer length to add to the hash
*
* \details
* This version of the function is for when you need to compute a
* hash of more than one buffer.
*
* This famous hash algorithm was written by Dan Bernstein and is
* commonly used.
*
* \sa http://www.cse.yorku.ca/~oz/hash.html
*/
static
int
buf_hash
(
const
char
*
pos
,
size_t
len
)
{
return
buf_hash_add
(
pos
,
len
,
5381
);
}
static
int
dialog_associations_hash
(
const
void
*
obj
,
int
flags
)
{
const
struct
distributor_dialog_data
*
object
;
union
{
const
pjsip_dialog
*
dlg
;
const
char
buf
[
sizeof
(
pjsip_dialog
*
)];
}
key
;
switch
(
flags
&
OBJ_SEARCH_MASK
)
{
case
OBJ_SEARCH_KEY
:
key
.
dlg
=
obj
;
break
;
case
OBJ_SEARCH_OBJECT
:
object
=
obj
;
key
.
dlg
=
object
->
dlg
;
break
;
default:
/* Hash can only work on something with a full key. */
ast_assert
(
0
);
return
0
;
}
return
ast_str_hash_restrict
(
buf_hash
(
key
.
buf
,
sizeof
(
key
.
buf
)));
}
dist
=
PJ_POOL_ZALLOC_T
(
dlg
->
pool
,
struct
distributor_dialog_data
);
pjsip_dlg_set_mod_data
(
dlg
,
distributor_mod
.
id
,
dist
);
static
int
dialog_associations_cmp
(
void
*
obj
,
void
*
arg
,
int
flags
)
{
const
struct
distributor_dialog_data
*
object_left
=
obj
;
const
struct
distributor_dialog_data
*
object_right
=
arg
;
const
pjsip_dialog
*
right_key
=
arg
;
int
cmp
=
0
;
return
dist
;
switch
(
flags
&
OBJ_SEARCH_MASK
)
{
case
OBJ_SEARCH_OBJECT
:
right_key
=
object_right
->
dlg
;
/* Fall through */
case
OBJ_SEARCH_KEY
:
if
(
object_left
->
dlg
==
right_key
)
{
cmp
=
CMP_MATCH
;
}
break
;
case
OBJ_SEARCH_PARTIAL_KEY
:
/* There is no such thing for this container. */
ast_assert
(
0
);
break
;
default:
cmp
=
0
;
break
;
}
return
cmp
;
}
void
ast_sip_dialog_set_serializer
(
pjsip_dialog
*
dlg
,
struct
ast_taskprocessor
*
serializer
)
{
struct
distributor_dialog_data
*
dist
;
SCOPED_LOCK
(
lock
,
dlg
,
pjsip_dlg_inc_lock
,
pjsip_dlg_dec_lock
);
dist
=
pjsip_dlg_get_mod_data
(
dlg
,
distributor_mod
.
id
);
ao2_wrlock
(
dialog_associations
);
dist
=
ao2_find
(
dialog_associations
,
dlg
,
OBJ_SEARCH_KEY
|
OBJ_NOLOCK
);
if
(
!
dist
)
{
dist
=
distributor_dialog_data_alloc
(
dlg
);
if
(
serializer
)
{
dist
=
ao2_alloc
(
sizeof
(
*
dist
),
NULL
);
if
(
dist
)
{
dist
->
dlg
=
dlg
;
dist
->
serializer
=
serializer
;
ao2_link_flags
(
dialog_associations
,
dist
,
OBJ_NOLOCK
);
ao2_ref
(
dist
,
-
1
);
}
}
}
else
{
ao2_lock
(
dist
);
dist
->
serializer
=
serializer
;
if
(
!
dist
->
serializer
&&
!
dist
->
endpoint
)
{
ao2_unlink_flags
(
dialog_associations
,
dist
,
OBJ_NOLOCK
);
}
ao2_unlock
(
dist
);
ao2_ref
(
dist
,
-
1
);
}
dist
->
serializer
=
serializer
;
ao2_unlock
(
dialog_associations
)
;
}
void
ast_sip_dialog_set_endpoint
(
pjsip_dialog
*
dlg
,
struct
ast_sip_endpoint
*
endpoint
)
{
struct
distributor_dialog_data
*
dist
;
SCOPED_LOCK
(
lock
,
dlg
,
pjsip_dlg_inc_lock
,
pjsip_dlg_dec_lock
);
dist
=
pjsip_dlg_get_mod_data
(
dlg
,
distributor_mod
.
id
);
ao2_wrlock
(
dialog_associations
);
dist
=
ao2_find
(
dialog_associations
,
dlg
,
OBJ_SEARCH_KEY
|
OBJ_NOLOCK
);
if
(
!
dist
)
{
dist
=
distributor_dialog_data_alloc
(
dlg
);
if
(
endpoint
)
{
dist
=
ao2_alloc
(
sizeof
(
*
dist
),
NULL
);
if
(
dist
)
{
dist
->
dlg
=
dlg
;
dist
->
endpoint
=
endpoint
;
ao2_link_flags
(
dialog_associations
,
dist
,
OBJ_NOLOCK
);
ao2_ref
(
dist
,
-
1
);
}
}
}
else
{
ao2_lock
(
dist
);
dist
->
endpoint
=
endpoint
;
if
(
!
dist
->
serializer
&&
!
dist
->
endpoint
)
{
ao2_unlink_flags
(
dialog_associations
,
dist
,
OBJ_NOLOCK
);
}
ao2_unlock
(
dist
);
ao2_ref
(
dist
,
-
1
);
}
dist
->
endpoint
=
endpoint
;
ao2_unlock
(
dialog_associations
)
;
}
struct
ast_sip_endpoint
*
ast_sip_dialog_get_endpoint
(
pjsip_dialog
*
dlg
)
{
struct
distributor_dialog_data
*
dist
;
SCOPED_LOCK
(
lock
,
dlg
,
pjsip_dlg_inc_lock
,
pjsip_dlg_dec_lock
)
;
struct
ast_sip_endpoint
*
endpoint
;
dist
=
pjsip_dlg_get_mod_data
(
dlg
,
distributor_mod
.
id
);
if
(
!
dist
||
!
dist
->
endpoint
)
{
return
NULL
;
dist
=
ao2_find
(
dialog_associations
,
dlg
,
OBJ_SEARCH_KEY
);
if
(
dist
)
{
ao2_lock
(
dist
);
endpoint
=
ao2_bump
(
dist
->
endpoint
);
ao2_unlock
(
dist
);
ao2_ref
(
dist
,
-
1
);
}
else
{
endpoint
=
NULL
;
}
ao2_ref
(
dist
->
endpoint
,
+
1
);
return
dist
->
endpoint
;
return
endpoint
;
}
static
pjsip_dialog
*
find_dialog
(
pjsip_rx_data
*
rdata
)
...
...
@@ -237,7 +364,7 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata)
pjsip_method_cmp
(
&
rdata
->
msg_info
.
msg
->
line
.
req
.
method
,
&
pjsip_cancel_method
)
||
rdata
->
msg_info
.
to
->
tag
.
slen
!=
0
)
{
dlg
=
pjsip_ua_find_dialog
(
&
rdata
->
msg_info
.
cid
->
id
,
local_tag
,
remote_tag
,
PJ_
TRU
E
);
remote_tag
,
PJ_
FALS
E
);
if
(
dlg
)
{
return
dlg
;
}
...
...
@@ -275,11 +402,6 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata)
pj_mutex_unlock
(
tsx
->
mutex
);
#endif
if
(
!
dlg
)
{
return
NULL
;
}
pjsip_dlg_inc_lock
(
dlg
);
return
dlg
;
}
...
...
@@ -302,16 +424,7 @@ static pjsip_dialog *find_dialog(pjsip_rx_data *rdata)
*/
static
int
pjstr_hash_add
(
pj_str_t
*
str
,
int
hash
)
{
size_t
len
;
const
char
*
pos
;
len
=
pj_strlen
(
str
);
pos
=
pj_strbuf
(
str
);
while
(
len
--
)
{
hash
=
hash
*
33
^
*
pos
++
;
}
return
hash
;
return
buf_hash_add
(
pj_strbuf
(
str
),
pj_strlen
(
str
),
hash
);
}
/*!
...
...
@@ -350,7 +463,7 @@ struct ast_taskprocessor *ast_sip_get_distributor_serializer(pjsip_rx_data *rdat
/* Compute the hash from the SIP message call-id and remote-tag */
hash
=
pjstr_hash
(
&
rdata
->
msg_info
.
cid
->
id
);
hash
=
pjstr_hash_add
(
remote_tag
,
hash
);
hash
=
a
b
s
(
hash
);
hash
=
as
t_str_hash_restrict
(
hash
);
serializer
=
ao2_bump
(
distributor_pool
[
hash
%
ARRAY_LEN
(
distributor_pool
)]);
if
(
serializer
)
{
...
...
@@ -385,17 +498,18 @@ static pj_bool_t distributor(pjsip_rx_data *rdata)
dlg
=
find_dialog
(
rdata
);
if
(
dlg
)
{
ast_debug
(
3
,
"Searching for serializer
on
dialog %s for %s
\n
"
,
ast_debug
(
3
,
"Searching for serializer
associated with
dialog %s for %s
\n
"
,
dlg
->
obj_name
,
pjsip_rx_data_get_info
(
rdata
));
dist
=
pjsip_dlg_get_mod_data
(
dlg
,
distributor_mod
.
id
);
dist
=
ao2_find
(
dialog_associations
,
dlg
,
OBJ_SEARCH_KEY
);
if
(
dist
)
{
ao2_lock
(
dist
);
serializer
=
ao2_bump
(
dist
->
serializer
);
ao2_unlock
(
dist
);
if
(
serializer
)
{
ast_debug
(
3
,
"Found serializer %s
on
dialog %s
\n
"
,
ast_debug
(
3
,
"Found serializer %s
associated with
dialog %s
\n
"
,
ast_taskprocessor_name
(
serializer
),
dlg
->
obj_name
);
}
}
pjsip_dlg_dec_lock
(
dlg
);
}
if
(
serializer
)
{
...
...
@@ -417,6 +531,7 @@ static pj_bool_t distributor(pjsip_rx_data *rdata)
/* We have a BYE or CANCEL request without a serializer. */
pjsip_endpt_respond_stateless
(
ast_sip_get_pjsip_endpoint
(),
rdata
,
PJSIP_SC_CALL_TSX_DOES_NOT_EXIST
,
NULL
,
NULL
,
NULL
);
ao2_cleanup
(
dist
);
return
PJ_TRUE
;
}
else
{
if
(
ast_taskprocessor_alert_get
())
{
...
...
@@ -431,6 +546,7 @@ static pj_bool_t distributor(pjsip_rx_data *rdata)
*/
ast_debug
(
3
,
"Taskprocessor overload alert: Ignoring '%s'.
\n
"
,
pjsip_rx_data_get_info
(
rdata
));
ao2_cleanup
(
dist
);
return
PJ_TRUE
;
}
...
...
@@ -438,10 +554,17 @@ static pj_bool_t distributor(pjsip_rx_data *rdata)
serializer
=
ast_sip_get_distributor_serializer
(
rdata
);
}
pjsip_rx_data_clone
(
rdata
,
0
,
&
clone
);
if
(
pjsip_rx_data_clone
(
rdata
,
0
,
&
clone
)
!=
PJ_SUCCESS
)
{
ast_taskprocessor_unreference
(
serializer
);
ao2_cleanup
(
dist
);
return
PJ_TRUE
;
}
if
(
dist
)
{
ao2_lock
(
dist
);
clone
->
endpt_info
.
mod_data
[
endpoint_mod
.
id
]
=
ao2_bump
(
dist
->
endpoint
);
ao2_unlock
(
dist
);
ao2_cleanup
(
dist
);
}
if
(
ast_sip_push_task
(
serializer
,
distribute
,
clone
))
{
...
...
@@ -1088,6 +1211,14 @@ int ast_sip_initialize_distributor(void)
return
-
1
;
}
dialog_associations
=
ao2_container_alloc_hash
(
AO2_ALLOC_OPT_LOCK_RWLOCK
,
0
,
DIALOG_ASSOCIATIONS_BUCKETS
,
dialog_associations_hash
,
NULL
,
dialog_associations_cmp
);
if
(
!
dialog_associations
)
{
ast_sip_destroy_distributor
();
return
-
1
;
}
if
(
distributor_pool_setup
())
{
ast_sip_destroy_distributor
();
return
-
1
;
...
...
@@ -1166,5 +1297,6 @@ void ast_sip_destroy_distributor(void)
distributor_pool_shutdown
();
ao2_cleanup
(
dialog_associations
);
ao2_cleanup
(
unidentified_requests
);
}
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