src/protocols/rendezvous/mdns.c

changeset 8631
f45bad880ec2
parent 8629
0c35c1e5a316
child 8634
2781838b4e10
equal deleted inserted replaced
8630:70cf27cc1765 8631:f45bad880ec2
74 gaim_debug_error("mdns", "Unable to bind socket to interface.\n"); 74 gaim_debug_error("mdns", "Unable to bind socket to interface.\n");
75 close(fd); 75 close(fd);
76 return -1; 76 return -1;
77 } 77 }
78 78
79 /* Ensure loopback is enabled (it should be enabled by default, by let's be sure) */ 79 /* Ensure loopback is enabled (it should be enabled by default, but let's be sure) */
80 loop = 1; 80 loop = 1;
81 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(unsigned char)) == -1) { 81 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(unsigned char)) == -1) {
82 gaim_debug_error("mdns", "Error calling setsockopt for IP_MULTICAST_LOOP\n"); 82 gaim_debug_error("mdns", "Error calling setsockopt for IP_MULTICAST_LOOP\n");
83 } 83 }
84 84
133 /***************************************/ 133 /***************************************/
134 /* Functions for sending mDNS messages */ 134 /* Functions for sending mDNS messages */
135 /***************************************/ 135 /***************************************/
136 136
137 static int 137 static int
138 mdns_getlength_RR_txt(void *rdata) 138 mdns_getlength_name(const void *name)
139 { 139 {
140 GSList *cur; 140 return strlen((const char *)name) + 2;
141 ResourceRecordTXTRDataNode *node; 141 }
142
143 static int
144 mdns_getlength_RR_rdata(unsigned short type, const void *rdata)
145 {
142 int rdlength = 0; 146 int rdlength = 0;
143 147
144 for (cur = (GSList *)rdata; cur != NULL; cur = cur->next) { 148 switch (type) {
145 node = (ResourceRecordTXTRDataNode *)cur->data; 149 case RENDEZVOUS_RRTYPE_PTR:
146 rdlength += 1 + strlen(node->name); 150 rdlength = mdns_getlength_name(rdata);
147 if (node->value != NULL) 151 break;
148 rdlength += 1 + strlen(node->value); 152
153 case RENDEZVOUS_RRTYPE_TXT: {
154 GSList *cur;
155 ResourceRecordRDataTXTNode *node;
156
157 for (cur = (GSList *)rdata; cur != NULL; cur = cur->next) {
158 node = (ResourceRecordRDataTXTNode *)cur->data;
159 rdlength += 1 + strlen(node->name);
160 if (node->value != NULL)
161 rdlength += 1 + strlen(node->value);
162 }
163 } break;
164
165 case RENDEZVOUS_RRTYPE_SRV:
166 rdlength = 6 + mdns_getlength_name(((const ResourceRecordRDataSRV *)rdata)->target);
167 break;
149 } 168 }
150 169
151 return rdlength; 170 return rdlength;
152 } 171 }
153 172
154 static int 173 static int
155 mdns_getlength_RR(const ResourceRecord *rr) 174 mdns_getlength_RR(ResourceRecord *rr)
156 { 175 {
157 int ret = 0; 176 int ret = 0;
177
178 rr->rdlength = mdns_getlength_RR_rdata(rr->type, rr->rdata);
158 179
159 ret += strlen(rr->name) + 2; 180 ret += strlen(rr->name) + 2;
160 ret += 10; 181 ret += 10;
161 182 ret += rr->rdlength;
162 switch (rr->type) {
163 case RENDEZVOUS_RRTYPE_PTR:
164 ret += strlen((const char *)rr->rdata) + 2;
165 break;
166
167 case RENDEZVOUS_RRTYPE_TXT:
168 ret += mdns_getlength_RR_txt(rr->rdata);
169 break;
170 }
171 183
172 return ret; 184 return ret;
173 } 185 }
174 186
175 static int 187 static int
199 211
200 i += mdns_put_name(data, datalen, offset + i, rr->name); 212 i += mdns_put_name(data, datalen, offset + i, rr->name);
201 i += util_put16(&data[offset + i], rr->type); 213 i += util_put16(&data[offset + i], rr->type);
202 i += util_put16(&data[offset + i], rr->class); 214 i += util_put16(&data[offset + i], rr->class);
203 i += util_put32(&data[offset + i], rr->ttl); 215 i += util_put32(&data[offset + i], rr->ttl);
216 i += util_put16(&data[offset + i], rr->rdlength);
204 217
205 switch (rr->type) { 218 switch (rr->type) {
206 case RENDEZVOUS_RRTYPE_PTR: 219 case RENDEZVOUS_RRTYPE_PTR:
207 i += util_put16(&data[offset + i], strlen((const char *)rr->rdata) + 2);
208 i += mdns_put_name(data, datalen, offset + i, (const char *)rr->rdata); 220 i += mdns_put_name(data, datalen, offset + i, (const char *)rr->rdata);
209 break; 221 break;
210 222
211 case RENDEZVOUS_RRTYPE_TXT: { 223 case RENDEZVOUS_RRTYPE_TXT: {
212 GSList *cur; 224 GSList *cur;
213 ResourceRecordTXTRDataNode *node; 225 ResourceRecordRDataTXTNode *node;
214 int rdlength = mdns_getlength_RR_txt(rr->rdata);
215 int mylength; 226 int mylength;
216 227
217 i += util_put16(&data[offset + i], rdlength);
218 for (cur = (GSList *)rr->rdata; cur != NULL; cur = cur->next) { 228 for (cur = (GSList *)rr->rdata; cur != NULL; cur = cur->next) {
219 node = (ResourceRecordTXTRDataNode *)cur->data; 229 node = (ResourceRecordRDataTXTNode *)cur->data;
220 mylength = 1 + strlen(node->name); 230 mylength = 1 + strlen(node->name);
221 if (node->value) 231 if (node->value)
222 mylength += 1 + strlen(node->value); 232 mylength += 1 + strlen(node->value);
223 i += util_put8(&data[offset + i], mylength - 1); 233 i += util_put8(&data[offset + i], mylength - 1);
224 memcpy(&data[offset + i], node->name, strlen(node->name)); 234 memcpy(&data[offset + i], node->name, strlen(node->name));
229 memcpy(&data[offset + i], node->value, strlen(node->value)); 239 memcpy(&data[offset + i], node->value, strlen(node->value));
230 i += strlen(node->value); 240 i += strlen(node->value);
231 } 241 }
232 } 242 }
233 } break; 243 } break;
244
245 case RENDEZVOUS_RRTYPE_SRV: {
246 ResourceRecordRDataSRV *srv = rr->rdata;
247 i += util_put16(&data[offset + i], 0);
248 i += util_put16(&data[offset + i], 0);
249 i += util_put16(&data[offset + i], srv->port);
250 i += mdns_put_name(data, datalen, offset + i, srv->target);
251 } break;
234 } 252 }
235 253
236 return i; 254 return i;
237 } 255 }
238 256
251 /* Header */ 269 /* Header */
252 datalen += 12; 270 datalen += 12;
253 271
254 /* Questions */ 272 /* Questions */
255 for (i = 0; i < dns->header.numquestions; i++) 273 for (i = 0; i < dns->header.numquestions; i++)
256 datalen += strlen(dns->questions[i].name) + 2 + 4; 274 datalen += mdns_getlength_name(dns->questions[i].name) + 4;
257 275
258 /* Resource records */ 276 /* Resource records */
259 for (i = 0; i < dns->header.numanswers; i++) 277 for (i = 0; i < dns->header.numanswers; i++)
260 datalen += mdns_getlength_RR(&dns->answers[i]); 278 datalen += mdns_getlength_RR(&dns->answers[i]);
261 for (i = 0; i < dns->header.numauthority; i++) 279 for (i = 0; i < dns->header.numauthority; i++)
355 dns->questions = NULL; 373 dns->questions = NULL;
356 374
357 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord)); 375 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
358 dns->answers[0].name = g_strdup(name); 376 dns->answers[0].name = g_strdup(name);
359 dns->answers[0].type = RENDEZVOUS_RRTYPE_PTR; 377 dns->answers[0].type = RENDEZVOUS_RRTYPE_PTR;
360 dns->answers[0].class = 0x0001; 378 dns->answers[0].class = 0x8001;
361 dns->answers[0].ttl = 0x00001c20; 379 dns->answers[0].ttl = 0x00001c20;
362 dns->answers[0].rdlength = 0x0000; /* Set automatically */ 380 dns->answers[0].rdlength = 0x0000; /* Set automatically */
363 dns->answers[0].rdata = (void *)g_strdup(domain); 381 dns->answers[0].rdata = (void *)g_strdup(domain);
364 382
365 dns->authority = NULL; 383 dns->authority = NULL;
392 dns->questions = NULL; 410 dns->questions = NULL;
393 411
394 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord)); 412 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
395 dns->answers[0].name = g_strdup(name); 413 dns->answers[0].name = g_strdup(name);
396 dns->answers[0].type = RENDEZVOUS_RRTYPE_TXT; 414 dns->answers[0].type = RENDEZVOUS_RRTYPE_TXT;
397 dns->answers[0].class = 0x0001; 415 dns->answers[0].class = 0x8001;
398 dns->answers[0].ttl = 0x00001c20; 416 dns->answers[0].ttl = 0x00001c20;
399 dns->answers[0].rdlength = 0x0000; /* Set automatically */ 417 dns->answers[0].rdlength = 0x0000; /* Set automatically */
400 dns->answers[0].rdata = (void *)rdata; 418 dns->answers[0].rdata = (void *)rdata;
401 419
402 dns->authority = NULL; 420 dns->authority = NULL;
403 dns->additional = NULL; 421 dns->additional = NULL;
404 422
405 mdns_send_dns(fd, dns); 423 mdns_send_dns(fd, dns);
406 424
407 /* The hash table should be freed by the caller of this function */ 425 /* The rdata should be freed by the caller of this function */
426 dns->answers[0].rdata = NULL;
427
428 mdns_free(dns);
429
430 return ret;
431 }
432
433 int
434 mdns_advertise_srv(int fd, const char *name, unsigned short port, const char *target)
435 {
436 int ret;
437 DNSPacket *dns;
438 ResourceRecordRDataSRV *rdata;
439
440 if ((strlen(target) > 255)) {
441 return -EINVAL;
442 }
443
444 rdata = g_malloc(sizeof(ResourceRecordRDataSRV));
445 rdata->port = port;
446 rdata->target = target;
447
448 dns = (DNSPacket *)g_malloc(sizeof(DNSPacket));
449 dns->header.id = 0x0000;
450 dns->header.flags = 0x8400;
451 dns->header.numquestions = 0x0000;
452 dns->header.numanswers = 0x0001;
453 dns->header.numauthority = 0x0000;
454 dns->header.numadditional = 0x0000;
455 dns->questions = NULL;
456
457 dns->answers = (ResourceRecord *)g_malloc(1 * sizeof(ResourceRecord));
458 dns->answers[0].name = g_strdup(name);
459 dns->answers[0].type = RENDEZVOUS_RRTYPE_SRV;
460 dns->answers[0].class = 0x8001;
461 dns->answers[0].ttl = 0x00001c20;
462 dns->answers[0].rdlength = 0x0000; /* Set automatically */
463 dns->answers[0].rdata = rdata;
464
465 dns->authority = NULL;
466 dns->additional = NULL;
467
468 mdns_send_dns(fd, dns);
469
470 g_free(dns->answers[0].rdata);
408 dns->answers[0].rdata = NULL; 471 dns->answers[0].rdata = NULL;
409 472
410 mdns_free(dns); 473 mdns_free(dns);
411 474
412 return ret; 475 return ret;
416 /* Functions for parsing mDNS messages */ 479 /* Functions for parsing mDNS messages */
417 /***************************************/ 480 /***************************************/
418 481
419 /* 482 /*
420 * XXX - Needs bounds checking! 483 * XXX - Needs bounds checking!
484 * XXX - Also make sure you don't backtrack and infinitely loop.
421 * 485 *
422 * Read in a domain name from the given buffer starting at the given 486 * Read in a domain name from the given buffer starting at the given
423 * offset. This handles using domain name compression to jump around 487 * offset. This handles using domain name compression to jump around
424 * the data buffer, if needed. 488 * the data buffer, if needed.
425 * 489 *
801 */ 865 */
802 static void 866 static void
803 mdns_free_rr(ResourceRecord *rr) 867 mdns_free_rr(ResourceRecord *rr)
804 { 868 {
805 g_free(rr->name); 869 g_free(rr->name);
806 mdns_free_rr_rdata(rr->type, rr->rdata); 870 if (rr->rdata != NULL)
871 mdns_free_rr_rdata(rr->type, rr->rdata);
807 } 872 }
808 873
809 void 874 void
810 mdns_free(DNSPacket *dns) 875 mdns_free(DNSPacket *dns)
811 { 876 {

mercurial