Merge "res_pjsip_notify: improve realtime performance on CLI completion on the endpoint"
[asterisk/asterisk.git] / res / res_pjsip / config_global.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@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 #include "asterisk.h"
20
21 #include <pjsip.h>
22 #include <pjlib.h>
23
24 #include "asterisk/res_pjsip.h"
25 #include "include/res_pjsip_private.h"
26 #include "asterisk/sorcery.h"
27 #include "asterisk/taskprocessor.h"
28 #include "asterisk/ast_version.h"
29 #include "asterisk/res_pjsip_cli.h"
30
31 #define DEFAULT_MAX_FORWARDS 70
32 #define DEFAULT_KEEPALIVE_INTERVAL 90
33 #define DEFAULT_USERAGENT_PREFIX "Asterisk PBX"
34 #define DEFAULT_OUTBOUND_ENDPOINT "default_outbound_endpoint"
35 #define DEFAULT_DEBUG "no"
36 #define DEFAULT_ENDPOINT_IDENTIFIER_ORDER "ip,username,anonymous"
37 #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0
38 #define DEFAULT_FROM_USER "asterisk"
39 #define DEFAULT_REALM "asterisk"
40 #define DEFAULT_REGCONTEXT ""
41 #define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30
42 #define DEFAULT_DISABLE_MULTI_DOMAIN 0
43 #define DEFAULT_VOICEMAIL_EXTENSION ""
44 #define DEFAULT_UNIDENTIFIED_REQUEST_COUNT 5
45 #define DEFAULT_UNIDENTIFIED_REQUEST_PERIOD 5
46 #define DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL 30
47 #define DEFAULT_MWI_TPS_QUEUE_HIGH AST_TASKPROCESSOR_HIGH_WATER_LEVEL
48 #define DEFAULT_MWI_TPS_QUEUE_LOW -1
49 #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0
50 #define DEFAULT_IGNORE_URI_USER_OPTIONS 0
51 #define DEFAULT_USE_CALLERID_CONTACT 0
52
53 /*!
54  * \brief Cached global config object
55  *
56  * \details
57  * Cached so we don't have to keep asking sorcery for the config.
58  * We could ask for it hundreds of times a second if not more.
59  */
60 static AO2_GLOBAL_OBJ_STATIC(global_cfg);
61
62 static char default_useragent[256];
63
64 struct global_config {
65         SORCERY_OBJECT(details);
66         AST_DECLARE_STRING_FIELDS(
67                 AST_STRING_FIELD(useragent);
68                 AST_STRING_FIELD(regcontext);
69                 AST_STRING_FIELD(default_outbound_endpoint);
70                 /*! Debug logging yes|no|host */
71                 AST_STRING_FIELD(debug);
72                 /*! Order by which endpoint identifiers are checked (comma separated list) */
73                 AST_STRING_FIELD(endpoint_identifier_order);
74                 /*! User name to place in From header if there is no better option */
75                 AST_STRING_FIELD(default_from_user);
76                 /*! Default voicemail extension */
77                 AST_STRING_FIELD(default_voicemail_extension);
78                 /*! Realm to use in challenges before an endpoint is identified */
79                 AST_STRING_FIELD(default_realm);
80         );
81         /*! Value to put in Max-Forwards header */
82         unsigned int max_forwards;
83         /*! The interval at which to send keep alive messages to active connection-oriented transports */
84         unsigned int keep_alive_interval;
85         /*! The maximum time for all contacts to be qualified at startup */
86         unsigned int max_initial_qualify_time;
87         /*! The interval at which to check for expired contacts */
88         unsigned int contact_expiration_check_interval;
89         /*! Nonzero to disable multi domain support */
90         unsigned int disable_multi_domain;
91         /*! The maximum number of unidentified requests per source IP address before a security event is logged */
92         unsigned int unidentified_request_count;
93         /*! The period during which unidentified requests are accumulated */
94         unsigned int unidentified_request_period;
95         /*! Interval at which expired unidentifed requests will be pruned */
96         unsigned int unidentified_request_prune_interval;
97         struct {
98                 /*! Taskprocessor high water alert trigger level */
99                 unsigned int tps_queue_high;
100                 /*! Taskprocessor low water clear alert level. */
101                 int tps_queue_low;
102                 /*! Nonzero to disable sending unsolicited mwi to all endpoints on startup */
103                 unsigned int disable_initial_unsolicited;
104         } mwi;
105         /*! Nonzero if URI user field options are ignored. */
106         unsigned int ignore_uri_user_options;
107         /*! Nonzero if CALLERID(num) is to be used as the default contact username instead of default_from_user */
108         unsigned int use_callerid_contact;
109 };
110
111 static void global_destructor(void *obj)
112 {
113         struct global_config *cfg = obj;
114
115         ast_string_field_free_memory(cfg);
116 }
117
118 static void *global_alloc(const char *name)
119 {
120         struct global_config *cfg;
121
122         cfg = ast_sorcery_generic_alloc(sizeof(*cfg), global_destructor);
123         if (!cfg || ast_string_field_init(cfg, 100)) {
124                 ao2_cleanup(cfg);
125                 return NULL;
126         }
127
128         return cfg;
129 }
130
131 static int global_apply(const struct ast_sorcery *sorcery, void *obj)
132 {
133         struct global_config *cfg = obj;
134         char max_forwards[10];
135
136         if (ast_strlen_zero(cfg->debug)) {
137                 ast_log(LOG_ERROR,
138                         "Global option 'debug' can't be empty.  Set it to a valid value or remove the entry to accept 'no' as the default\n");
139                 return -1;
140         }
141
142         if (ast_strlen_zero(cfg->default_from_user)) {
143                 ast_log(LOG_ERROR,
144                         "Global option 'default_from_user' can't be empty.  Set it to a valid value or remove the entry to accept 'asterisk' as the default\n");
145                 return -1;
146         }
147
148         snprintf(max_forwards, sizeof(max_forwards), "%u", cfg->max_forwards);
149
150         ast_sip_add_global_request_header("Max-Forwards", max_forwards, 1);
151         ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1);
152         ast_sip_add_global_response_header("Server", cfg->useragent, 1);
153
154         ao2_t_global_obj_replace_unref(global_cfg, cfg, "Applying global settings");
155         return 0;
156 }
157
158 static struct global_config *get_global_cfg(void)
159 {
160         return ao2_global_obj_ref(global_cfg);
161 }
162
163 char *ast_sip_global_default_outbound_endpoint(void)
164 {
165         char *str;
166         struct global_config *cfg;
167
168         cfg = get_global_cfg();
169         if (!cfg) {
170                 return ast_strdup(DEFAULT_OUTBOUND_ENDPOINT);
171         }
172
173         str = ast_strdup(cfg->default_outbound_endpoint);
174         ao2_ref(cfg, -1);
175         return str;
176 }
177
178 char *ast_sip_get_debug(void)
179 {
180         char *res;
181         struct global_config *cfg;
182
183         cfg = get_global_cfg();
184         if (!cfg) {
185                 return ast_strdup(DEFAULT_DEBUG);
186         }
187
188         res = ast_strdup(cfg->debug);
189         ao2_ref(cfg, -1);
190         return res;
191 }
192
193 char *ast_sip_get_regcontext(void)
194 {
195         char *res;
196         struct global_config *cfg;
197
198         cfg = get_global_cfg();
199         if (!cfg) {
200                 return ast_strdup(DEFAULT_REGCONTEXT);
201         }
202
203         res = ast_strdup(cfg->regcontext);
204         ao2_ref(cfg, -1);
205
206         return res;
207 }
208
209 char *ast_sip_get_default_voicemail_extension(void)
210 {
211         char *res;
212         struct global_config *cfg;
213
214         cfg = get_global_cfg();
215         if (!cfg) {
216                 return ast_strdup(DEFAULT_VOICEMAIL_EXTENSION);
217         }
218
219         res = ast_strdup(cfg->default_voicemail_extension);
220         ao2_ref(cfg, -1);
221
222         return res;
223 }
224
225 char *ast_sip_get_endpoint_identifier_order(void)
226 {
227         char *res;
228         struct global_config *cfg;
229
230         cfg = get_global_cfg();
231         if (!cfg) {
232                 return ast_strdup(DEFAULT_ENDPOINT_IDENTIFIER_ORDER);
233         }
234
235         res = ast_strdup(cfg->endpoint_identifier_order);
236         ao2_ref(cfg, -1);
237         return res;
238 }
239
240 unsigned int ast_sip_get_keep_alive_interval(void)
241 {
242         unsigned int interval;
243         struct global_config *cfg;
244
245         cfg = get_global_cfg();
246         if (!cfg) {
247                 return DEFAULT_KEEPALIVE_INTERVAL;
248         }
249
250         interval = cfg->keep_alive_interval;
251         ao2_ref(cfg, -1);
252         return interval;
253 }
254
255 unsigned int ast_sip_get_contact_expiration_check_interval(void)
256 {
257         unsigned int interval;
258         struct global_config *cfg;
259
260         cfg = get_global_cfg();
261         if (!cfg) {
262                 return DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL;
263         }
264
265         interval = cfg->contact_expiration_check_interval;
266         ao2_ref(cfg, -1);
267         return interval;
268 }
269
270 unsigned int ast_sip_get_disable_multi_domain(void)
271 {
272         unsigned int disable_multi_domain;
273         struct global_config *cfg;
274
275         cfg = get_global_cfg();
276         if (!cfg) {
277                 return DEFAULT_DISABLE_MULTI_DOMAIN;
278         }
279
280         disable_multi_domain = cfg->disable_multi_domain;
281         ao2_ref(cfg, -1);
282         return disable_multi_domain;
283 }
284
285 unsigned int ast_sip_get_max_initial_qualify_time(void)
286 {
287         unsigned int time;
288         struct global_config *cfg;
289
290         cfg = get_global_cfg();
291         if (!cfg) {
292                 return DEFAULT_MAX_INITIAL_QUALIFY_TIME;
293         }
294
295         time = cfg->max_initial_qualify_time;
296         ao2_ref(cfg, -1);
297         return time;
298 }
299
300 void ast_sip_get_unidentified_request_thresholds(unsigned int *count, unsigned int *period,
301         unsigned int *prune_interval)
302 {
303         struct global_config *cfg;
304
305         cfg = get_global_cfg();
306         if (!cfg) {
307                 *count = DEFAULT_UNIDENTIFIED_REQUEST_COUNT;
308                 *period = DEFAULT_UNIDENTIFIED_REQUEST_PERIOD;
309                 *prune_interval = DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL;
310                 return;
311         }
312
313         *count = cfg->unidentified_request_count;
314         *period = cfg->unidentified_request_period;
315         *prune_interval = cfg->unidentified_request_prune_interval;
316
317         ao2_ref(cfg, -1);
318         return;
319 }
320
321 void ast_sip_get_default_realm(char *realm, size_t size)
322 {
323         struct global_config *cfg;
324
325         cfg = get_global_cfg();
326         if (!cfg) {
327                 ast_copy_string(realm, DEFAULT_REALM, size);
328         } else {
329                 ast_copy_string(realm, cfg->default_realm, size);
330                 ao2_ref(cfg, -1);
331         }
332 }
333
334 void ast_sip_get_default_from_user(char *from_user, size_t size)
335 {
336         struct global_config *cfg;
337
338         cfg = get_global_cfg();
339         if (!cfg) {
340                 ast_copy_string(from_user, DEFAULT_FROM_USER, size);
341         } else {
342                 ast_copy_string(from_user, cfg->default_from_user, size);
343                 ao2_ref(cfg, -1);
344         }
345 }
346
347
348 unsigned int ast_sip_get_mwi_tps_queue_high(void)
349 {
350         unsigned int tps_queue_high;
351         struct global_config *cfg;
352
353         cfg = get_global_cfg();
354         if (!cfg) {
355                 return DEFAULT_MWI_TPS_QUEUE_HIGH;
356         }
357
358         tps_queue_high = cfg->mwi.tps_queue_high;
359         ao2_ref(cfg, -1);
360         return tps_queue_high;
361 }
362
363 int ast_sip_get_mwi_tps_queue_low(void)
364 {
365         int tps_queue_low;
366         struct global_config *cfg;
367
368         cfg = get_global_cfg();
369         if (!cfg) {
370                 return DEFAULT_MWI_TPS_QUEUE_LOW;
371         }
372
373         tps_queue_low = cfg->mwi.tps_queue_low;
374         ao2_ref(cfg, -1);
375         return tps_queue_low;
376 }
377
378 unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void)
379 {
380         unsigned int disable_initial_unsolicited;
381         struct global_config *cfg;
382
383         cfg = get_global_cfg();
384         if (!cfg) {
385                 return DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED;
386         }
387
388         disable_initial_unsolicited = cfg->mwi.disable_initial_unsolicited;
389         ao2_ref(cfg, -1);
390         return disable_initial_unsolicited;
391 }
392
393 unsigned int ast_sip_get_ignore_uri_user_options(void)
394 {
395         unsigned int ignore_uri_user_options;
396         struct global_config *cfg;
397
398         cfg = get_global_cfg();
399         if (!cfg) {
400                 return DEFAULT_IGNORE_URI_USER_OPTIONS;
401         }
402
403         ignore_uri_user_options = cfg->ignore_uri_user_options;
404         ao2_ref(cfg, -1);
405         return ignore_uri_user_options;
406 }
407
408 unsigned int ast_sip_get_use_callerid_contact(void)
409 {
410         unsigned int use_callerid_contact;
411         struct global_config *cfg;
412
413         cfg = get_global_cfg();
414         if (!cfg) {
415                 return DEFAULT_USE_CALLERID_CONTACT;
416         }
417
418         use_callerid_contact = cfg->use_callerid_contact;
419         ao2_ref(cfg, -1);
420         return use_callerid_contact;
421 }
422
423 /*!
424  * \internal
425  * \brief Observer to set default global object if none exist.
426  *
427  * \param name Module name owning the sorcery instance.
428  * \param sorcery Instance being observed.
429  * \param object_type Name of object being observed.
430  * \param reloaded Non-zero if the object is being reloaded.
431  *
432  * \return Nothing
433  */
434 static void global_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
435 {
436         struct ao2_container *globals;
437         struct global_config *cfg;
438
439         if (strcmp(object_type, "global")) {
440                 /* Not interested */
441                 return;
442         }
443
444         globals = ast_sorcery_retrieve_by_fields(sorcery, "global",
445                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
446         if (globals) {
447                 int count;
448
449                 count = ao2_container_count(globals);
450                 ao2_ref(globals, -1);
451
452                 if (1 < count) {
453                         ast_log(LOG_ERROR,
454                                 "At most one pjsip.conf type=global object can be defined.  You have %d defined.\n",
455                                 count);
456                         return;
457                 }
458                 if (count) {
459                         return;
460                 }
461         }
462
463         ast_debug(1, "No pjsip.conf type=global object exists so applying defaults.\n");
464         cfg = ast_sorcery_alloc(sorcery, "global", NULL);
465         if (!cfg) {
466                 return;
467         }
468         global_apply(sorcery, cfg);
469         ao2_ref(cfg, -1);
470 }
471
472 static const struct ast_sorcery_instance_observer observer_callbacks_global = {
473         .object_type_loaded = global_loaded_observer,
474 };
475
476 int sip_cli_print_global(struct ast_sip_cli_context *context)
477 {
478         struct global_config *cfg = get_global_cfg();
479
480         if (!cfg) {
481                 cfg = ast_sorcery_alloc(ast_sip_get_sorcery(), "global", NULL);
482                 if (!cfg) {
483                         return -1;
484                 }
485         }
486
487         ast_str_append(&context->output_buffer, 0, "\nGlobal Settings:\n\n");
488         ast_sip_cli_print_sorcery_objectset(cfg, context, 0);
489
490         ao2_ref(cfg, -1);
491         return 0;
492 }
493
494 int ast_sip_destroy_sorcery_global(void)
495 {
496         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
497
498         ast_sorcery_instance_observer_remove(sorcery, &observer_callbacks_global);
499
500         ao2_t_global_obj_release(global_cfg, "Module is unloading");
501
502         return 0;
503 }
504
505 int ast_sip_initialize_sorcery_global(void)
506 {
507         struct ast_sorcery *sorcery = ast_sip_get_sorcery();
508
509         snprintf(default_useragent, sizeof(default_useragent), "%s %s",
510                 DEFAULT_USERAGENT_PREFIX, ast_get_version());
511
512         ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global,single_object=yes,explicit_name=global");
513
514         if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {
515                 return -1;
516         }
517
518         ast_sorcery_object_field_register(sorcery, "global", "type", "", OPT_NOOP_T, 0, 0);
519         ast_sorcery_object_field_register(sorcery, "global", "max_forwards",
520                 __stringify(DEFAULT_MAX_FORWARDS),
521                 OPT_UINT_T, 0, FLDSET(struct global_config, max_forwards));
522         ast_sorcery_object_field_register(sorcery, "global", "user_agent", default_useragent,
523                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, useragent));
524         ast_sorcery_object_field_register(sorcery, "global", "default_outbound_endpoint",
525                 DEFAULT_OUTBOUND_ENDPOINT,
526                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_outbound_endpoint));
527         ast_sorcery_object_field_register(sorcery, "global", "debug", DEFAULT_DEBUG,
528                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, debug));
529         ast_sorcery_object_field_register(sorcery, "global", "endpoint_identifier_order",
530                 DEFAULT_ENDPOINT_IDENTIFIER_ORDER,
531                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, endpoint_identifier_order));
532         ast_sorcery_object_field_register(sorcery, "global", "keep_alive_interval",
533                 __stringify(DEFAULT_KEEPALIVE_INTERVAL),
534                 OPT_UINT_T, 0, FLDSET(struct global_config, keep_alive_interval));
535         ast_sorcery_object_field_register(sorcery, "global", "max_initial_qualify_time",
536                 __stringify(DEFAULT_MAX_INITIAL_QUALIFY_TIME),
537                 OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time));
538         ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER,
539                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user));
540         ast_sorcery_object_field_register(sorcery, "global", "default_voicemail_extension",
541                 DEFAULT_VOICEMAIL_EXTENSION, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config,
542                 default_voicemail_extension));
543         ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT,
544                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext));
545         ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval",
546                 __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL),
547                 OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval));
548         ast_sorcery_object_field_register(sorcery, "global", "disable_multi_domain",
549                 DEFAULT_DISABLE_MULTI_DOMAIN ? "yes" : "no",
550                 OPT_BOOL_T, 1, FLDSET(struct global_config, disable_multi_domain));
551         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_count",
552                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_COUNT),
553                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_count));
554         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_period",
555                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PERIOD),
556                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_period));
557         ast_sorcery_object_field_register(sorcery, "global", "unidentified_request_prune_interval",
558                 __stringify(DEFAULT_UNIDENTIFIED_REQUEST_PRUNE_INTERVAL),
559                 OPT_UINT_T, 0, FLDSET(struct global_config, unidentified_request_prune_interval));
560         ast_sorcery_object_field_register(sorcery, "global", "default_realm", DEFAULT_REALM,
561                 OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_realm));
562         ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_high",
563                 __stringify(DEFAULT_MWI_TPS_QUEUE_HIGH),
564                 OPT_UINT_T, 0, FLDSET(struct global_config, mwi.tps_queue_high));
565         ast_sorcery_object_field_register(sorcery, "global", "mwi_tps_queue_low",
566                 __stringify(DEFAULT_MWI_TPS_QUEUE_LOW),
567                 OPT_INT_T, 0, FLDSET(struct global_config, mwi.tps_queue_low));
568         ast_sorcery_object_field_register(sorcery, "global", "mwi_disable_initial_unsolicited",
569                 DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED ? "yes" : "no",
570                 OPT_BOOL_T, 1, FLDSET(struct global_config, mwi.disable_initial_unsolicited));
571         ast_sorcery_object_field_register(sorcery, "global", "ignore_uri_user_options",
572                 DEFAULT_IGNORE_URI_USER_OPTIONS ? "yes" : "no",
573                 OPT_BOOL_T, 1, FLDSET(struct global_config, ignore_uri_user_options));
574         ast_sorcery_object_field_register(sorcery, "global", "use_callerid_contact",
575                 DEFAULT_USE_CALLERID_CONTACT ? "yes" : "no",
576                 OPT_YESNO_T, 1, FLDSET(struct global_config, use_callerid_contact));
577
578         if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) {
579                 return -1;
580         }
581
582         return 0;
583 }