res_pjsip: Enable PJSIP DNS client support.
[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_config(system_sorcery, "res_pjsip");
121
122         ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
123
124         if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
125                 ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");
126                 ast_sorcery_unref(system_sorcery);
127                 system_sorcery = NULL;
128                 return -1;
129         }
130
131         ast_sorcery_object_field_register(system_sorcery, "system", "type", "", OPT_NOOP_T, 0, 0);
132         ast_sorcery_object_field_register(system_sorcery, "system", "timer_t1", __stringify(DEFAULT_TIMER_T1),
133                         OPT_UINT_T, 0, FLDSET(struct system_config, timert1));
134         ast_sorcery_object_field_register(system_sorcery, "system", "timer_b", __stringify(DEFAULT_TIMER_B),
135                         OPT_UINT_T, 0, FLDSET(struct system_config, timerb));
136         ast_sorcery_object_field_register(system_sorcery, "system", "compact_headers", "no",
137                         OPT_BOOL_T, 1, FLDSET(struct system_config, compactheaders));
138         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_initial_size", "0",
139                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.initial_size));
140         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_auto_increment", "5",
141                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.auto_increment));
142         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_idle_timeout", "60",
143                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.idle_timeout));
144         ast_sorcery_object_field_register(system_sorcery, "system", "threadpool_max_size", "0",
145                         OPT_UINT_T, 0, FLDSET(struct system_config, threadpool.max_size));
146
147         ast_sorcery_load(system_sorcery);
148
149         system_configs = ast_sorcery_retrieve_by_fields(system_sorcery, "system",
150                 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
151
152         if (ao2_container_count(system_configs)) {
153                 return 0;
154         }
155
156         /* No config present, allocate one and apply defaults */
157         system = ast_sorcery_alloc(system_sorcery, "system", NULL);
158         if (!system) {
159                 ast_log(LOG_ERROR, "Unable to allocate default system config.\n");
160                 ast_sorcery_unref(system_sorcery);
161                 return -1;
162         }
163
164         if (system_apply(system_sorcery, system)) {
165                 ast_log(LOG_ERROR, "Failed to apply default system config.\n");
166                 ast_sorcery_unref(system_sorcery);
167                 return -1;
168         }
169
170         return 0;
171 }
172
173 void ast_sip_destroy_system(void)
174 {
175         ast_sorcery_unref(system_sorcery);
176 }
177
178 static int system_create_resolver_and_set_nameservers(void *data)
179 {
180         struct ao2_container *discovered_nameservers;
181         struct ao2_iterator it_nameservers;
182         char *nameserver;
183         pj_status_t status;
184         pj_dns_resolver *resolver;
185         pj_str_t nameservers[PJ_DNS_RESOLVER_MAX_NS];
186         unsigned int count = 0;
187
188         discovered_nameservers = ast_dns_get_nameservers();
189         if (!discovered_nameservers) {
190                 ast_log(LOG_ERROR, "Could not retrieve local system nameservers, resorting to system resolution\n");
191                 return 0;
192         }
193
194         if (!ao2_container_count(discovered_nameservers)) {
195                 ast_log(LOG_ERROR, "There are no local system nameservers configured, resorting to system resolution\n");
196                 ao2_ref(discovered_nameservers, -1);
197                 return -1;
198         }
199
200         if (!(resolver = pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint()))) {
201                 status = pjsip_endpt_create_resolver(ast_sip_get_pjsip_endpoint(), &resolver);
202                 if (status != PJ_SUCCESS) {
203                         ast_log(LOG_ERROR, "Could not create DNS resolver(%d), resorting to system resolution\n", status);
204                         return 0;
205                 }
206         }
207
208         it_nameservers = ao2_iterator_init(discovered_nameservers, 0);
209         while ((nameserver = ao2_iterator_next(&it_nameservers))) {
210                 pj_strset2(&nameservers[count++], nameserver);
211                 ao2_ref(nameserver, -1);
212
213                 if (count == (PJ_DNS_RESOLVER_MAX_NS - 1)) {
214                         break;
215                 }
216         }
217         ao2_iterator_destroy(&it_nameservers);
218
219         status = pj_dns_resolver_set_ns(resolver, count, nameservers, NULL);
220
221         /* Since we no longer need the nameservers we can drop the list of them */
222         ao2_ref(discovered_nameservers, -1);
223
224         if (status != PJ_SUCCESS) {
225                 ast_log(LOG_ERROR, "Could not set nameservers on DNS resolver in PJSIP(%d), resorting to system resolution\n",
226                         status);
227                 return 0;
228         }
229
230         if (!pjsip_endpt_get_resolver(ast_sip_get_pjsip_endpoint())) {
231                 status = pjsip_endpt_set_resolver(ast_sip_get_pjsip_endpoint(), resolver);
232                 if (status != PJ_SUCCESS) {
233                         ast_log(LOG_ERROR, "Could not set DNS resolver in PJSIP(%d), resorting to system resolution\n", status);
234                         return 0;
235                 }
236         }
237
238         return 0;
239 }
240
241 void ast_sip_initialize_dns(void)
242 {
243         ast_sip_push_task_synchronous(NULL, system_create_resolver_and_set_nameservers, NULL);
244 }