Mercurial > pidgin.yaz
comparison src/protocols/bonjour/dns_sd.c @ 11477:36f575351c49
[gaim-migrate @ 13719]
Commit the Bonjour code from oldstatus to HEAD. It hasn't been
updated for the new status code yet.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Fri, 09 Sep 2005 12:34:27 +0000 |
parents | |
children | 3f038da50a18 |
comparison
equal
deleted
inserted
replaced
11476:5d3f8d9e8f92 | 11477:36f575351c49 |
---|---|
1 /* | |
2 * This program is free software; you can redistribute it and/or modify | |
3 * it under the terms of the GNU General Public License as published by | |
4 * the Free Software Foundation; either version 2 of the License, or | |
5 * (at your option) any later version. | |
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 Library General Public License for more details. | |
11 * | |
12 * You should have received a copy of the GNU General Public License | |
13 * along with this program; if not, write to the Free Software | |
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
15 */ | |
16 | |
17 #include <string.h> | |
18 | |
19 #include "dns_sd.h" | |
20 #include "bonjour.h" | |
21 #include "buddy.h" | |
22 #include "debug.h" | |
23 | |
24 // Private data | |
25 | |
26 typedef struct _dns_sd_packet{ | |
27 gchar* name; | |
28 gchar* txtvers; | |
29 gchar* version; | |
30 gchar* first; | |
31 gchar* last; | |
32 gint port_p2pj; | |
33 gchar* phsh; | |
34 gchar* status; | |
35 gchar* message; | |
36 gchar* email; | |
37 gchar* vc; | |
38 gchar* jid; | |
39 gchar* AIM; | |
40 }dns_sd_packet; | |
41 | |
42 // End private data | |
43 | |
44 // Private functions | |
45 | |
46 static sw_result HOWL_API _publish_reply(sw_discovery discovery, | |
47 sw_discovery_oid oid, sw_discovery_publish_status status, sw_opaque extra) | |
48 { | |
49 gaim_debug_warning("bonjour", "_publish_reply --> Start\n"); | |
50 // Check the answer from the mDNS daemon | |
51 switch(status){ | |
52 case SW_DISCOVERY_PUBLISH_STARTED : | |
53 gaim_debug_info("bonjour", "_publish_reply --> Service started\n"); | |
54 break; | |
55 case SW_DISCOVERY_PUBLISH_STOPPED : | |
56 gaim_debug_info("bonjour", "_publish_reply --> Service stopped\n"); | |
57 break; | |
58 case SW_DISCOVERY_PUBLISH_NAME_COLLISION : | |
59 gaim_debug_info("bonjour", "_publish_reply --> Name collision\n"); | |
60 break; | |
61 case SW_DISCOVERY_PUBLISH_INVALID : | |
62 gaim_debug_info("bonjour", "_publish_reply --> Service invalid\n"); | |
63 break; | |
64 } | |
65 | |
66 return SW_OKAY; | |
67 } | |
68 | |
69 static sw_result HOWL_API _resolve_reply(sw_discovery discovery, | |
70 sw_discovery_oid oid, sw_uint32 interface_index, sw_const_string name, | |
71 sw_const_string type, sw_const_string domain, sw_ipv4_address address, | |
72 sw_port port, sw_octets text_record, sw_ulong text_record_len, | |
73 sw_opaque extra) | |
74 { | |
75 BonjourBuddy* buddy; | |
76 GaimAccount* account = (GaimAccount*)extra; | |
77 gchar* txtvers = NULL; | |
78 gchar* version = NULL; | |
79 gchar* first = NULL; | |
80 gint port_p2pj = -1; | |
81 gchar* phsh = NULL; | |
82 gchar* status = NULL; | |
83 gchar* email = NULL; | |
84 gchar* last = NULL; | |
85 gchar* jid = NULL; | |
86 gchar* AIM = NULL; | |
87 gchar* vc = NULL; | |
88 gchar* msg = NULL; | |
89 gint address_length = 16; | |
90 gchar* ip = NULL; | |
91 sw_text_record_iterator iterator; | |
92 sw_int8 key[SW_TEXT_RECORD_MAX_LEN]; | |
93 sw_int8 value[SW_TEXT_RECORD_MAX_LEN]; | |
94 sw_uint32 value_length; | |
95 | |
96 sw_discovery_cancel(discovery, oid); | |
97 | |
98 // Get the ip as a string | |
99 ip = malloc(address_length); | |
100 sw_ipv4_address_name(address, ip, address_length); | |
101 | |
102 // Obtain the parameters from the text_record | |
103 if ((text_record_len > 0) && (text_record) && (*text_record != '\0')) { | |
104 sw_text_record_iterator_init(&iterator, text_record, text_record_len); | |
105 while (sw_text_record_iterator_next(iterator, key, value, &value_length) == SW_OKAY) { | |
106 // Compare the keys with the possible ones and save them on | |
107 // the appropiate place of the buddy_list | |
108 if (strcmp(key, "txtvers") == 0) { | |
109 txtvers = g_strdup(value); | |
110 } else if (strcmp(key, "version") == 0) { | |
111 version = g_strdup(value); | |
112 } else if (strcmp(key, "1st") == 0) { | |
113 first = g_strdup(value); | |
114 } else if (strcmp(key, "port.p2pj") == 0) { | |
115 port_p2pj = atoi(value); | |
116 } else if (strcmp(key, "status") == 0) { | |
117 status = g_strdup(value); | |
118 } else if (strcmp(key, "email") == 0) { | |
119 email = g_strdup(value); | |
120 } else if (strcmp(key, "last") == 0) { | |
121 last = g_strdup(value); | |
122 } else if (strcmp(key, "jid") == 0) { | |
123 jid = g_strdup(value); | |
124 } else if (strcmp(key, "AIM") == 0) { | |
125 AIM = g_strdup(value); | |
126 } else if (strcmp(key, "vc") == 0) { | |
127 vc = g_strdup(value); | |
128 } else if (strcmp(key, "phsh") == 0) { | |
129 phsh = g_strdup(value); | |
130 } else if (strcmp(key, "msg") == 0) { | |
131 msg = g_strdup(value); | |
132 } | |
133 } | |
134 } | |
135 | |
136 // Put the parameters of the text_record in a buddy and add the buddy to | |
137 // the buddy list | |
138 buddy = bonjour_buddy_new((gchar*)name, first, port_p2pj, phsh, status, email, | |
139 last, jid, AIM, vc, ip, msg); | |
140 | |
141 if (bonjour_buddy_check(buddy) == FALSE) { | |
142 return SW_DISCOVERY_E_UNKNOWN; | |
143 } | |
144 | |
145 // Look for the buddy within the buddy list, if exist, change the status information, | |
146 // else create a new buddy within the group Bonjour | |
147 bonjour_buddy_add_to_gaim(buddy, account); | |
148 | |
149 // Free all the temporal strings | |
150 g_free(txtvers); | |
151 g_free(version); | |
152 g_free(first); | |
153 g_free(last); | |
154 g_free(status); | |
155 g_free(email); | |
156 g_free(jid); | |
157 g_free(AIM); | |
158 g_free(vc); | |
159 g_free(phsh); | |
160 g_free(msg); | |
161 | |
162 return SW_OKAY; | |
163 } | |
164 | |
165 static sw_result HOWL_API _browser_reply(sw_discovery discovery, sw_discovery_oid oid, | |
166 sw_discovery_browse_status status, sw_uint32 interface_index, sw_const_string name, | |
167 sw_const_string type, sw_const_string domain, sw_opaque_t extra) | |
168 { | |
169 sw_discovery_resolve_id rid; | |
170 GaimAccount* account = (GaimAccount*)extra; | |
171 GaimBuddy* gb = NULL; | |
172 | |
173 switch(status){ | |
174 case SW_DISCOVERY_BROWSE_INVALID: | |
175 gaim_debug_warning("bonjour", "_browser_reply --> Invalid\n"); | |
176 break; | |
177 case SW_DISCOVERY_BROWSE_RELEASE: | |
178 gaim_debug_warning("bonjour", "_browser_reply --> Release\n"); | |
179 break; | |
180 case SW_DISCOVERY_BROWSE_ADD_DOMAIN: | |
181 gaim_debug_warning("bonjour", "_browser_reply --> Add domain\n"); | |
182 break; | |
183 case SW_DISCOVERY_BROWSE_ADD_DEFAULT_DOMAIN: | |
184 gaim_debug_warning("bonjour", "_browser_reply --> Add default domain\n"); | |
185 break; | |
186 case SW_DISCOVERY_BROWSE_REMOVE_DOMAIN: | |
187 gaim_debug_warning("bonjour", "_browser_reply --> Remove domain\n"); | |
188 break; | |
189 case SW_DISCOVERY_BROWSE_ADD_SERVICE: | |
190 // A new peer has join the network and uses iChat bonjour | |
191 gaim_debug_info("bonjour", "_browser_reply --> Add service\n"); | |
192 if (g_ascii_strcasecmp(name, account->username) != 0){ | |
193 if (sw_discovery_resolve(discovery, interface_index, name, type, | |
194 domain, _resolve_reply, extra, &rid) != SW_OKAY) { | |
195 gaim_debug_warning("bonjour", "_browser_reply --> Cannot send resolve\n"); | |
196 } | |
197 } | |
198 break; | |
199 case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: | |
200 gaim_debug_info("bonjour", "_browser_reply --> Remove service\n"); | |
201 gb = gaim_find_buddy((GaimAccount*)extra, name); | |
202 if (gb != NULL) { | |
203 bonjour_buddy_delete(gb->proto_data); | |
204 gaim_blist_remove_buddy(gb); | |
205 } | |
206 break; | |
207 case SW_DISCOVERY_BROWSE_RESOLVED: | |
208 gaim_debug_info("bonjour", "_browse_reply --> Resolved\n"); | |
209 break; | |
210 default: | |
211 break; | |
212 } | |
213 | |
214 return SW_OKAY; | |
215 } | |
216 | |
217 int _dns_sd_publish(BonjourDnsSd* data, PublishType type) | |
218 { | |
219 sw_text_record dns_data; | |
220 sw_result publish_result; | |
221 | |
222 // Fill the data for the service | |
223 if(sw_text_record_init(&dns_data) != SW_OKAY){ | |
224 gaim_debug_error("bonjour", "Unable to initialize the data for the mDNS."); | |
225 return -1; | |
226 } | |
227 | |
228 sw_text_record_add_key_and_string_value(dns_data, "txtvers", data->txtvers); | |
229 sw_text_record_add_key_and_string_value(dns_data, "version", data->version); | |
230 sw_text_record_add_key_and_string_value(dns_data, "1st", data->first); | |
231 sw_text_record_add_key_and_string_value(dns_data, "last", data->last); | |
232 // sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", itoa(data->port_p2pj)); | |
233 sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", BONJOUR_DEFAULT_PORT); | |
234 sw_text_record_add_key_and_string_value(dns_data, "phsh", data->phsh); | |
235 sw_text_record_add_key_and_string_value(dns_data, "status", data->status); | |
236 sw_text_record_add_key_and_string_value(dns_data, "msg", data->msg); | |
237 sw_text_record_add_key_and_string_value(dns_data, "email", data->email); | |
238 sw_text_record_add_key_and_string_value(dns_data, "vc", data->vc); | |
239 sw_text_record_add_key_and_string_value(dns_data, "jid", data->jid); | |
240 sw_text_record_add_key_and_string_value(dns_data, "AIM", data->AIM); | |
241 | |
242 // Publish the service | |
243 switch (type) { | |
244 case PUBLISH_START: | |
245 publish_result = sw_discovery_publish(*(data->session), 0, data->name, ICHAT_SERVICE, NULL, | |
246 NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data), | |
247 _publish_reply, NULL, &(data->session_id)); | |
248 break; | |
249 case PUBLISH_UPDATE: | |
250 publish_result = sw_discovery_publish_update(*(data->session),data->session_id, | |
251 sw_text_record_bytes(dns_data), sw_text_record_len(dns_data)); | |
252 break; | |
253 } | |
254 if(publish_result != SW_OKAY){ | |
255 gaim_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service."); | |
256 return -1; | |
257 } | |
258 | |
259 // Free the memory used by temp data | |
260 sw_text_record_fina(dns_data); | |
261 | |
262 return 0; | |
263 } | |
264 | |
265 gboolean _dns_sd_handle_packets(GIOChannel* source, GIOCondition condition, gpointer data) | |
266 { | |
267 sw_discovery_read_socket(*((sw_discovery*)data)); | |
268 return TRUE; | |
269 } | |
270 | |
271 gpointer _dns_sd_wait_for_connections(gpointer data) | |
272 { | |
273 sw_discovery_oid session_id; | |
274 BonjourDnsSd* dns_sd_data = (BonjourDnsSd*)data; | |
275 | |
276 // Advise the daemon that we are waiting for connections | |
277 if(sw_discovery_browse(*(dns_sd_data->session), 0, ICHAT_SERVICE, NULL, _browser_reply, | |
278 dns_sd_data->account, &session_id) != SW_OKAY){ | |
279 gaim_debug_error("bonjour", "Unable to get service."); | |
280 return NULL; | |
281 } | |
282 | |
283 // Yields control of the cpu to the daemon | |
284 sw_discovery_run(*(dns_sd_data->session)); | |
285 | |
286 return NULL; | |
287 } | |
288 | |
289 // End private functions | |
290 | |
291 /** | |
292 * Allocate space for the dns-sd data. | |
293 */ | |
294 BonjourDnsSd* bonjour_dns_sd_new() | |
295 { | |
296 BonjourDnsSd* data = g_new(BonjourDnsSd, 1); | |
297 data->session = g_malloc(sizeof(sw_discovery)); | |
298 | |
299 return data; | |
300 } | |
301 | |
302 /** | |
303 * Deallocate the space of the dns-sd data. | |
304 */ | |
305 void bonjour_dns_sd_free(BonjourDnsSd* data) | |
306 { | |
307 g_free(data->session); | |
308 g_free(data); | |
309 } | |
310 | |
311 /** | |
312 * Send a new dns-sd packet updating our status. | |
313 */ | |
314 void bonjour_dns_sd_send_status(BonjourDnsSd* data, char* status, const char* status_message) | |
315 { | |
316 if (data->status) g_free(data->status); | |
317 if (data->msg) g_free(data->msg); | |
318 | |
319 data->status = g_strdup(status); | |
320 data->msg = g_strdup(status_message); | |
321 | |
322 // Update our text record with the new status | |
323 _dns_sd_publish(data, PUBLISH_UPDATE); // <--We must control the errors | |
324 } | |
325 | |
326 /** | |
327 * Advertise our presence within the dns-sd daemon and start browsing for other | |
328 * bonjour peers. | |
329 */ | |
330 void bonjour_dns_sd_start(BonjourDnsSd* data) | |
331 { | |
332 GIOChannel* io_channel; | |
333 gint dns_sd_socket; | |
334 sw_discovery_oid session_id; | |
335 | |
336 // Initilizations of the dns-sd data and session | |
337 data->session = malloc(sizeof(sw_discovery)); | |
338 if(sw_discovery_init(data->session) != SW_OKAY){ | |
339 gaim_debug_error("bonjour", "Unable to initialize a mDNS session."); | |
340 return; | |
341 } | |
342 | |
343 // Publish our bonjour IM client at the mDNS daemon | |
344 _dns_sd_publish(data, PUBLISH_START); // <--We must control the errors | |
345 | |
346 | |
347 // Advise the daemon that we are waiting for connections | |
348 if(sw_discovery_browse(*(data->session), 0, ICHAT_SERVICE, NULL, _browser_reply, | |
349 data->account, &session_id) != SW_OKAY){ | |
350 gaim_debug_error("bonjour", "Unable to get service."); | |
351 return; | |
352 } | |
353 | |
354 // Get the socket that communicates with the mDNS daemon and bind it to a | |
355 // callback that will handle the dns_sd packets | |
356 dns_sd_socket = sw_discovery_socket(*(data->session)); | |
357 io_channel = g_io_channel_unix_new(dns_sd_socket); | |
358 g_io_add_watch(io_channel, G_IO_IN, _dns_sd_handle_packets, data->session); // Add more for other conditions like when the conn. has been broken | |
359 } | |
360 | |
361 /** | |
362 * Unregister the "_presence._tcp" service at the mDNS daemon. | |
363 */ | |
364 int bonjour_dns_sd_stop(BonjourDnsSd* data) | |
365 { | |
366 sw_discovery_cancel(*(data->session), data->session_id); | |
367 | |
368 return 0; | |
369 } |