summaryrefslogtreecommitdiff
path: root/res/res_sorcery_memory.c
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2016-02-15 13:08:22 -0600
committerMark Michelson <mmichelson@digium.com>2016-02-15 13:46:18 -0600
commitebe167f79267e5e071911d583df58a42bf5d1153 (patch)
tree202aaa70cbc3e5969b5c8067d3e9ccdfa5be585b /res/res_sorcery_memory.c
parent1cddd954f90955c3805b5dfe5313d33a1d3e1ac9 (diff)
Fix creation race of contact_status structures.
It is possible when processing a SIP REGISTER request to have two threads end up creating contact_status structures in sorcery. contact_status is created using a "find or create" function. If two threads call into this at the same time, each thread will fail to find an existing contact_status, and so both will end up creating a new contact status. During testing, we would see sporadic failures because the PJSIP_CONTACT() dialplan function would operate on a different contact_status than what had been updated by res_pjsip/pjsip_options. The fix here is two-fold: 1) The "find or create" function for contact_status now has a lock around the entire operation. This way, if two threads attempt the operation simultaneously, the first to get there will create the object, and the second will find the object created by the first thread. 2) res_sorcery_memory has had its create callback updated so that it will not allow for objects with duplicate IDs to be created. Change-Id: I55b1460ff1eb0af0a3697b82d7c2bac9f6af5b97
Diffstat (limited to 'res/res_sorcery_memory.c')
-rw-r--r--res/res_sorcery_memory.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c
index 7d398c2eb..45bde26f9 100644
--- a/res/res_sorcery_memory.c
+++ b/res/res_sorcery_memory.c
@@ -98,7 +98,21 @@ static int sorcery_memory_cmp(void *obj, void *arg, int flags)
static int sorcery_memory_create(const struct ast_sorcery *sorcery, void *data, void *object)
{
- ao2_link(data, object);
+ void *existing;
+
+ ao2_lock(data);
+
+ existing = ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_NOLOCK);
+ if (existing) {
+ ao2_ref(existing, -1);
+ ao2_unlock(data);
+ return -1;
+ }
+
+ ao2_link_flags(data, object, OBJ_NOLOCK);
+
+ ao2_unlock(data);
+
return 0;
}