yong-stropheruby 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/ext/sock.c ADDED
@@ -0,0 +1,911 @@
1
+ /* sock.c
2
+ ** strophe XMPP client library -- socket abstraction implementation
3
+ **
4
+ ** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
5
+ **
6
+ ** This software is provided AS-IS with no warranty, either express
7
+ ** or implied.
8
+ **
9
+ ** This software is distributed under license and may not be copied,
10
+ ** modified or distributed except as expressly authorized under the
11
+ ** terms of the license contained in the file LICENSE.txt in this
12
+ ** distribution.
13
+ */
14
+
15
+ /** @file
16
+ * Socket abstraction.
17
+ */
18
+
19
+ #include <stdio.h>
20
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <sys/types.h>
23
+
24
+ #ifdef _WIN32
25
+ #include <winsock2.h>
26
+ #include <ws2tcpip.h>
27
+ #include <windns.h>
28
+ #include <Iphlpapi.h>
29
+ #define snprintf _snprintf
30
+ #else
31
+ #include <errno.h>
32
+ #include <unistd.h>
33
+ #include <sys/socket.h>
34
+ #include <netinet/in.h>
35
+ #include <netdb.h>
36
+ #include <fcntl.h>
37
+ #include <arpa/nameser.h>
38
+ #include <arpa/nameser_compat.h>
39
+ #include <resolv.h>
40
+ #endif
41
+
42
+ #include "sock.h"
43
+
44
+ void sock_initialize(void)
45
+ {
46
+ #ifdef _WIN32
47
+ WSADATA wsad;
48
+ WSAStartup(0x0101, &wsad);
49
+ #endif
50
+ }
51
+
52
+ void sock_shutdown(void)
53
+ {
54
+ #ifdef _WIN32
55
+ WSACleanup();
56
+ #endif
57
+ }
58
+
59
+ int sock_error(void)
60
+ {
61
+ #ifdef _WIN32
62
+ return WSAGetLastError();
63
+ #else
64
+ return errno;
65
+ #endif
66
+ }
67
+
68
+ static int _in_progress(int error)
69
+ {
70
+ #ifdef _WIN32
71
+ return (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS);
72
+ #else
73
+ return (errno == EINPROGRESS);
74
+ #endif
75
+ }
76
+
77
+ sock_t sock_connect(const char * const host, const unsigned int port)
78
+ {
79
+ sock_t sock;
80
+ char service[6];
81
+ struct addrinfo *res, *ainfo, hints;
82
+ int err;
83
+
84
+ sock = -1;
85
+
86
+ snprintf(service, 6, "%u", port);
87
+
88
+ memset(&hints, 0, sizeof(struct addrinfo));
89
+ hints.ai_family = AF_INET;
90
+ hints.ai_protocol = IPPROTO_TCP;
91
+ hints.ai_socktype = SOCK_STREAM;
92
+
93
+ if ((err = getaddrinfo(host, service, &hints, &res)) != 0)
94
+ return -1;
95
+
96
+ ainfo = res;
97
+ while (ainfo) {
98
+ if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype,
99
+ ainfo->ai_protocol)) >= 0) {
100
+ sock_set_nonblocking(sock);
101
+
102
+ err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
103
+
104
+ if ((err == 0) || (err < 0 && _in_progress(sock_error())))
105
+ break;
106
+ }
107
+
108
+ ainfo = ainfo->ai_next;
109
+ }
110
+
111
+ if (res) freeaddrinfo(res);
112
+
113
+ return sock;
114
+ }
115
+
116
+ int sock_close(const sock_t sock)
117
+ {
118
+ #ifdef _WIN32
119
+ return closesocket(sock);
120
+ #else
121
+ return close(sock);
122
+ #endif
123
+ }
124
+
125
+ int sock_set_blocking(const sock_t sock)
126
+ {
127
+ #ifdef _WIN32
128
+ u_long block = 0;
129
+ return ioctlsocket(sock, FIONBIO, &block);
130
+ #else
131
+ return fcntl(sock, F_SETFL, 0);
132
+ #endif
133
+ }
134
+
135
+ int sock_set_nonblocking(const sock_t sock)
136
+ {
137
+ #ifdef _WIN32
138
+ u_long nonblock = 1;
139
+ return ioctlsocket(sock, FIONBIO, &nonblock);
140
+ #else
141
+ return fcntl(sock, F_SETFL, O_NONBLOCK);
142
+ #endif
143
+ }
144
+
145
+ int sock_read(const sock_t sock, void * const buff, const size_t len)
146
+ {
147
+ return recv(sock, buff, len, 0);
148
+ }
149
+
150
+ int sock_write(const sock_t sock, const void * const buff, const size_t len)
151
+ {
152
+ return send(sock, buff, len, 0);
153
+ }
154
+
155
+ int sock_is_recoverable(const int error)
156
+ {
157
+ #ifdef _WIN32
158
+ return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
159
+ error == WSAEINPROGRESS);
160
+ #else
161
+ return (error == EAGAIN || error == EINTR);
162
+ #endif
163
+ }
164
+
165
+ int sock_connect_error(const sock_t sock)
166
+ {
167
+ struct sockaddr sa;
168
+ unsigned len;
169
+ char temp;
170
+
171
+ sa.sa_family = AF_INET;
172
+
173
+ len = sizeof(sa);
174
+
175
+ /* we don't actually care about the peer name, we're just checking if
176
+ * we're connected or not */
177
+ if (getpeername(sock, &sa, &len) == 0)
178
+ {
179
+ return 0;
180
+ }
181
+
182
+ /* it's possible that the error wasn't ENOTCONN, so if it wasn't,
183
+ * return that */
184
+ #ifdef _WIN32
185
+ if (sock_error() != WSAENOTCONN) return sock_error();
186
+ #else
187
+ if (sock_error() != ENOTCONN) return sock_error();
188
+ #endif
189
+
190
+ /* load the correct error into errno through error slippage */
191
+ recv(sock, &temp, 1, 0);
192
+
193
+ return sock_error();
194
+ }
195
+
196
+ struct dnsquery_header
197
+ {
198
+ unsigned short id;
199
+ unsigned char qr;
200
+ unsigned char opcode;
201
+ unsigned char aa;
202
+ unsigned char tc;
203
+ unsigned char rd;
204
+ unsigned char ra;
205
+ unsigned char z;
206
+ unsigned char rcode;
207
+ unsigned short qdcount;
208
+ unsigned short ancount;
209
+ unsigned short nscount;
210
+ unsigned short arcount;
211
+ };
212
+
213
+ struct dnsquery_question
214
+ {
215
+ char qname[1024];
216
+ unsigned short qtype;
217
+ unsigned short qclass;
218
+ };
219
+
220
+ struct dnsquery_srvrdata
221
+ {
222
+ unsigned short priority;
223
+ unsigned short weight;
224
+ unsigned short port;
225
+ char target[1024];
226
+ };
227
+
228
+ struct dnsquery_resourcerecord
229
+ {
230
+ char name[1024];
231
+ unsigned short type;
232
+ unsigned short _class;
233
+ unsigned int ttl;
234
+ unsigned short rdlength;
235
+ struct dnsquery_srvrdata rdata;
236
+ };
237
+
238
+
239
+ void netbuf_add_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int num)
240
+ {
241
+ unsigned char *start = buf + *offset;
242
+ unsigned char *p = start;
243
+
244
+ /* assuming big endian */
245
+ *p++ = (num >> 24) & 0xff;
246
+ *p++ = (num >> 16) & 0xff;
247
+ *p++ = (num >> 8) & 0xff;
248
+ *p++ = (num) & 0xff;
249
+
250
+ *offset += 4;
251
+ }
252
+
253
+ void netbuf_get_32bitnum(unsigned char *buf, int buflen, int *offset, unsigned int *num)
254
+ {
255
+ unsigned char *start = buf + *offset;
256
+ unsigned char *p = start;
257
+ *num = 0;
258
+
259
+ /* assuming big endian */
260
+ *num |= (*p++) << 24;
261
+ *num |= (*p++) << 16;
262
+ *num |= (*p++) << 8;
263
+ *num |= (*p++);
264
+
265
+ *offset += 4;
266
+ }
267
+
268
+ void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
269
+ {
270
+ unsigned char *start = buf + *offset;
271
+ unsigned char *p = start;
272
+
273
+ /* assuming big endian */
274
+ *p++ = (num >> 8) & 0xff;
275
+ *p++ = (num) & 0xff;
276
+
277
+ *offset += 2;
278
+ }
279
+
280
+ void netbuf_get_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short *num)
281
+ {
282
+ unsigned char *start = buf + *offset;
283
+ unsigned char *p = start;
284
+ *num = 0;
285
+
286
+ /* assuming big endian */
287
+ *num |= (*p++) << 8;
288
+ *num |= (*p++);
289
+
290
+ *offset += 2;
291
+ }
292
+
293
+ void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
294
+ char *name)
295
+ {
296
+ unsigned char *start = buf + *offset;
297
+ unsigned char *p = start;
298
+ unsigned char *wordstart, *wordend;
299
+
300
+ wordstart = (unsigned char *)name;
301
+
302
+ while (*wordstart)
303
+ {
304
+ int len;
305
+ wordend = wordstart;
306
+ while (*wordend && *wordend != '.')
307
+ {
308
+ wordend++;
309
+ }
310
+
311
+ len = (int)(wordend - wordstart);
312
+
313
+ if (len > 0x3F)
314
+ {
315
+ len = 0x3F;
316
+ }
317
+
318
+ *p++ = len;
319
+
320
+ while (wordstart != wordend)
321
+ {
322
+ *p++ = *wordstart++;
323
+ }
324
+
325
+ if (*wordstart == '.')
326
+ {
327
+ wordstart++;
328
+ }
329
+ }
330
+
331
+ *p++ = '\0';
332
+
333
+ *offset += p - start;
334
+ }
335
+
336
+ int calc_domain_name_size(unsigned char *buf, int buflen, int offset)
337
+ {
338
+ unsigned char *p = buf + offset;
339
+ int len = 0;
340
+
341
+ while (*p)
342
+ {
343
+ if ((*p & 0xC0) == 0xC0)
344
+ {
345
+ int newoffset = 0;
346
+ newoffset |= (*p++ & 0x3F) << 8;
347
+ newoffset |= *p;
348
+
349
+ p = buf + newoffset;
350
+ }
351
+ else
352
+ {
353
+ if (len)
354
+ {
355
+ len += 1;
356
+ }
357
+ len += *p;
358
+ p += *p + 1;
359
+ }
360
+ }
361
+
362
+ return len;
363
+ }
364
+
365
+ int netbuf_get_domain_name(unsigned char *buf, int buflen, int *offset, char *namebuf, int namebuflen)
366
+ {
367
+ unsigned char *start = buf + *offset;
368
+ unsigned char *p, *p2;
369
+ int *curroffset = offset;
370
+ int len = 0;
371
+
372
+ *namebuf = '\0';
373
+
374
+ /* measure length */
375
+ p = start;
376
+ while (*p)
377
+ {
378
+ if ((*p & 0xC0) == 0xC0)
379
+ {
380
+ int newoffset = 0;
381
+ newoffset |= (*p++ & 0x3F) << 8;
382
+ newoffset |= *p++;
383
+
384
+ p = buf + newoffset;
385
+ }
386
+ else
387
+ {
388
+ len += *p;
389
+ p += *p + 1;
390
+ }
391
+ }
392
+
393
+ if (namebuflen < len)
394
+ {
395
+ return len;
396
+ }
397
+
398
+ /* actually copy in name */
399
+ p = start;
400
+ p2 = (unsigned char *)namebuf;
401
+ while (*p)
402
+ {
403
+ if ((*p & 0xC0) == 0xC0)
404
+ {
405
+ int newoffset = 0;
406
+ newoffset |= (*p++ & 0x3F) << 8;
407
+ newoffset |= *p++;
408
+
409
+ if (curroffset)
410
+ {
411
+ *curroffset += (int)(p - start);
412
+ curroffset = NULL;
413
+ }
414
+
415
+ p = buf + newoffset;
416
+ }
417
+ else
418
+ {
419
+ int i, partlen;
420
+
421
+ if (*namebuf != '\0')
422
+ {
423
+ *p2++ = '.';
424
+ }
425
+
426
+ partlen = *p++;
427
+
428
+ for (i=0; i < partlen; i++)
429
+ {
430
+ *p2++ = *p++;
431
+ }
432
+ }
433
+ }
434
+
435
+ if (curroffset)
436
+ {
437
+ p++;
438
+ *curroffset += (int)(p - start);
439
+ curroffset = NULL;
440
+ }
441
+
442
+ *p2 = '\0';
443
+
444
+ return 0;
445
+ }
446
+
447
+ void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
448
+ {
449
+ unsigned char *p;
450
+
451
+ netbuf_add_16bitnum(buf, buflen, offset, header->id);
452
+
453
+ p = buf + *offset;
454
+ *p++ = ((header->qr & 0x01) << 7)
455
+ | ((header->opcode & 0x0F) << 3)
456
+ | ((header->aa & 0x01) << 2)
457
+ | ((header->tc & 0x01) << 1)
458
+ | ((header->rd & 0x01));
459
+ *p++ = ((header->ra & 0x01) << 7)
460
+ | ((header->z & 0x07) << 4)
461
+ | ((header->rcode & 0x0F));
462
+ *offset += 2;
463
+
464
+ netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
465
+ netbuf_add_16bitnum(buf, buflen, offset, header->ancount);
466
+ netbuf_add_16bitnum(buf, buflen, offset, header->nscount);
467
+ netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
468
+ }
469
+
470
+ void netbuf_get_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
471
+ {
472
+ unsigned char *p;
473
+
474
+ netbuf_get_16bitnum(buf, buflen, offset, &(header->id));
475
+
476
+ p = buf + *offset;
477
+ header->qr = (*p >> 7) & 0x01;
478
+ header->opcode = (*p >> 3) & 0x0F;
479
+ header->aa = (*p >> 2) & 0x01;
480
+ header->tc = (*p >> 1) & 0x01;
481
+ header->rd = (*p) & 0x01;
482
+ p++;
483
+ header->ra = (*p >> 7) & 0x01;
484
+ header->z = (*p >> 4) & 0x07;
485
+ header->rcode = (*p) & 0x0F;
486
+ p++;
487
+ *offset += 2;
488
+
489
+ netbuf_get_16bitnum(buf, buflen, offset, &(header->qdcount));
490
+ netbuf_get_16bitnum(buf, buflen, offset, &(header->ancount));
491
+ netbuf_get_16bitnum(buf, buflen, offset, &(header->nscount));
492
+ netbuf_get_16bitnum(buf, buflen, offset, &(header->arcount));
493
+ }
494
+
495
+ void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
496
+ {
497
+ netbuf_add_domain_name(buf, buflen, offset, question->qname);
498
+ netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
499
+ netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
500
+ }
501
+
502
+ void netbuf_get_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
503
+ {
504
+ netbuf_get_domain_name(buf, buflen, offset, question->qname, 1024);
505
+ netbuf_get_16bitnum(buf, buflen, offset, &(question->qtype));
506
+ netbuf_get_16bitnum(buf, buflen, offset, &(question->qclass));
507
+ }
508
+
509
+ void netbuf_get_dnsquery_srvrdata(unsigned char *buf, int buflen, int *offset, struct dnsquery_srvrdata *srvrdata)
510
+ {
511
+ netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->priority));
512
+ netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->weight));
513
+ netbuf_get_16bitnum(buf, buflen, offset, &(srvrdata->port));
514
+ netbuf_get_domain_name(buf, buflen, offset, srvrdata->target, 1024);
515
+ }
516
+
517
+ void netbuf_get_dnsquery_resourcerecord(unsigned char *buf, int buflen, int *offset, struct dnsquery_resourcerecord *rr)
518
+ {
519
+ netbuf_get_domain_name(buf, buflen, offset, rr->name, 1024);
520
+ netbuf_get_16bitnum(buf, buflen, offset, &(rr->type));
521
+ netbuf_get_16bitnum(buf, buflen, offset, &(rr->_class));
522
+ netbuf_get_32bitnum(buf, buflen, offset, &(rr->ttl));
523
+ netbuf_get_16bitnum(buf, buflen, offset, &(rr->rdlength));
524
+ if (rr->type == 33) /* SRV */
525
+ {
526
+ int newoffset = *offset;
527
+ netbuf_get_dnsquery_srvrdata(buf, buflen, &newoffset, &(rr->rdata));
528
+ }
529
+ *offset += rr->rdlength;
530
+ }
531
+
532
+
533
+ int sock_srv_lookup(const char *service, const char *proto, const char *domain, char *resulttarget, int resulttargetlength, int *resultport)
534
+ {
535
+ int set = 0;
536
+ char fulldomain[2048];
537
+
538
+ snprintf(fulldomain, 2048, "_%s._%s.%s", service, proto, domain);
539
+ #ifdef _WIN32
540
+
541
+ /* try using dnsapi first */
542
+ if (!set)
543
+ {
544
+ HINSTANCE hdnsapi = NULL;
545
+
546
+ DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
547
+ void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
548
+
549
+ if (hdnsapi = LoadLibrary("dnsapi.dll")) {
550
+
551
+ pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
552
+ pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
553
+
554
+ if (pDnsQuery_A && pDnsRecordListFree) {
555
+ PDNS_RECORD dnsrecords = NULL;
556
+ DNS_STATUS error;
557
+
558
+ error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
559
+
560
+ if (error == 0) {
561
+ PDNS_RECORD current = dnsrecords;
562
+
563
+ while (current) {
564
+ if (current->wType == DNS_TYPE_SRV) {
565
+ snprintf(resulttarget, resulttargetlength, current->Data.Srv.pNameTarget);
566
+ *resultport = current->Data.Srv.wPort;
567
+ set = 1;
568
+
569
+ current = NULL;
570
+ } else {
571
+ current = current->pNext;
572
+ }
573
+ }
574
+ }
575
+
576
+ pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
577
+ }
578
+
579
+ FreeLibrary(hdnsapi);
580
+ }
581
+ }
582
+
583
+ /* if dnsapi didn't work/isn't there, try querying the dns server manually */
584
+ if (!set)
585
+ {
586
+ unsigned char buf[65536];
587
+ struct dnsquery_header header;
588
+ struct dnsquery_question question;
589
+ int offset = 0;
590
+ int addrlen;
591
+ sock_t sock;
592
+ struct sockaddr_in dnsaddr;
593
+ char dnsserverips[16][256];
594
+ int numdnsservers = 0;
595
+ int j;
596
+
597
+ /* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
598
+ if (!numdnsservers)
599
+ {
600
+ HINSTANCE hiphlpapi = NULL;
601
+ DWORD (WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
602
+
603
+ if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
604
+ {
605
+ pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
606
+
607
+ if (pGetNetworkParams)
608
+ {
609
+ FIXED_INFO *fi;
610
+ ULONG len;
611
+ DWORD error;
612
+ char buffer[65535];
613
+
614
+ len = 65535;
615
+ fi = buffer;
616
+
617
+ if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
618
+ {
619
+ IP_ADDR_STRING *pias = &(fi->DnsServerList);
620
+
621
+ while (pias && numdnsservers < 16)
622
+ {
623
+ strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
624
+ pias = pias->Next;
625
+ }
626
+ }
627
+ }
628
+ }
629
+ FreeLibrary(hiphlpapi);
630
+ }
631
+
632
+ /* Next, try getting the DNS server ips from the registry */
633
+ if (!numdnsservers)
634
+ {
635
+ HKEY search;
636
+ LONG error;
637
+
638
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
639
+
640
+ if (error != ERROR_SUCCESS)
641
+ {
642
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
643
+ }
644
+
645
+ if (error == ERROR_SUCCESS)
646
+ {
647
+ char name[512];
648
+ DWORD len = 512;
649
+
650
+ error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
651
+
652
+ if (error != ERROR_SUCCESS)
653
+ {
654
+ error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
655
+ }
656
+
657
+ if (error == ERROR_SUCCESS)
658
+ {
659
+ char *parse = "0123456789.", *start, *end;
660
+ start = name;
661
+ end = name;
662
+ name[len] = '\0';
663
+
664
+ while (*start && numdnsservers < 16)
665
+ {
666
+ while (strchr(parse, *end))
667
+ {
668
+ end++;
669
+ }
670
+
671
+ strncpy(dnsserverips[numdnsservers++], start, end - start);
672
+
673
+ while (*end && !strchr(parse, *end))
674
+ {
675
+ end++;
676
+ }
677
+
678
+ start = end;
679
+ }
680
+ }
681
+ }
682
+
683
+ RegCloseKey(search);
684
+ }
685
+
686
+ if (!numdnsservers)
687
+ {
688
+ HKEY searchlist;
689
+ LONG error;
690
+
691
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
692
+
693
+ if (error == ERROR_SUCCESS)
694
+ {
695
+ unsigned int i;
696
+ DWORD numinterfaces = 0;
697
+
698
+ RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
699
+
700
+ for (i = 0; i < numinterfaces; i++)
701
+ {
702
+ char name[512];
703
+ DWORD len = 512;
704
+ HKEY searchentry;
705
+
706
+ RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
707
+
708
+ if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
709
+ {
710
+ if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
711
+ {
712
+ char *parse = "0123456789.", *start, *end;
713
+ start = name;
714
+ end = name;
715
+ name[len] = '\0';
716
+
717
+ while (*start && numdnsservers < 16)
718
+ {
719
+ while (strchr(parse, *end))
720
+ {
721
+ end++;
722
+ }
723
+
724
+ strncpy(dnsserverips[numdnsservers++], start, end - start);
725
+
726
+ while (*end && !strchr(parse, *end))
727
+ {
728
+ end++;
729
+ }
730
+
731
+ start = end;
732
+ }
733
+ }
734
+ else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
735
+ {
736
+ char *parse = "0123456789.", *start, *end;
737
+ start = name;
738
+ end = name;
739
+ name[len] = '\0';
740
+
741
+ while (*start && numdnsservers < 16)
742
+ {
743
+ while (strchr(parse, *end))
744
+ {
745
+ end++;
746
+ }
747
+
748
+ strncpy(dnsserverips[numdnsservers++], start, end - start);
749
+
750
+ while (*end && !strchr(parse, *end))
751
+ {
752
+ end++;
753
+ }
754
+
755
+ start = end;
756
+ }
757
+ }
758
+ RegCloseKey(searchentry);
759
+ }
760
+ }
761
+ RegCloseKey(searchlist);
762
+ }
763
+ }
764
+
765
+ /* If we have a DNS server, use it */
766
+ if (numdnsservers)
767
+ {
768
+ ULONG nonblocking = 1;
769
+ int i;
770
+ int insize;
771
+
772
+ memset(&header, 0, sizeof(header));
773
+ header.id = 12345; /* FIXME: Get a better id here */
774
+ header.rd = 1;
775
+ header.qdcount = 1;
776
+
777
+ netbuf_add_dnsquery_header(buf, 65536, &offset, &header);
778
+
779
+ memset(&question, 0, sizeof(question));
780
+ strncpy(question.qname, fulldomain, 1024);
781
+ question.qtype = 33; /* SRV */
782
+ question.qclass = 1; /* INTERNET! */
783
+
784
+ netbuf_add_dnsquery_question(buf, 65536, &offset, &question);
785
+
786
+ insize = 0;
787
+ for (i = 0; i < numdnsservers && insize <= 0; i++)
788
+ {
789
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
790
+ ioctlsocket(sock, FIONBIO, &nonblocking);
791
+
792
+ memset(&dnsaddr, 0, sizeof(dnsaddr));
793
+
794
+ dnsaddr.sin_family = AF_INET;
795
+ dnsaddr.sin_port = htons(53);
796
+ dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
797
+
798
+ addrlen = sizeof(dnsaddr);
799
+ sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
800
+ for (j = 0; j < 50; j++)
801
+ {
802
+ insize = recvfrom(sock, (char *)buf, 65536, 0, (struct sockaddr *)&dnsaddr, &addrlen);
803
+ if (insize == SOCKET_ERROR)
804
+ {
805
+ if (sock_error() == WSAEWOULDBLOCK)
806
+ {
807
+ Sleep(100);
808
+ }
809
+ else
810
+ {
811
+ break;
812
+ }
813
+ }
814
+ else
815
+ {
816
+ break;
817
+ }
818
+ }
819
+
820
+ closesocket(sock);
821
+ }
822
+
823
+ offset = insize;
824
+
825
+ if (offset > 0)
826
+ {
827
+ int len = offset;
828
+ int i;
829
+ struct dnsquery_header header;
830
+ struct dnsquery_question question;
831
+ struct dnsquery_resourcerecord rr;
832
+
833
+ offset = 0;
834
+ netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
835
+
836
+ for (i = 0; i < header.qdcount; i++)
837
+ {
838
+ netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
839
+ }
840
+
841
+ for (i = 0; i < header.ancount; i++)
842
+ {
843
+ netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
844
+
845
+ if (rr.type == 33)
846
+ {
847
+ struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
848
+
849
+ snprintf(resulttarget, resulttargetlength, srvrdata->target);
850
+ *resultport = srvrdata->port;
851
+ set = 1;
852
+ }
853
+ }
854
+
855
+ for (i = 0; i < header.ancount; i++)
856
+ {
857
+ netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
858
+ }
859
+ }
860
+ }
861
+
862
+ }
863
+
864
+ #else
865
+ if (!set) {
866
+ unsigned char buf[65535];
867
+ int len;
868
+
869
+ if ((len = res_query(fulldomain, C_IN, T_SRV, buf, 65535)) > 0) {
870
+ int offset;
871
+ int i;
872
+ struct dnsquery_header header;
873
+ struct dnsquery_question question;
874
+ struct dnsquery_resourcerecord rr;
875
+
876
+ offset = 0;
877
+ netbuf_get_dnsquery_header(buf, 65536, &offset, &header);
878
+
879
+ for (i = 0; i < header.qdcount; i++) {
880
+ netbuf_get_dnsquery_question(buf, 65536, &offset, &question);
881
+ }
882
+
883
+ for (i = 0; i < header.ancount; i++) {
884
+ netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
885
+
886
+ if (rr.type == 33) {
887
+ struct dnsquery_srvrdata *srvrdata = &(rr.rdata);
888
+
889
+ snprintf(resulttarget, resulttargetlength,
890
+ srvrdata->target);
891
+ *resultport = srvrdata->port;
892
+ set = 1;
893
+ }
894
+ }
895
+
896
+ for (i = 0; i < header.ancount; i++) {
897
+ netbuf_get_dnsquery_resourcerecord(buf, 65536, &offset, &rr);
898
+ }
899
+ }
900
+ }
901
+ #endif
902
+
903
+ if (!set)
904
+ {
905
+ snprintf(resulttarget, resulttargetlength, domain);
906
+ *resultport = 5222;
907
+ return 0;
908
+ }
909
+
910
+ return 1;
911
+ }