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