comparison libpurple/protocols/gg/lib/resolver.c @ 32763:326591e64aaa

Gadu-Gadu: move our win32 resolver out of libgadu sources. Refs #343
author tomkiewicz@cpw.pidgin.im
date Mon, 17 Oct 2011 21:25:53 +0000
parents b8646c6ae19a
children ef01f180114b
comparison
equal deleted inserted replaced
32762:9c9143e32b6c 32763:326591e64aaa
317 */ 317 */
318 struct gg_resolver_fork_data { 318 struct gg_resolver_fork_data {
319 int pid; /*< Identyfikator procesu */ 319 int pid; /*< Identyfikator procesu */
320 }; 320 };
321 321
322 #ifdef _WIN32
323 /**
324 * Deal with the fact that you can't select() on a win32 file fd.
325 * This makes it practically impossible to tie into purple's event loop.
326 *
327 * -This is thanks to Tor Lillqvist.
328 * XXX - Move this to where the rest of the the win32 compatiblity stuff goes when we push the changes back to libgadu.
329 */
330 static int
331 socket_pipe (int *fds)
332 {
333 SOCKET temp, socket1 = -1, socket2 = -1;
334 struct sockaddr_in saddr;
335 int len;
336 u_long arg;
337 fd_set read_set, write_set;
338 struct timeval tv;
339
340 temp = socket(AF_INET, SOCK_STREAM, 0);
341
342 if (temp == INVALID_SOCKET) {
343 goto out0;
344 }
345
346 arg = 1;
347 if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) {
348 goto out0;
349 }
350
351 memset(&saddr, 0, sizeof(saddr));
352 saddr.sin_family = AF_INET;
353 saddr.sin_port = 0;
354 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
355
356 if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) {
357 goto out0;
358 }
359
360 if (listen(temp, 1) == SOCKET_ERROR) {
361 goto out0;
362 }
363
364 len = sizeof(saddr);
365 if (getsockname(temp, (struct sockaddr *)&saddr, &len)) {
366 goto out0;
367 }
368
369 socket1 = socket(AF_INET, SOCK_STREAM, 0);
370
371 if (socket1 == INVALID_SOCKET) {
372 goto out0;
373 }
374
375 arg = 1;
376 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
377 goto out1;
378 }
379
380 if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR ||
381 WSAGetLastError() != WSAEWOULDBLOCK) {
382 goto out1;
383 }
384
385 FD_ZERO(&read_set);
386 FD_SET(temp, &read_set);
387
388 tv.tv_sec = 0;
389 tv.tv_usec = 0;
390
391 if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
392 goto out1;
393 }
394
395 if (!FD_ISSET(temp, &read_set)) {
396 goto out1;
397 }
398
399 socket2 = accept(temp, (struct sockaddr *) &saddr, &len);
400 if (socket2 == INVALID_SOCKET) {
401 goto out1;
402 }
403
404 FD_ZERO(&write_set);
405 FD_SET(socket1, &write_set);
406
407 tv.tv_sec = 0;
408 tv.tv_usec = 0;
409
410 if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
411 goto out2;
412 }
413
414 if (!FD_ISSET(socket1, &write_set)) {
415 goto out2;
416 }
417
418 arg = 0;
419 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
420 goto out2;
421 }
422
423 arg = 0;
424 if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) {
425 goto out2;
426 }
427
428 fds[0] = socket1;
429 fds[1] = socket2;
430
431 closesocket (temp);
432
433 return 0;
434
435 out2:
436 closesocket (socket2);
437 out1:
438 closesocket (socket1);
439 out0:
440 closesocket (temp);
441 errno = EIO; /* XXX */
442
443 return -1;
444 }
445 #endif
446
447
448
449 #ifdef _WIN32
450 struct gg_resolve_win32thread_data {
451 char *hostname;
452 int fd;
453 };
454
455 static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg)
456 {
457 struct gg_resolve_win32thread_data *d = arg;
458 struct in_addr addr_ip[2], *addr_list;
459 int addr_count;
460
461 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() host: %s, fd: %i called\n", d->hostname, d->fd);
462
463 if ((addr_ip[0].s_addr = inet_addr(d->hostname)) == INADDR_NONE) {
464 /* W przypadku błędu gg_gethostbyname_real() zwróci -1
465 * i nie zmieni &addr. Tam jest już INADDR_NONE,
466 * więc nie musimy robić nic więcej. */
467 if (gg_gethostbyname_real(d->hostname, &addr_list, &addr_count, 0) == -1)
468 {
469 addr_list = addr_ip;
470 }
471 } else {
472 addr_list = addr_ip;
473 addr_ip[1].s_addr = INADDR_NONE;
474 addr_count = 1;
475 }
476
477 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() count = %d\n", addr_count);
478
479 write(d->fd, addr_list, (addr_count+1) * sizeof(struct in_addr));
480 close(d->fd);
481
482 free(d->hostname);
483 d->hostname = NULL;
484
485 free(d);
486
487 if (addr_list != addr_ip)
488 free(addr_list);
489
490 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_thread() done\n");
491
492 return 0;
493 }
494
495
496 static int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname)
497 {
498 struct gg_resolve_win32thread_data *d = NULL;
499 HANDLE h;
500 DWORD dwTId;
501 int pipes[2], new_errno;
502
503 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname);
504
505 if (!resolver || !fd || !hostname) {
506 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n");
507 errno = EFAULT;
508 return -1;
509 }
510
511 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() creating pipes...\n");
512
513 if (socket_pipe(pipes) == -1) {
514 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno));
515 return -1;
516 }
517
518 if (!(d = malloc(sizeof(*d)))) {
519 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n");
520 new_errno = errno;
521 goto cleanup;
522 }
523
524 d->hostname = NULL;
525
526 if (!(d->hostname = strdup(hostname))) {
527 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n");
528 new_errno = errno;
529 goto cleanup;
530 }
531
532 d->fd = pipes[1];
533
534 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() creating thread...\n");
535
536 h = CreateThread(NULL, 0, gg_resolve_win32thread_thread,
537 d, 0, &dwTId);
538
539 if (h == NULL) {
540 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n");
541 new_errno = errno;
542 goto cleanup;
543 }
544
545 *resolver = h;
546 *fd = pipes[0];
547
548 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() done\n");
549
550 return 0;
551
552 cleanup:
553 if (d) {
554 free(d->hostname);
555 free(d);
556 }
557
558 close(pipes[0]);
559 close(pipes[1]);
560
561 errno = new_errno;
562
563 return -1;
564
565 }
566
567 static void gg_resolve_win32thread_cleanup(void **priv_data, int force)
568 {
569 struct gg_resolve_win32thread_data *data;
570
571 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() force: %i called\n", force);
572
573 if (priv_data == NULL || *priv_data == NULL)
574 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() priv_data: NULL\n");
575 return;
576
577 data = (struct gg_resolve_win32thread_data*) *priv_data;
578 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() data: %s called\n", data->hostname);
579 *priv_data = NULL;
580
581 if (force) {
582 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() force called\n", force);
583 //pthread_cancel(data->thread);
584 //pthread_join(data->thread, NULL);
585 }
586
587 free(data->hostname);
588 data->hostname = NULL;
589
590 if (data->fd != -1) {
591 close(data->fd);
592 data->fd = -1;
593 }
594 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread_cleanup() done\n");
595 free(data);
596 }
597 #endif
598
599 #ifndef _WIN32 322 #ifndef _WIN32
600 /** 323 /**
601 * \internal Rozwiązuje nazwę serwera w osobnym procesie. 324 * \internal Rozwiązuje nazwę serwera w osobnym procesie.
602 * 325 *
603 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania 326 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania
871 gs->resolver_cleanup = gg_global_resolver_cleanup; 594 gs->resolver_cleanup = gg_global_resolver_cleanup;
872 return 0; 595 return 0;
873 } 596 }
874 597
875 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) 598 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT)
876 # ifdef _WIN32
877 type = GG_RESOLVER_WIN32;
878 # else
879 type = GG_RESOLVER_FORK; 599 type = GG_RESOLVER_FORK;
880 # endif
881 #else 600 #else
882 type = GG_RESOLVER_PTHREAD; 601 type = GG_RESOLVER_PTHREAD;
883 #endif 602 #endif
884 } 603 }
885 604
886 switch (type) { 605 switch (type) {
887 #ifdef _WIN32 606 #ifdef GG_CONFIG_HAVE_FORK
888 case GG_RESOLVER_WIN32:
889 gs->resolver_type = type;
890 gs->resolver_start = gg_resolve_win32thread;
891 gs->resolver_cleanup = gg_resolve_win32thread_cleanup;
892 return 0;
893 #else
894 case GG_RESOLVER_FORK: 607 case GG_RESOLVER_FORK:
895 gs->resolver_type = type; 608 gs->resolver_type = type;
896 gs->resolver_start = gg_resolver_fork_start; 609 gs->resolver_start = gg_resolver_fork_start;
897 gs->resolver_cleanup = gg_resolver_fork_cleanup; 610 gs->resolver_cleanup = gg_resolver_fork_cleanup;
898 return 0; 611 return 0;
992 gh->resolver_cleanup = gg_global_resolver_cleanup; 705 gh->resolver_cleanup = gg_global_resolver_cleanup;
993 return 0; 706 return 0;
994 } 707 }
995 708
996 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) 709 #if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT)
997 # ifdef _WIN32
998 type = GG_RESOLVER_WIN32;
999 # else
1000 type = GG_RESOLVER_FORK; 710 type = GG_RESOLVER_FORK;
1001 # endif
1002 #else 711 #else
1003 type = GG_RESOLVER_PTHREAD; 712 type = GG_RESOLVER_PTHREAD;
1004 #endif 713 #endif
1005 } 714 }
1006 715
1007 switch (type) { 716 switch (type) {
1008 #ifdef _WIN32 717 #ifdef GG_CONFIG_HAVE_FORK
1009 case GG_RESOLVER_WIN32:
1010 gh->resolver_type = type;
1011 gh->resolver_start = gg_resolve_win32thread;
1012 gh->resolver_cleanup = gg_resolve_win32thread_cleanup;
1013 return 0;
1014 #else
1015 case GG_RESOLVER_FORK: 718 case GG_RESOLVER_FORK:
1016 gh->resolver_type = type; 719 gh->resolver_type = type;
1017 gh->resolver_start = gg_resolver_fork_start; 720 gh->resolver_start = gg_resolver_fork_start;
1018 gh->resolver_cleanup = gg_resolver_fork_cleanup; 721 gh->resolver_cleanup = gg_resolver_fork_cleanup;
1019 return 0; 722 return 0;
1087 gg_global_resolver_type = type; 790 gg_global_resolver_type = type;
1088 gg_global_resolver_start = NULL; 791 gg_global_resolver_start = NULL;
1089 gg_global_resolver_cleanup = NULL; 792 gg_global_resolver_cleanup = NULL;
1090 return 0; 793 return 0;
1091 794
1092 #ifdef _WIN32 795 #ifdef GG_CONFIG_HAVE_FORK
1093 case GG_RESOLVER_WIN32:
1094 gg_global_resolver_type = type;
1095 gg_global_resolver_start = gg_resolve_win32thread;
1096 gg_global_resolver_cleanup = gg_resolve_win32thread_cleanup;
1097 return 0;
1098 #else
1099 case GG_RESOLVER_FORK: 796 case GG_RESOLVER_FORK:
1100 gg_global_resolver_type = type; 797 gg_global_resolver_type = type;
1101 gg_global_resolver_start = gg_resolver_fork_start; 798 gg_global_resolver_start = gg_resolver_fork_start;
1102 gg_global_resolver_cleanup = gg_resolver_fork_cleanup; 799 gg_global_resolver_cleanup = gg_resolver_fork_cleanup;
1103 return 0; 800 return 0;