Add improved resolver framework
[framework/connectivity/connman.git] / src / resolver.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "connman.h"
27
28 struct entry_data {
29         struct connman_resolver *resolver;
30         char *interface;
31         char *domain;
32         char *server;
33 };
34
35 static GSList *entry_list = NULL;
36 static GSList *resolver_list = NULL;
37
38 static void remove_entries(GSList *entries)
39 {
40         GSList *list;
41
42         for (list = entries; list; list = list->next) {
43                 struct entry_data *entry = list->data;
44                 struct connman_resolver *resolver = entry->resolver;
45
46                 entry_list = g_slist_remove(entry_list, entry);
47
48                 if (resolver->remove)
49                         resolver->remove(entry->interface, entry->domain,
50                                                                 entry->server);
51
52                 g_free(entry->server);
53                 g_free(entry->domain);
54                 g_free(entry->interface);
55                 g_free(entry);
56         }
57
58         g_slist_free(entries);
59 }
60
61 static gint compare_priority(gconstpointer a, gconstpointer b)
62 {
63         const struct connman_resolver *resolver1 = a;
64         const struct connman_resolver *resolver2 = b;
65
66         return resolver2->priority - resolver1->priority;
67 }
68
69 /**
70  * connman_resolver_register:
71  * @resolver: resolver module
72  *
73  * Register a new resolver module
74  *
75  * Returns: %0 on success
76  */
77 int connman_resolver_register(struct connman_resolver *resolver)
78 {
79         GSList *list;
80
81         DBG("resolver %p name %s", resolver, resolver->name);
82
83         resolver_list = g_slist_insert_sorted(resolver_list, resolver,
84                                                         compare_priority);
85
86         if (resolver->append == NULL)
87                 return 0;
88
89         for (list = entry_list; list; list = list->next) {
90                 struct entry_data *entry = list->data;
91
92                 if (entry->resolver)
93                         continue;
94
95                 if (resolver->append(entry->interface, entry->domain,
96                                                         entry->server) == 0)
97                         entry->resolver = resolver;
98         }
99
100         return 0;
101 }
102
103 /**
104  * connman_resolver_unregister:
105  * @resolver: resolver module
106  *
107  * Remove a previously registered resolver module
108  */
109 void connman_resolver_unregister(struct connman_resolver *resolver)
110 {
111         GSList *list, *matches = NULL;
112
113         DBG("resolver %p name %s", resolver, resolver->name);
114
115         resolver_list = g_slist_remove(resolver_list, resolver);
116
117         for (list = entry_list; list; list = list->next) {
118                 struct entry_data *entry = list->data;
119
120                 if (entry->resolver != resolver)
121                         continue;
122
123                 matches = g_slist_append(matches, entry);
124         }
125
126         remove_entries(matches);
127 }
128
129 /**
130  * connman_resolver_append:
131  * @interface: network interface
132  * @domain: domain limitation
133  * @server: server address
134  *
135  * Append resolver server address to current list
136  */
137 int connman_resolver_append(const char *interface, const char *domain,
138                                                         const char *server)
139 {
140         struct entry_data *entry;
141         GSList *list;
142
143         DBG("interface %s domain %s server %s", interface, domain, server);
144
145         entry = g_try_new0(struct entry_data, 1);
146         if (entry == NULL)
147                 return -ENOMEM;
148
149         entry->interface = g_strdup(interface);
150         entry->domain = g_strdup(domain);
151         entry->server = g_strdup(server);
152
153         entry_list = g_slist_append(entry_list, entry);
154
155         for (list = resolver_list; list; list = list->next) {
156                 struct connman_resolver *resolver = list->data;
157
158                 if (resolver->append == NULL)
159                         continue;
160
161                 if (resolver->append(interface, domain, server) == 0) {
162                         entry->resolver = resolver;
163                         break;
164                 }
165         }
166
167         return 0;
168 }
169
170 /**
171  * connman_resolver_remove_all:
172  * @interface: network interface
173  *
174  * Remove all resolver server address for the specified interface
175  */
176 int connman_resolver_remove_all(const char *interface)
177 {
178         GSList *list, *matches = NULL;
179
180         DBG("interface %s", interface);
181
182         for (list = entry_list; list; list = list->next) {
183                 struct entry_data *entry = list->data;
184                 struct connman_resolver *resolver;
185
186                 if (g_str_equal(entry->interface, interface) == FALSE)
187                         continue;
188
189                 matches = g_slist_append(matches, entry);
190         }
191
192         remove_entries(matches);
193
194         return 0;
195 }
196
197 static int selftest_append(const char *interface, const char *domain,
198                                                         const char *server)
199 {
200         DBG("server %s", server);
201
202         return 0;
203 }
204
205 static int selftest_remove(const char *interface, const char *domain,
206                                                         const char *server)
207 {
208         DBG("server %s", server);
209
210         return 0;
211 }
212
213 static struct connman_resolver selftest = {
214         .name     = "selftest",
215         .priority = CONNMAN_RESOLVER_PRIORITY_HIGH + 42,
216         .append   = selftest_append,
217         .remove   = selftest_remove,
218 };
219
220 int __connman_resolver_selftest(void)
221 {
222         connman_resolver_append("wlan0", "lwn.net", "192.168.0.1");
223
224         connman_resolver_register(&selftest);
225
226         connman_resolver_append("eth0", "moblin.org", "192.168.42.1");
227         connman_resolver_append("wlan0", "lwn.net", "192.168.0.2");
228
229         connman_resolver_remove_all("wlan0");
230
231         connman_resolver_unregister(&selftest);
232
233         return 0;
234 }