Fix stuck channel in ARI through the introduction of synchronous bridge actions.
[asterisk/asterisk.git] / res / res_pjsip / config_system.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 "asterisk/sorcery.h"
26 #include "include/res_pjsip_private.h"
27 #include "asterisk/threadpool.h"
28
29 #define TIMER_T1_MIN 100
30 #define DEFAULT_TIMER_T1 500
31 #define DEFAULT_TIMER_B 32000
32
33 struct system_config {
34         SORCERY_OBJECT(details);
35         /*! Transaction Timer T1 value */
36         unsigned int timert1;
37         /*! Transaction Timer B value */
38         unsigned int timerb;
39         /*! Should we use short forms for headers? */
40         unsigned int compactheaders;
41         struct {
42                 /*! Initial number of threads in the threadpool */
43                 int initial_size;
44                 /*! The amount by which the number of threads is incremented when necessary */
45                 int auto_increment;
46                 /*! Thread idle timeout in seconds */
47                 int idle_timeout;
48                 /*! Maxumum number of threads in the threadpool */
49                 int max_size;
50         } threadpool;
51 };
52
53 static struct ast_threadpool_options sip_threadpool_options = {
54         .version = AST_THREADPOOL_OPTIONS_VERSION,
55 };
56
57 void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options)
58 {
59         *threadpool_options = sip_threadpool_options;
60 }
61
62 static struct ast_sorcery *system_sorcery;
63
64 static void *system_alloc(const char *name)
65 {
66         struct system_config *system = ast_sorcery_generic_alloc(sizeof(*system), NULL);
67
68         if (!system) {
69                 return NULL;
70         }
71
72         return system;
73 }
74
75 static int system_apply(const struct ast_sorcery *system_sorcery, void *obj)
76 {
77         struct system_config *system = obj;
78         int min_timerb;
79
80         if (system->timert1 < TIMER_T1_MIN) {
81                 ast_log(LOG_WARNING, "Timer T1 setting is too low. Setting to %d\n", TIMER_T1_MIN);
82                 system->timert1 = TIMER_T1_MIN;
83         }
84
85         min_timerb = 64 * system->timert1;
86
87         if (system->timerb < min_timerb) {
88                 ast_log(LOG_WARNING, "Timer B setting is too low. Setting to %d\n", min_timerb);
89                 system->timerb = min_timerb;
90         }
91
92         pjsip_cfg()->tsx.t1 = system->timert1;
93         pjsip_cfg()->tsx.td = system->timerb;
94
95         if (system->compactheaders) {
96                 extern pj_bool_t pjsip_use_compact_form;
97                 pjsip_use_compact_form = PJ_TRUE;
98         }
99
100         sip_threadpool_options.initial_size = system->threadpool.initial_size;
101         sip_threadpool_options.auto_increment = system->threadpool.auto_increment;
102         sip_threadpool_options.idle_timeout = system->threadpool.idle_timeout;
103         sip_threadpool_options.max_size = system->threadpool.max_size;
104
105         return 0;
106 }
107
108 int ast_sip_initialize_system(void)
109 {
110         RAII_VAR(struct ao2_container *, system_configs, NULL, ao2_cleanup);
111         RAII_VAR(struct system_config *, system, NULL, ao2_cleanup);
112
113         system_sorcery = ast_sorcery_open();
114         if (!system_sorcery) {
115                 ast_log(LOG_ERROR, "Failed to open SIP system sorcery\n");
116                 return -1;
117         }
118
119         ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
120
121         if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
122                 ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");
123                 ast_sorcery_unref(system_sorcery);
124                 system_sorcery = NULL;
125                 return -1;
126         }
127
128         ast_sorcery_object_field_register(system_sorcery, "system", "type", "", OPT_NOOP_T, 0, 0);
129         ast_sorcery_object_field_register(system_sorcery, "system", "timer_t1", __stringify(DEFAULT_TIMER_T1),
130                         OPT_UINT_T, 0, FLDSET(struct system_config, timert1));
131         ast_sorcery_object_field_register(system_sorcery, "system", "timer_b", __stringify(DEFAULT_TIMER_B),
132                         OPT_UINT_T, 0, FLDSET(struct system_config, timerb));
133         ast_sorcery_object_field_register(system_sorcery, "system", "compact_headers", "no",
134                         OPT_BOOL_T, 1, FLDSET(struct system_config, compactheaders));
135         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_initial_size", "0",
136                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.initial_size));
137         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_auto_increment", "5",
138                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.auto_increment));
139         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_idle_timeout", "60",
140                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.idle_timeout));
141         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_max_size", "0",
142                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.max_size));
143
144         ast_sorcery_load(system_sorcery);
145
146         system_configs = ast_sorcery_retrieve_by_fields(system_sorcery, "system",
147                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
148
149         if (ao2_container_count(system_configs)) {
150                 return 0;
151         }
152
153         /* No config present, allocate one and apply defaults */
154         system = ast_sorcery_alloc(system_sorcery, "system", NULL);
155         if (!system) {
156                 ast_log(LOG_ERROR, "Unable to allocate default system config.\n");
157                 ast_sorcery_unref(system_sorcery);
158                 return -1;
159         }
160
161         if (system_apply(system_sorcery, system)) {
162                 ast_log(LOG_ERROR, "Failed to apply default system config.\n");
163                 ast_sorcery_unref(system_sorcery);
164                 return -1;
165         }
166
167         return 0;
168 }
169
170 void ast_sip_destroy_system(void)
171 {
172         ast_sorcery_unref(system_sorcery);
173 }
174