~cyphermox/ubuntu/precise/dnsmasq/dbus

« back to all changes in this revision

Viewing changes to src/dbus.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Kelley
  • Date: 2005-09-03 20:02:32 UTC
  • mfrom: (0.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20050903200232-76u3kbiz1hm4ok3u
Tags: 2.24-1
 * New upstream. (closes: #330422)
 * Fix typo and clean up dnsmasq.conf (closes: #326057) (closes: #304446)
 * Add build support for I18N and gettext.
 * Fixed manpage typos. (closes: #336413)
 * Create a dnsmasq-unique userid for the daemon to run as. (closes: #338353)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 dated June, 1991.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
*/
 
12
 
 
13
#include "dnsmasq.h"
 
14
 
 
15
#ifdef HAVE_DBUS
 
16
 
 
17
#define DBUS_API_SUBJECT_TO_CHANGE
 
18
#include <dbus/dbus.h>
 
19
 
 
20
struct watch {
 
21
  DBusWatch *watch;      
 
22
  struct watch *next;
 
23
};
 
24
 
 
25
 
 
26
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
 
27
{
 
28
  struct daemon *daemon = data;
 
29
  struct watch *w;
 
30
 
 
31
  for (w = daemon->watches; w; w = w->next)
 
32
    if (w->watch == watch)
 
33
      return TRUE;
 
34
 
 
35
  if (!(w = malloc(sizeof(struct watch))))
 
36
    return FALSE;
 
37
 
 
38
  w->watch = watch;
 
39
  w->next = daemon->watches;
 
40
  daemon->watches = w;
 
41
 
 
42
  dbus_watch_set_data (watch, (void *)daemon, NULL);
 
43
 
 
44
  return TRUE;
 
45
}
 
46
 
 
47
static void remove_watch(DBusWatch *watch, void *data)
 
48
{
 
49
  struct daemon *daemon = data;
 
50
  struct watch **up, *w;  
 
51
  
 
52
  for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
 
53
    if (w->watch == watch)
 
54
      {
 
55
        *up = w->next;
 
56
        free(w);
 
57
      }
 
58
    else
 
59
      up = &(w->next);
 
60
}
 
61
 
 
62
static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
 
63
{
 
64
  struct server *serv, *tmp, **up;
 
65
  DBusMessageIter iter;
 
66
  union  mysockaddr addr, source_addr;
 
67
  char *domain;
 
68
  
 
69
  dbus_message_iter_init(message, &iter);
 
70
  
 
71
  /* mark everything from DBUS */
 
72
  for (serv = daemon->servers; serv; serv = serv->next)
 
73
    if (serv->flags & SERV_FROM_DBUS)
 
74
      serv->flags |= SERV_MARK;
 
75
  
 
76
  while (1)
 
77
    {
 
78
      int skip = 0;
 
79
 
 
80
      if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
 
81
        {
 
82
          u32 a;
 
83
          
 
84
          dbus_message_iter_get_basic(&iter, &a);
 
85
          dbus_message_iter_next (&iter);
 
86
          
 
87
#ifdef HAVE_SOCKADDR_SA_LEN
 
88
          source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
 
89
#endif
 
90
          addr.in.sin_addr.s_addr = ntohl(a);
 
91
          source_addr.in.sin_family = addr.in.sin_family = AF_INET;
 
92
          addr.in.sin_port = htons(NAMESERVER_PORT);
 
93
          source_addr.in.sin_addr.s_addr = INADDR_ANY;
 
94
          source_addr.in.sin_port = htons(daemon->query_port);
 
95
        }
 
96
      else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
 
97
        {
 
98
          unsigned char p[sizeof(struct in6_addr)];
 
99
          unsigned int i;
 
100
 
 
101
          skip = 1;
 
102
 
 
103
          for(i = 0; i < sizeof(struct in6_addr); i++)
 
104
            {
 
105
              dbus_message_iter_get_basic(&iter, &p[i]);
 
106
              dbus_message_iter_next (&iter);
 
107
              if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
 
108
                break;
 
109
            }
 
110
 
 
111
#ifndef HAVE_IPV6
 
112
          syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
 
113
#else
 
114
          if (i == sizeof(struct in6_addr)-1)
 
115
            {
 
116
              memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
 
117
#ifdef HAVE_SOCKADDR_SA_LEN
 
118
              source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
 
119
#endif
 
120
              source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
 
121
              addr.in6.sin6_port = htons(NAMESERVER_PORT);
 
122
              source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
 
123
              source_addr.in6.sin6_addr = in6addr_any;
 
124
              source_addr.in6.sin6_port = htons(daemon->query_port);
 
125
              skip = 0;
 
126
            }
 
127
#endif
 
128
        }
 
129
      else
 
130
        /* At the end */
 
131
        break;
 
132
      
 
133
      do {
 
134
        if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
 
135
          {
 
136
            dbus_message_iter_get_basic(&iter, &domain);
 
137
            dbus_message_iter_next (&iter);
 
138
          }
 
139
        else
 
140
          domain = NULL;
 
141
        
 
142
        if (!skip)
 
143
          {
 
144
            /* See if this is already there, and unmark */
 
145
            for (serv = daemon->servers; serv; serv = serv->next)
 
146
              if ((serv->flags & SERV_FROM_DBUS) &&
 
147
                  (serv->flags & SERV_MARK))
 
148
                {
 
149
                  if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
 
150
                    {
 
151
                      serv->flags &= ~SERV_MARK;
 
152
                      break;
 
153
                    }
 
154
                  if ((serv->flags & SERV_HAS_DOMAIN) && 
 
155
                      domain &&
 
156
                      hostname_isequal(domain, serv->domain))
 
157
                    {
 
158
                      serv->flags &= ~SERV_MARK;
 
159
                      break;
 
160
                    }
 
161
                }
 
162
            
 
163
            if (!serv && (serv = malloc(sizeof (struct server))))
 
164
              {
 
165
                /* Not found, create a new one. */
 
166
                if (domain)
 
167
                  serv->domain = malloc(strlen(domain)+1);
 
168
                if (domain && !serv->domain)
 
169
                  {
 
170
                    free(serv);
 
171
                    serv = NULL;
 
172
                  }
 
173
                else
 
174
                  {
 
175
                    serv->next = daemon->servers;
 
176
                    daemon->servers = serv;
 
177
                    serv->flags = SERV_FROM_DBUS;
 
178
                    serv->sfd = NULL;
 
179
                    if (domain)
 
180
                      {
 
181
                        strcpy(serv->domain, domain);
 
182
                        serv->flags |= SERV_HAS_DOMAIN;
 
183
                      }
 
184
                  }
 
185
              }
 
186
 
 
187
            if (serv)
 
188
              {
 
189
                if (source_addr.in.sin_family == AF_INET &&
 
190
                    addr.in.sin_addr.s_addr == 0 &&
 
191
                    serv->domain)
 
192
                  serv->flags |= SERV_NO_ADDR;
 
193
                else
 
194
                  {
 
195
                    serv->flags &= ~SERV_NO_ADDR;
 
196
                    serv->addr = addr;
 
197
                    serv->source_addr = source_addr;
 
198
                  }
 
199
              }
 
200
          }
 
201
        } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
 
202
    }
 
203
  
 
204
  /* unlink and free anything still marked. */
 
205
  for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp) 
 
206
    {
 
207
      tmp = serv->next;
 
208
      if (serv->flags & SERV_MARK)
 
209
        {
 
210
          *up = serv->next;
 
211
          free(serv);
 
212
        }
 
213
      else 
 
214
            up = &serv->next;
 
215
    }
 
216
 
 
217
}
 
218
 
 
219
DBusHandlerResult message_handler (DBusConnection *connection, 
 
220
                                   DBusMessage *message, 
 
221
                                   void *user_data)
 
222
{
 
223
  char *method = (char *)dbus_message_get_member(message);
 
224
  struct daemon *daemon = (struct daemon *)user_data;
 
225
  
 
226
  if (strcmp(method, "GetVersion") == 0)
 
227
    {
 
228
      char *v = VERSION;
 
229
      DBusMessage *reply = dbus_message_new_method_return(message);
 
230
      
 
231
      dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
 
232
      dbus_connection_send (connection, reply, NULL);
 
233
      dbus_message_unref (reply);
 
234
    }
 
235
  else if (strcmp(method, "SetServers") == 0)
 
236
    {
 
237
      syslog(LOG_INFO, _("setting upstream servers from DBus"));
 
238
      dbus_read_servers(daemon, message);
 
239
      check_servers(daemon);
 
240
    }
 
241
  else if (strcmp(method, "ClearCache") == 0)
 
242
    clear_cache_and_reload(daemon, dnsmasq_time(daemon->uptime_fd));
 
243
  else
 
244
    return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
 
245
  
 
246
  return (DBUS_HANDLER_RESULT_HANDLED);
 
247
 
 
248
}
 
249
 
 
250
 
 
251
/* returns NULL or error message, may fail silently if dbus daemon not yet up. */
 
252
char *dbus_init(struct daemon *daemon)
 
253
{
 
254
  DBusConnection *connection = NULL;
 
255
  DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
 
256
  DBusError dbus_error;
 
257
  DBusMessage *message;
 
258
 
 
259
  dbus_error_init (&dbus_error);
 
260
  if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
 
261
    return NULL;
 
262
 
 
263
  dbus_connection_set_exit_on_disconnect(connection, FALSE);
 
264
  dbus_connection_set_watch_functions(connection, add_watch, remove_watch, 
 
265
                                      NULL, (void *)daemon, NULL);
 
266
  dbus_error_init (&dbus_error);
 
267
  dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
 
268
  if (dbus_error_is_set (&dbus_error))
 
269
    return (char *)dbus_error.message;
 
270
  
 
271
  if (!dbus_connection_register_object_path(connection,  DNSMASQ_PATH, 
 
272
                                            &dnsmasq_vtable, daemon))
 
273
    return _("could not register a DBus message handler");
 
274
  
 
275
  daemon->dbus = connection; 
 
276
  
 
277
  if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
 
278
    dbus_connection_send(connection, message, NULL);
 
279
 
 
280
  return NULL;
 
281
}
 
282
 
 
283
 
 
284
int set_dbus_listeners(struct daemon *daemon, int maxfd,
 
285
                       fd_set *rset, fd_set *wset, fd_set *eset)
 
286
{
 
287
  struct watch *w;
 
288
  
 
289
  for (w = daemon->watches; w; w = w->next)
 
290
    if (dbus_watch_get_enabled(w->watch))
 
291
      {
 
292
        unsigned int flags = dbus_watch_get_flags(w->watch);
 
293
        int fd = dbus_watch_get_fd(w->watch);
 
294
        
 
295
        if (fd > maxfd)
 
296
          maxfd = fd;
 
297
        
 
298
        if (flags & DBUS_WATCH_READABLE)
 
299
          FD_SET(fd, rset);
 
300
        
 
301
        if (flags & DBUS_WATCH_WRITABLE)
 
302
          FD_SET(fd, wset);
 
303
        
 
304
        FD_SET(fd, eset);
 
305
      }
 
306
  return maxfd;
 
307
}
 
308
 
 
309
void check_dbus_listeners(struct daemon *daemon,
 
310
                          fd_set *rset, fd_set *wset, fd_set *eset)
 
311
{
 
312
  DBusConnection *connection = (DBusConnection *)daemon->dbus;
 
313
  struct watch *w;
 
314
 
 
315
  for (w = daemon->watches; w; w = w->next)
 
316
    if (dbus_watch_get_enabled(w->watch))
 
317
      {
 
318
        unsigned int flags = 0;
 
319
        int fd = dbus_watch_get_fd(w->watch);
 
320
        
 
321
        if (FD_ISSET(fd, rset))
 
322
          flags |= DBUS_WATCH_READABLE;
 
323
        
 
324
        if (FD_ISSET(fd, wset))
 
325
          flags |= DBUS_WATCH_WRITABLE;
 
326
        
 
327
        if (FD_ISSET(fd, eset))
 
328
          flags |= DBUS_WATCH_ERROR;
 
329
 
 
330
        if (flags != 0)
 
331
          dbus_watch_handle(w->watch, flags);
 
332
      }
 
333
 
 
334
  if (connection)
 
335
    {
 
336
      dbus_connection_ref (connection);
 
337
      while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
 
338
      dbus_connection_unref (connection);
 
339
    }
 
340
}
 
341
 
 
342
#endif