]> git.meshlink.io Git - catta/blob - avahi-client/client.c
7edc469faafca9b4cbe1505678979a4f1e347454
[catta] / avahi-client / client.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <avahi-client/client.h>
27 #include <avahi-common/dbus.h>
28 #include <avahi-common/llist.h>
29 #include <avahi-common/error.h>
30 #include <avahi-common/malloc.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <dbus/dbus.h>
36
37 #include <stdlib.h>
38
39 #include "dbus-watch-glue.h"
40 #include "client.h"
41 #include "internal.h"
42
43 int
44 avahi_client_set_errno (AvahiClient *client, int error)
45 {
46     if (client == NULL) return error;
47
48     client->error = error;
49
50     return error;
51 }
52     
53 static
54 void avahi_client_state_change (AvahiClient *client, int state)
55 {
56     if (client == NULL || client->callback == NULL) 
57         return;
58
59     client->callback (client, state, client->user_data);
60 }
61
62 static void
63 avahi_client_state_request_callback (DBusPendingCall *call, void *data)
64 {
65     AvahiClient *client = data;
66     DBusError error;
67     DBusMessage *reply;
68     int state, type;
69
70     dbus_error_init (&error);
71
72     reply = dbus_pending_call_steal_reply (call);
73
74     type = dbus_message_get_type (reply);
75
76     if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
77     {
78         dbus_message_get_args (reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID);
79         
80         if (dbus_error_is_set (&error))
81             return;
82         
83         avahi_client_state_change (client, state);
84     } else if (type == DBUS_MESSAGE_TYPE_ERROR) {
85         dbus_set_error_from_message (&error, reply);
86     }
87
88     dbus_pending_call_unref (call);
89 }
90
91 static void
92 avahi_client_schedule_state_request (AvahiClient *client)
93 {
94     DBusMessage *message;
95     DBusPendingCall *pcall;
96
97     if (client == NULL) return;
98
99     message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetState");
100
101     dbus_connection_send_with_reply (client->bus, message, &pcall, -1);
102
103     dbus_pending_call_set_notify (pcall, avahi_client_state_request_callback, client, NULL);
104 }
105
106 static DBusHandlerResult
107 filter_func (DBusConnection *bus, DBusMessage *message, void *data)
108 {
109     AvahiClient *client = data;
110     DBusError error;
111     
112     printf ("dbus: interface=%s, path=%s, member=%s\n",
113             dbus_message_get_interface (message),
114             dbus_message_get_path (message),
115             dbus_message_get_member (message));
116
117     dbus_error_init (&error);
118
119     if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
120         char *name, *old, *new;
121         dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID);
122         
123         if (dbus_error_is_set (&error)) {
124             dbus_error_free (&error);
125             goto out;
126         }
127
128         if (strcmp (name, AVAHI_DBUS_NAME) == 0) {
129
130             if (old == NULL && new != NULL) {
131                 avahi_client_state_change (client, AVAHI_CLIENT_RECONNECTED);
132             } else if (old != NULL && new == NULL) {
133                 avahi_client_state_change (client, AVAHI_CLIENT_DISCONNECTED);
134                 /* XXX: we really need to expire all entry groups */
135             }
136         }
137     } else if (dbus_message_is_signal (message, AVAHI_DBUS_NAME, "StateChanged")) {
138         /* XXX: todo */
139         printf ("server statechange\n");
140     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged")) {
141         const char *path;
142         AvahiEntryGroup *n, *group = NULL;
143         path = dbus_message_get_path (message);
144
145         for (n = client->groups; n != NULL; n = n->groups_next)
146         {
147             if (strcmp (n->path, path) == 0)
148             {
149                 group = n;
150                 break;
151             }
152         }
153         
154         if (group != NULL) {
155             int state;
156             DBusError error;
157             dbus_error_init (&error);
158             dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID);
159             if (dbus_error_is_set (&error))
160                 goto out;
161             
162             avahi_entry_group_state_change (group, state);
163         }
164     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemNew")) {
165         return avahi_domain_browser_event (client, AVAHI_BROWSER_NEW, message);
166     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemRemove")) {
167         return avahi_domain_browser_event (client, AVAHI_BROWSER_REMOVE, message);
168     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemNew")) {
169         return avahi_service_type_browser_event (client, AVAHI_BROWSER_NEW, message);
170     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemRemove")) {
171         return avahi_service_type_browser_event (client, AVAHI_BROWSER_REMOVE, message);
172     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemNew")) {
173         return avahi_service_browser_event (client, AVAHI_BROWSER_NEW, message);
174     } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemRemove")) {
175         return avahi_service_browser_event (client, AVAHI_BROWSER_REMOVE, message);
176     }
177
178     return DBUS_HANDLER_RESULT_HANDLED;
179
180 out: 
181     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
182 }
183
184 AvahiClient *
185 avahi_client_new (const AvahiPoll *poll_api, AvahiClientCallback callback, void *user_data)
186 {
187     AvahiClient *tmp = NULL;
188     DBusError error;
189
190     dbus_error_init (&error);
191
192     if (!(tmp = avahi_new(AvahiClient, 1)))
193         goto fail;
194
195     AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, tmp->groups);
196     AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, tmp->domain_browsers);
197     AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, tmp->service_browsers);
198     AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, tmp->service_type_browsers);
199     
200     tmp->poll_api = poll_api;
201     tmp->bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
202
203     if (dbus_error_is_set (&error)) {
204         goto fail;
205     }
206
207 /*     dbus_connection_setup_with_g_main (tmp->bus, NULL); */
208 /*     dbus_connection_set_exit_on_disconnect (tmp->bus, FALSE); */
209
210     if (avahi_dbus_connection_glue(tmp->bus, poll_api) < 0)
211         goto fail;
212
213     if (!dbus_connection_add_filter (tmp->bus, filter_func, tmp, NULL))
214     {
215         goto fail;
216     }
217
218     dbus_bus_add_match (tmp->bus,
219             "type='signal', "
220             "interface='" AVAHI_DBUS_INTERFACE_SERVER "', "
221             "sender='" AVAHI_DBUS_NAME "', "
222             "path='" AVAHI_DBUS_PATH_SERVER "'",
223             &error);
224
225     if (dbus_error_is_set (&error))
226     {
227         goto fail;
228     }   
229
230     dbus_bus_add_match (tmp->bus,
231             "type='signal', "
232             "interface='" DBUS_INTERFACE_DBUS "', "
233             "sender='" DBUS_SERVICE_DBUS "', "
234             "path='" DBUS_PATH_DBUS "'",
235             &error);
236
237     if (dbus_error_is_set (&error))
238     {
239         goto fail;
240     }
241
242     tmp->callback = callback;
243     tmp->user_data = user_data;
244
245     avahi_client_schedule_state_request (tmp);
246
247     avahi_client_set_errno (tmp, AVAHI_OK);
248     return tmp;
249
250 fail:
251     avahi_free (tmp);
252
253     if (dbus_error_is_set(&error))
254         dbus_error_free(&error);
255         
256     return NULL;
257 }
258
259 static char*
260 avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param)
261 {
262     DBusMessage *message;
263     DBusMessage *reply;
264     DBusError error;
265     char *ret, *new;
266
267     if (client == NULL || method == NULL) return NULL;
268
269     dbus_error_init (&error);
270
271     message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, method);
272
273     if (param != NULL)
274     {
275         if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &param, DBUS_TYPE_INVALID))
276         {
277             avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
278             return NULL;
279         }
280     }
281     
282     reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error);
283
284     if (dbus_error_is_set (&error))
285     {
286         dbus_error_free (&error);
287         dbus_message_unref (message);
288
289         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
290         return NULL;
291     }
292
293     if (reply == NULL)
294     {
295         dbus_message_unref (message);
296
297         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
298         return NULL;
299     }
300
301     dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &ret, DBUS_TYPE_INVALID);
302
303     if (dbus_error_is_set (&error))
304     {
305         dbus_error_free (&error);
306
307         avahi_client_set_errno (client, AVAHI_ERR_DBUS_ERROR);
308         return NULL;
309     }
310
311     new = avahi_strdup (ret);
312
313     avahi_client_set_errno (client, AVAHI_OK);
314     return new;
315 }
316
317 char*
318 avahi_client_get_version_string (AvahiClient *client)
319 {
320     return avahi_client_get_string_reply_and_block (client, "GetVersionString", NULL);
321 }
322
323 char*
324 avahi_client_get_domain_name (AvahiClient *client)
325 {
326     return avahi_client_get_string_reply_and_block (client, "GetDomainName", NULL);
327 }
328
329 char*
330 avahi_client_get_host_name (AvahiClient *client)
331 {
332     return avahi_client_get_string_reply_and_block (client, "GetHostName", NULL);
333 }
334
335 char*
336 avahi_client_get_host_name_fqdn (AvahiClient *client)
337 {
338     return avahi_client_get_string_reply_and_block (client, "GetHostNameFqdn", NULL);
339 }