Merge "rtp_engine: rtcp_report_to_json can overflow the ssrc integer value"
[asterisk/asterisk.git] / main / dns_recurring.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 /*! \file
20  *
21  * \brief DNS Recurring Query Support
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/astobj2.h"
33 #include "asterisk/linkedlists.h"
34 #include "asterisk/sched.h"
35 #include "asterisk/strings.h"
36 #include "asterisk/dns_core.h"
37 #include "asterisk/dns_recurring.h"
38 #include "asterisk/dns_internal.h"
39
40 #include <arpa/nameser.h>
41
42 /*! \brief Destructor for a DNS query */
43 static void dns_query_recurring_destroy(void *data)
44 {
45         struct ast_dns_query_recurring *recurring = data;
46
47         ao2_cleanup(recurring->user_data);
48 }
49
50 static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query);
51
52 /*! \brief Scheduled recurring query callback */
53 static int dns_query_recurring_scheduled_callback(const void *data)
54 {
55         struct ast_dns_query_recurring *recurring = (struct ast_dns_query_recurring *)data;
56
57         ao2_lock(recurring);
58         recurring->timer = -1;
59         if (!recurring->cancelled) {
60                 recurring->active = ast_dns_resolve_async(recurring->name, recurring->rr_type, recurring->rr_class, dns_query_recurring_resolution_callback,
61                         recurring);
62         }
63         ao2_unlock(recurring);
64
65         ao2_ref(recurring, -1);
66
67         return 0;
68 }
69
70 /*! \brief Query resolution callback */
71 static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query)
72 {
73         struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
74         struct ast_dns_query *callback_query;
75
76         /* Create a separate query to invoke the user specific callback on as the
77          * recurring query user data may get used externally (by the unit test)
78          * and thus changing it is problematic
79          */
80         callback_query = dns_query_alloc(query->name, query->rr_type, query->rr_class,
81                 recurring->callback, recurring->user_data);
82         if (callback_query) {
83                 /* The result is immutable at this point and can be safely provided */
84                 callback_query->result = query->result;
85                 callback_query->callback(callback_query);
86                 callback_query->result = NULL;
87                 ao2_ref(callback_query, -1);
88         }
89
90         ao2_lock(recurring);
91         /* So.. if something has not externally cancelled this we can reschedule based on the TTL */
92         if (!recurring->cancelled) {
93                 const struct ast_dns_result *result = ast_dns_query_get_result(query);
94                 int ttl = MIN(ast_dns_result_get_lowest_ttl(result), INT_MAX / 1000);
95
96                 if (ttl) {
97                         recurring->timer = ast_sched_add(ast_dns_get_sched(), ttl * 1000, dns_query_recurring_scheduled_callback, ao2_bump(recurring));
98                         if (recurring->timer < 0) {
99                                 /* It is impossible for this to be the last reference as the query has a reference to it */
100                                 ao2_ref(recurring, -1);
101                         }
102                 }
103         }
104
105         ao2_replace(recurring->active, NULL);
106         ao2_unlock(recurring);
107 }
108
109 struct ast_dns_query_recurring *ast_dns_resolve_recurring(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
110 {
111         struct ast_dns_query_recurring *recurring;
112
113         if (ast_strlen_zero(name) || !callback || !ast_dns_get_sched()) {
114                 return NULL;
115         }
116
117         recurring = ao2_alloc(sizeof(*recurring) + strlen(name) + 1, dns_query_recurring_destroy);
118         if (!recurring) {
119                 return NULL;
120         }
121
122         recurring->callback = callback;
123         recurring->user_data = ao2_bump(data);
124         recurring->timer = -1;
125         recurring->rr_type = rr_type;
126         recurring->rr_class = rr_class;
127         strcpy(recurring->name, name); /* SAFE */
128
129         recurring->active = ast_dns_resolve_async(name, rr_type, rr_class, dns_query_recurring_resolution_callback, recurring);
130         if (!recurring->active) {
131                 ao2_ref(recurring, -1);
132                 return NULL;
133         }
134
135         return recurring;
136 }
137
138 int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring)
139 {
140         int res = 0;
141
142         ao2_lock(recurring);
143
144         recurring->cancelled = 1;
145         AST_SCHED_DEL_UNREF(ast_dns_get_sched(), recurring->timer, ao2_ref(recurring, -1));
146
147         if (recurring->active) {
148                 res = ast_dns_resolve_cancel(recurring->active);
149                 ao2_replace(recurring->active, NULL);
150         }
151
152         ao2_unlock(recurring);
153
154         return res;
155 }