pjsip: race condition in registrar
[asterisk/asterisk.git] / res / res_pjsip_registrar.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*** MODULEINFO
20         <depend>pjproject</depend>
21         <depend>res_pjsip</depend>
22         <support_level>core</support_level>
23  ***/
24
25 #include "asterisk.h"
26
27 #include <pjsip.h>
28 #include <pjsip_ua.h>
29
30 #include "asterisk/res_pjsip.h"
31 #include "asterisk/module.h"
32 #include "asterisk/test.h"
33 #include "asterisk/taskprocessor.h"
34
35 /*! \brief Internal function which returns the expiration time for a contact */
36 static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
37 {
38         pjsip_expires_hdr *expires;
39         int expiration = aor->default_expiration;
40
41         if (contact->expires != -1) {
42                 /* Expiration was provided with the contact itself */
43                 expiration = contact->expires;
44         } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
45                 /* Expiration was provided using the Expires header */
46                 expiration = expires->ivalue;
47         }
48
49         /* If the value has explicitly been set to 0, do not enforce */
50         if (!expiration) {
51                 return expiration;
52         }
53
54         /* Enforce the range that we will allow for expiration */
55         if (expiration < aor->minimum_expiration) {
56                 expiration = aor->minimum_expiration;
57         } else if (expiration > aor->maximum_expiration) {
58                 expiration = aor->maximum_expiration;
59         }
60
61         return expiration;
62 }
63
64 /*! \brief Structure used for finding contact */
65 struct registrar_contact_details {
66         /*! \brief Pool used for parsing URI */
67         pj_pool_t *pool;
68         /*! \brief URI being looked for */
69         pjsip_uri *uri;
70 };
71
72 /*! \brief Callback function for finding a contact */
73 static int registrar_find_contact(void *obj, void *arg, int flags)
74 {
75         struct ast_sip_contact *contact = obj;
76         const struct registrar_contact_details *details = arg;
77         pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
78
79         return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH | CMP_STOP : 0;
80 }
81
82 /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
83 static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
84 {
85         pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
86         struct registrar_contact_details details = {
87                 .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
88         };
89
90         if (!details.pool) {
91                 return -1;
92         }
93
94         while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
95                 int expiration = registrar_get_expiration(aor, contact, rdata);
96                 RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
97
98                 if (contact->star) {
99                         /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
100                         if ((expiration != 0) || previous) {
101                                 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
102                                 return -1;
103                         }
104                         continue;
105                 } else if (previous && previous->star) {
106                         /* If there is a previous contact and it is a '*' this is a deal breaker */
107                         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
108                         return -1;
109                 }
110                 previous = contact;
111
112                 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
113                         continue;
114                 }
115
116                 details.uri = pjsip_uri_get_uri(contact->uri);
117
118                 /* Determine if this is an add, update, or delete for policy enforcement purposes */
119                 if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
120                         if (expiration) {
121                                 (*added)++;
122                         }
123                 } else if (expiration) {
124                         (*updated)++;
125                 } else {
126                         (*deleted)++;
127                 }
128         }
129
130         /* The provided contacts are acceptable, huzzah! */
131         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
132         return 0;
133 }
134
135 /*! \brief Callback function which prunes static contacts */
136 static int registrar_prune_static(void *obj, void *arg, int flags)
137 {
138         struct ast_sip_contact *contact = obj;
139
140         return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
141 }
142
143 /*! \brief Internal function used to delete all contacts from an AOR */
144 static int registrar_delete_contact(void *obj, void *arg, int flags)
145 {
146         struct ast_sip_contact *contact = obj;
147         const char *aor_name = arg;
148
149         ast_sip_location_delete_contact(contact);
150         if (!ast_strlen_zero(aor_name)) {
151                 ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
152                 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
153                                 "Contact: %s\r\n"
154                                 "AOR: %s",
155                                 contact->uri,
156                                 aor_name);
157         }
158
159         return 0;
160 }
161
162 /*! \brief Internal function which adds a contact to a response */
163 static int registrar_add_contact(void *obj, void *arg, int flags)
164 {
165         struct ast_sip_contact *contact = obj;
166         pjsip_tx_data *tdata = arg;
167         pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
168         pj_str_t uri;
169
170         pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
171         hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
172         hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
173
174         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
175
176         return 0;
177 }
178
179 /*! \brief Helper function which adds a Date header to a response */
180 static void registrar_add_date_header(pjsip_tx_data *tdata)
181 {
182         char date[256];
183         struct tm tm;
184         time_t t = time(NULL);
185
186         gmtime_r(&t, &tm);
187         strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
188
189         ast_sip_add_header(tdata, "Date", date);
190 }
191
192 #define SERIALIZER_BUCKETS 59
193
194 static struct ao2_container *serializers;
195
196 /*! \brief Serializer with associated aor key */
197 struct serializer {
198         /* Serializer to distribute tasks to */
199         struct ast_taskprocessor *serializer;
200         /* The name of the aor to associate with the serializer */
201         char aor_name[0];
202 };
203
204 static void serializer_destroy(void *obj)
205 {
206         struct serializer *ser = obj;
207
208         ast_taskprocessor_unreference(ser->serializer);
209 }
210
211 static struct serializer *serializer_create(const char *aor_name)
212 {
213         size_t size = strlen(aor_name) + 1;
214         struct serializer *ser = ao2_alloc(
215                 sizeof(*ser) + size, serializer_destroy);
216
217         if (!ser) {
218                 return NULL;
219         }
220
221         if (!(ser->serializer = ast_sip_create_serializer())) {
222                 ao2_ref(ser, -1);
223                 return NULL;
224         }
225
226         strcpy(ser->aor_name, aor_name);
227         return ser;
228 }
229
230 static struct serializer *serializer_find_or_create(const char *aor_name)
231 {
232         struct serializer *ser = ao2_find(serializers, aor_name, OBJ_SEARCH_KEY);
233
234         if (ser) {
235                 return ser;
236         }
237
238         if (!(ser = serializer_create(aor_name))) {
239                 return NULL;
240         }
241
242         ao2_link(serializers, ser);
243         return ser;
244 }
245
246 static int serializer_hash(const void *obj, const int flags)
247 {
248         const struct serializer *object;
249         const char *key;
250
251         switch (flags & OBJ_SEARCH_MASK) {
252         case OBJ_SEARCH_KEY:
253                 key = obj;
254                 return ast_str_hash(key);
255         case OBJ_SEARCH_OBJECT:
256                 object = obj;
257                 return ast_str_hash(object->aor_name);
258         default:
259                 /* Hash can only work on something with a full key. */
260                 ast_assert(0);
261                 return 0;
262         }
263 }
264
265 static int serializer_cmp(void *obj_left, void *obj_right, int flags)
266 {
267         const struct serializer *object_left = obj_left;
268         const struct serializer *object_right = obj_right;
269         const char *right_key = obj_right;
270         int cmp;
271
272         switch (flags & OBJ_SEARCH_MASK) {
273         case OBJ_SEARCH_OBJECT:
274                 right_key = object_right->aor_name;
275                 /* Fall through */
276         case OBJ_SEARCH_KEY:
277                 cmp = strcmp(object_left->aor_name, right_key);
278                 break;
279         case OBJ_SEARCH_PARTIAL_KEY:
280                 /*
281                  * We could also use a partial key struct containing a length
282                  * so strlen() does not get called for every comparison instead.
283                  */
284                 cmp = strncmp(object_left->aor_name, right_key, strlen(right_key));
285                 break;
286         default:
287                 cmp = 0;
288                 break;
289         }
290
291         return cmp ? 0 : CMP_MATCH;
292 }
293
294 struct rx_task_data {
295         pjsip_rx_data *rdata;
296         struct ast_sip_endpoint *endpoint;
297         struct ast_sip_aor *aor;
298 };
299
300 static void rx_task_data_destroy(void *obj)
301 {
302         struct rx_task_data *task_data = obj;
303
304         pjsip_rx_data_free_cloned(task_data->rdata);
305         ao2_cleanup(task_data->endpoint);
306         ao2_cleanup(task_data->aor);
307 }
308
309 static struct rx_task_data *rx_task_data_create(pjsip_rx_data *rdata,
310                                                 struct ast_sip_endpoint *endpoint,
311                                                 struct ast_sip_aor *aor)
312 {
313         struct rx_task_data *task_data = ao2_alloc(
314                 sizeof(*task_data), rx_task_data_destroy);
315
316         if (!task_data) {
317                 return NULL;
318         }
319
320         pjsip_rx_data_clone(rdata, 0, &task_data->rdata);
321
322         task_data->endpoint = endpoint;
323         ao2_ref(task_data->endpoint, +1);
324
325         task_data->aor = aor;
326         ao2_ref(task_data->aor, +1);
327
328         return task_data;
329 }
330
331 static int rx_task(void *data)
332 {
333         RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
334         RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
335
336         int added = 0, updated = 0, deleted = 0;
337         pjsip_contact_hdr *contact_hdr = NULL;
338         struct registrar_contact_details details = { 0, };
339         pjsip_tx_data *tdata;
340         pjsip_response_addr addr;
341         const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
342
343         /* Retrieve the current contacts, we'll need to know whether to update or not */
344         contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
345
346         /* So we don't count static contacts against max_contacts we prune them out from the container */
347         ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
348
349         if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) {
350                 /* The provided Contact headers do not conform to the specification */
351                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL);
352                 ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided");
353                 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
354                                 ast_sorcery_object_get_id(task_data->endpoint));
355                 return PJ_TRUE;
356         }
357
358         if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) {
359                 /* Enforce the maximum number of contacts */
360                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL);
361                 ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
362                 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %d\n",
363                                 ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts);
364                 return PJ_TRUE;
365         }
366
367         if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
368                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL);
369                 return PJ_TRUE;
370         }
371
372         /* Iterate each provided Contact header and add, update, or delete */
373         while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
374                 int expiration;
375                 char contact_uri[PJSIP_MAX_URL_SIZE];
376                 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
377
378                 if (contact_hdr->star) {
379                         /* A star means to unregister everything, so do so for the possible contacts */
380                         ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name);
381                         break;
382                 }
383
384                 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
385                         /* This registrar only currently supports sip: and sips: URI schemes */
386                         continue;
387                 }
388
389                 expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata);
390                 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
391                 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
392
393                 if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
394                         /* If they are actually trying to delete a contact that does not exist... be forgiving */
395                         if (!expiration) {
396                                 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
397                                         contact_uri, aor_name);
398                                 continue;
399                         }
400
401                         ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
402                         ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
403                                 contact_uri, aor_name, expiration);
404                         ast_test_suite_event_notify("AOR_CONTACT_ADDED",
405                                         "Contact: %s\r\n"
406                                         "AOR: %s\r\n"
407                                         "Expiration: %d",
408                                         contact_uri,
409                                         aor_name,
410                                         expiration);
411                 } else if (expiration) {
412                         RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
413                         updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
414                         updated->qualify_frequency = task_data->aor->qualify_frequency;
415                         updated->authenticate_qualify = task_data->aor->authenticate_qualify;
416
417                         ast_sip_location_update_contact(updated);
418                         ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
419                                 contact_uri, aor_name, expiration);
420                         ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
421                                         "Contact: %s\r\n"
422                                         "AOR: %s\r\n"
423                                         "Expiration: %d",
424                                         contact_uri,
425                                         aor_name,
426                                         expiration);
427                 } else {
428                         ast_sip_location_delete_contact(contact);
429                         ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
430                         ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
431                                         "Contact: %s\r\n"
432                                         "AOR: %s",
433                                         contact_uri,
434                                         aor_name);
435                 }
436         }
437
438         pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
439
440         /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
441          * do so
442          */
443         if (task_data->aor->remove_existing) {
444                 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
445         }
446
447         /* Update the contacts as things will probably have changed */
448         ao2_cleanup(contacts);
449         contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
450
451         /* Send a response containing all of the contacts (including static) that are present on this AOR */
452         if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), task_data->rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
453                 return PJ_TRUE;
454         }
455
456         /* Add the date header to the response, some UAs use this to set their date and time */
457         registrar_add_date_header(tdata);
458
459         ao2_callback(contacts, 0, registrar_add_contact, tdata);
460
461         if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
462                 pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL);
463         } else {
464                 pjsip_tx_data_dec_ref(tdata);
465         }
466
467         return PJ_TRUE;
468 }
469
470 static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
471 {
472         RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
473         struct rx_task_data *task_data;
474
475         RAII_VAR(struct ast_sip_endpoint *, endpoint,
476                  ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
477         RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
478         pjsip_sip_uri *uri;
479         char user_name[64], domain_name[64];
480         char *configured_aors, *aor_name;
481
482         if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
483                 return PJ_FALSE;
484         }
485
486         if (ast_strlen_zero(endpoint->aors)) {
487                 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
488                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
489                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
490                 ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint));
491                 return PJ_TRUE;
492         }
493
494         if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
495                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
496                 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
497                 ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint));
498                 return PJ_TRUE;
499         }
500
501         uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
502         ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
503         ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));
504
505         configured_aors = ast_strdupa(endpoint->aors);
506
507         /* Iterate the configured AORs to see if the user or the user+domain match */
508         while ((aor_name = strsep(&configured_aors, ","))) {
509                 char id[AST_UUID_STR_LEN];
510                 RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
511
512                 snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
513                 if (!strcmp(aor_name, id)) {
514                         break;
515                 }
516
517                 if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
518                         snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
519                         if (!strcmp(aor_name, id)) {
520                                 break;
521                         }
522                 }
523
524                 if (!strcmp(aor_name, user_name)) {
525                         break;
526                 }
527         }
528
529         if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
530                 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
531                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
532                 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
533                 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint));
534                 return PJ_TRUE;
535         }
536
537         if (!aor->max_contacts) {
538                 /* Registration is not permitted for this AOR */
539                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
540                 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
541                 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n",
542                                 ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint));
543                 return PJ_TRUE;
544         }
545
546         if (!(ser = serializer_find_or_create(aor_name))) {
547                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
548                 ast_sip_report_mem_limit(endpoint, rdata);
549                 ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n",
550                         ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
551                 return PJ_TRUE;
552         }
553
554         if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) {
555                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
556                 ast_sip_report_mem_limit(endpoint, rdata);
557                 ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n",
558                         ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
559                 return PJ_TRUE;
560         }
561
562         if (ast_sip_push_task(ser->serializer, rx_task, task_data)) {
563                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
564                 ast_sip_report_mem_limit(endpoint, rdata);
565                 ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n",
566                         ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor));
567                 ao2_ref(task_data, -1);
568         }
569         return PJ_TRUE;
570 }
571
572 static pjsip_module registrar_module = {
573         .name = { "Registrar", 9 },
574         .id = -1,
575         .priority = PJSIP_MOD_PRIORITY_APPLICATION,
576         .on_rx_request = registrar_on_rx_request,
577 };
578
579 static int load_module(void)
580 {
581         const pj_str_t STR_REGISTER = { "REGISTER", 8 };
582
583         if (!(serializers = ao2_container_alloc(
584                       SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) {
585                 return AST_MODULE_LOAD_DECLINE;
586         }
587
588         if (ast_sip_register_service(&registrar_module)) {
589                 return AST_MODULE_LOAD_DECLINE;
590         }
591
592         if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
593                 ast_sip_unregister_service(&registrar_module);
594                 return AST_MODULE_LOAD_DECLINE;
595         }
596
597         return AST_MODULE_LOAD_SUCCESS;
598 }
599
600 static int unload_module(void)
601 {
602         ast_sip_unregister_service(&registrar_module);
603
604         ao2_cleanup(serializers);
605         return 0;
606 }
607
608 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Support",
609                 .load = load_module,
610                 .unload = unload_module,
611                 .load_pri = AST_MODPRI_APP_DEPEND,
612                );