7f8da85978e16f84d8cb6bceda061b8655d58acf
[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 #include "asterisk/dns.h"
29
30 #define TIMER_T1_MIN 100
31 #define DEFAULT_TIMER_T1 500
32 #define DEFAULT_TIMER_B 32000
33
34 struct system_config {
35         SORCERY_OBJECT(details);
36         /*! Transaction Timer T1 value */
37         unsigned int timert1;
38         /*! Transaction Timer B value */
39         unsigned int timerb;
40         /*! Should we use short forms for headers? */
41         unsigned int compactheaders;
42         struct {
43                 /*! Initial number of threads in the threadpool */
44                 int initial_size;
45                 /*! The amount by which the number of threads is incremented when necessary */
46                 int auto_increment;
47                 /*! Thread idle timeout in seconds */
48                 int idle_timeout;
49                 /*! Maxumum number of threads in the threadpool */
50                 int max_size;
51         } threadpool;
52 };
53
54 static struct ast_threadpool_options sip_threadpool_options = {
55         .version = AST_THREADPOOL_OPTIONS_VERSION,
56 };
57
58 void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options)
59 {
60         *threadpool_options = sip_threadpool_options;
61 }
62
63 static struct ast_sorcery *system_sorcery;
64
65 static void *system_alloc(const char *name)
66 {
67         struct system_config *system = ast_sorcery_generic_alloc(sizeof(*system), NULL);
68
69         if (!system) {
70                 return NULL;
71         }
72
73         return system;
74 }
75
76 static int system_apply(const struct ast_sorcery *system_sorcery, void *obj)
77 {
78         struct system_config *system = obj;
79         int min_timerb;
80
81         if (system->timert1 < TIMER_T1_MIN) {
82                 ast_log(LOG_WARNING, "Timer T1 setting is too low. Setting to %d\n", TIMER_T1_MIN);
83                 system->timert1 = TIMER_T1_MIN;
84         }
85
86         min_timerb = 64 * system->timert1;
87
88         if (system->timerb < min_timerb) {
89                 ast_log(LOG_WARNING, "Timer B setting is too low. Setting to %d\n", min_timerb);
90                 system->timerb = min_timerb;
91         }
92
93         pjsip_cfg()->tsx.t1 = system->timert1;
94         pjsip_cfg()->tsx.td = system->timerb;
95
96         if (system->compactheaders) {
97                 extern pj_bool_t pjsip_use_compact_form;
98                 pjsip_use_compact_form = PJ_TRUE;
99         }
100
101         sip_threadpool_options.initial_size = system->threadpool.initial_size;
102         sip_threadpool_options.auto_increment = system->threadpool.auto_increment;
103         sip_threadpool_options.idle_timeout = system->threadpool.idle_timeout;
104         sip_threadpool_options.max_size = system->threadpool.max_size;
105
106         return 0;
107 }
108
109 int ast_sip_initialize_system(void)
110 {
111         RAII_VAR(struct ao2_container *, system_configs, NULL, ao2_cleanup);
112         RAII_VAR(struct system_config *, system, NULL, ao2_cleanup);
113
114         system_sorcery = ast_sorcery_open();
115         if (!system_sorcery) {
116                 ast_log(LOG_ERROR, "Failed to open SIP system sorcery\n");
117                 return -1;
118         }
119
120         ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
121
122         if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
123                 ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");
124                 ast_sorcery_unref(system_sorcery);
125                 system_sorcery = NULL;
126                 return -1;
127         }
128
129         ast_sorcery_object_field_register(system_sorcery, "system", "type", "", OPT_NOOP_T, 0, 0);
130         ast_sorcery_object_field_register(system_sorcery, "system", "timer_t1", __stringify(DEFAULT_TIMER_T1),
131                         OPT_UINT_T, 0, FLDSET(struct system_config, timert1));
132         ast_sorcery_object_field_register(system_sorcery, "system", "timer_b", __stringify(DEFAULT_TIMER_B),
133                         OPT_UINT_T, 0, FLDSET(struct system_config, timerb));
134         ast_sorcery_object_field_register(system_sorcery, "system", "compact_headers", "no",
135                         OPT_BOOL_T, 1, FLDSET(struct system_config, compactheaders));
136         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_initial_size", "0",
137                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.initial_size));
138         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_auto_increment", "5",
139                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.auto_increment));
140         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_idle_timeout", "60",
141                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.idle_timeout));
142         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_max_size", "0",
143                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.max_size));
144
145         ast_sorcery_load(system_sorcery);
146
147         system_configs = ast_sorcery_retrieve_by_fields(system_sorcery, "system",
148                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
149
150         if (ao2_container_count(system_configs)) {
151                 return 0;
152         }
153
154         /* No config present, allocate one and apply defaults */
155         system = ast_sorcery_alloc(system_sorcery, "system", NULL);
156         if (!system) {
157                 ast_log(LOG_ERROR, "Unable to allocate default system config.\n");
158                 ast_sorcery_unref(system_sorcery);
159                 return -1;
160         }
161
162         if (system_apply(system_sorcery, system)) {
163                 ast_log(LOG_ERROR, "Failed to apply default system config.\n");
164                 ast_sorcery_unref(system_sorcery);
165                 return -1;
166         }
167
168         return 0;
169 }
170
171 void ast_sip_destroy_system(void)
172 {
173         ast_sorcery_unref(system_sorcery);
174 }
175
176 static int system_create_resolver_and_set_nameservers(void *data)
177 {
178         struct ao2_container *discovered_nameservers;
179         struct ao2_iterator it_nameservers;
180         char *nameserver;
181         pj_status_t status;
182         pj_dns_resolver *resolver;
183         pj_str_t nameservers[PJ_DNS_RESOLVER_MAX_NS];
184         unsigned int count = 0;
185
186         discovered_nameservers = ast_dns_get_nameservers();
187         if (!discovered_nameservers) {
188                 ast_log(LOG_ERROR, "Could not retrieve local system nameservers, resorting to system resolution\n");
189                 return 0;
190         }
191
192         if (!ao2_container_count(discovered_nameservers)) {
193                 ast_log(LOG_ERROR, "There are no local system nameservers configured, resorting to system resolution\n");
194                 ao2_ref(discovered_nameservers, -1);
195                 return -1;
196         }
197
198         if (!(resolver = pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint()))) {
199                 status = pjsip_endpt_create_resolver(ast_sip_get_pjsip_endpoint(), &resolver);
200                 if (status != PJ_SUCCESS) {
201                         ast_log(LOG_ERROR, "Could not create DNS resolver(%d), resorting to system resolution\n", status);
202                         ao2_ref(discovered_nameservers, -1);
203                         return 0;
204                 }
205         }
206
207         it_nameservers = ao2_iterator_init(discovered_nameservers, 0);
208         while ((nameserver = ao2_iterator_next(&it_nameservers))) {
209                 pj_strset2(&nameservers[count++], nameserver);
210                 ao2_ref(nameserver, -1);
211
212                 if (count == (PJ_DNS_RESOLVER_MAX_NS - 1)) {
213                         break;
214                 }
215         }
216         ao2_iterator_destroy(&it_nameservers);
217
218         status = pj_dns_resolver_set_ns(resolver, count, nameservers, NULL);
219
220         /* Since we no longer need the nameservers we can drop the list of them */
221         ao2_ref(discovered_nameservers, -1);
222
223         if (status != PJ_SUCCESS) {
224                 ast_log(LOG_ERROR, "Could not set nameservers on DNS resolver in PJSIP(%d), resorting to system resolution\n",
225                         status);
226                 return 0;
227         }
228
229         if (!pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint())) {
230                 status = pjsip_endpt_set_resolver(ast_sip_get_pjsip_endpoint(), resolver);
231                 if (status != PJ_SUCCESS) {
232                         ast_log(LOG_ERROR, "Could not set DNS resolver in PJSIP(%d), resorting to system resolution\n", status);
233                         return 0;
234                 }
235         }
236
237         return 0;
238 }
239
240 void ast_sip_initialize_dns(void)
241 {
242         ast_sip_push_task_synchronous(NULL, system_create_resolver_and_set_nameservers, NULL);
243 }