| 120 if (pthread) |
120 if (pthread) |
| 121 pthread_setcancelstate(old_state, NULL); |
121 pthread_setcancelstate(old_state, NULL); |
| 122 #endif |
122 #endif |
| 123 |
123 |
| 124 if (buf != NULL) { |
124 if (buf != NULL) { |
| |
125 while (1) { |
| 125 #ifndef sun |
126 #ifndef sun |
| 126 while ((ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop)) == ERANGE) { |
127 ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop); |
| |
128 if (ret != ERANGE) |
| |
129 break; |
| 127 #else |
130 #else |
| 128 while (((he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop)) == NULL) && (errno == ERANGE)) { |
131 he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop); |
| 129 #endif |
132 if (he_ptr != NULL || errno != ERANGE) |
| |
133 break; |
| |
134 #endif |
| |
135 |
| 130 buf_len *= 2; |
136 buf_len *= 2; |
| 131 |
137 |
| 132 #ifdef GG_CONFIG_HAVE_PTHREAD |
138 #ifdef GG_CONFIG_HAVE_PTHREAD |
| 133 if (pthread) |
139 if (pthread) |
| 134 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); |
140 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); |
| 304 } else { |
308 } else { |
| 305 addr_ip[1].s_addr = INADDR_NONE; |
309 addr_ip[1].s_addr = INADDR_NONE; |
| 306 addr_count = 1; |
310 addr_count = 1; |
| 307 } |
311 } |
| 308 |
312 |
| 309 if (send(fd, addr_list != NULL ? addr_list : addr_ip, (addr_count + 1) * sizeof(struct in_addr), 0) != (int)((addr_count + 1) * sizeof(struct in_addr))) |
313 if (send(fd, addr_list != NULL ? addr_list : addr_ip, |
| |
314 (addr_count + 1) * sizeof(struct in_addr), 0) != |
| |
315 (int)((addr_count + 1) * sizeof(struct in_addr))) |
| |
316 { |
| 310 res = -1; |
317 res = -1; |
| |
318 } |
| 311 |
319 |
| 312 #ifdef GG_CONFIG_HAVE_PTHREAD |
320 #ifdef GG_CONFIG_HAVE_PTHREAD |
| 313 if (pthread) |
321 if (pthread) |
| 314 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); |
322 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); |
| 315 #endif |
323 #endif |
| 362 /** |
370 /** |
| 363 * \internal Rozwiązuje nazwę serwera w osobnym procesie. |
371 * \internal Rozwiązuje nazwę serwera w osobnym procesie. |
| 364 * |
372 * |
| 365 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania |
373 * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania |
| 366 * nazwy serwera. W tym celu tworzona jest para gniazd, nowy proces i dopiero |
374 * nazwy serwera. W tym celu tworzona jest para gniazd, nowy proces i dopiero |
| 367 * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu |
375 * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu |
| 368 * zapisuje się w strukturze sieci i czeka na dane w postaci struktury |
376 * zapisuje się w strukturze sieci i czeka na dane w postaci struktury |
| 369 * \c in_addr. Jeśli nie znaleziono nazwy, zwracana jest \c INADDR_NONE. |
377 * \c in_addr. Jeśli nie znaleziono nazwy, zwracana jest \c INADDR_NONE. |
| 370 * |
378 * |
| 371 * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda |
379 * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda |
| 372 * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik |
380 * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik |
| 394 gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() out of memory for resolver data\n"); |
402 gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() out of memory for resolver data\n"); |
| 395 return -1; |
403 return -1; |
| 396 } |
404 } |
| 397 |
405 |
| 398 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
406 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
| 399 gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); |
407 gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable " |
| |
408 "to create pipes (errno=%d, %s)\n", |
| |
409 errno, strerror(errno)); |
| 400 free(data); |
410 free(data); |
| 401 return -1; |
411 return -1; |
| 402 } |
412 } |
| 403 |
413 |
| 404 data->pid = fork(); |
414 data->pid = fork(); |
| 562 gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory for resolver data\n"); |
572 gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory for resolver data\n"); |
| 563 return -1; |
573 return -1; |
| 564 } |
574 } |
| 565 |
575 |
| 566 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
576 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
| 567 gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); |
577 gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable " |
| |
578 "to create pipes (errno=%d, %s)\n", |
| |
579 errno, strerror(errno)); |
| 568 free(data); |
580 free(data); |
| 569 return -1; |
581 return -1; |
| 570 } |
582 } |
| 571 |
583 |
| 572 data->hostname = strdup(hostname); |
584 data->hostname = strdup(hostname); |
| 613 /** |
625 /** |
| 614 * \internal Struktura przekazywana do wątku rozwiązującego nazwę. |
626 * \internal Struktura przekazywana do wątku rozwiązującego nazwę. |
| 615 */ |
627 */ |
| 616 struct gg_resolver_win32_data { |
628 struct gg_resolver_win32_data { |
| 617 HANDLE thread; /*< Uchwyt wątku */ |
629 HANDLE thread; /*< Uchwyt wątku */ |
| |
630 CRITICAL_SECTION mutex; /*< Semafor wątku */ |
| 618 char *hostname; /*< Nazwa serwera */ |
631 char *hostname; /*< Nazwa serwera */ |
| 619 int wfd; /*< Deskryptor do zapisu */ |
632 int wfd; /*< Deskryptor do zapisu */ |
| |
633 int orphan; /*< Wątek powinien sam po sobie posprzątać */ |
| |
634 int finished; /*< Wątek już skończył pracę */ |
| 620 }; |
635 }; |
| 621 |
636 |
| 622 /** |
637 /** |
| 623 * \internal Wątek rozwiązujący nazwę. |
638 * \internal Wątek rozwiązujący nazwę. |
| 624 * |
639 * |
| 625 * \param arg Wskaźnik na strukturę \c gg_resolver_win32_data |
640 * \param arg Wskaźnik na strukturę \c gg_resolver_win32_data |
| 626 */ |
641 */ |
| 627 static DWORD WINAPI gg_resolver_win32_thread(void *arg) |
642 static DWORD WINAPI gg_resolver_win32_thread(void *arg) |
| 628 { |
643 { |
| 629 struct gg_resolver_win32_data *data = arg; |
644 struct gg_resolver_win32_data *data = arg; |
| 630 |
645 int result, is_orphan; |
| 631 if (gg_resolver_run(data->wfd, data->hostname, 0) == -1) |
646 |
| 632 ExitThread(-1); |
647 result = gg_resolver_run(data->wfd, data->hostname, 0); |
| 633 else |
648 |
| 634 ExitThread(0); |
649 EnterCriticalSection(&data->mutex); |
| 635 |
650 is_orphan = data->orphan; |
| 636 return 0; /* żeby kompilator nie marudził */ |
651 data->finished = 1; |
| |
652 LeaveCriticalSection(&data->mutex); |
| |
653 |
| |
654 if (is_orphan) { |
| |
655 CloseHandle(data->thread); |
| |
656 DeleteCriticalSection(&data->mutex); |
| |
657 close(data->wfd); |
| |
658 free(data->hostname); |
| |
659 free(data); |
| |
660 } |
| |
661 |
| |
662 ExitThread(result); |
| |
663 return 0; /* żeby kompilator nie marudził */ |
| 637 } |
664 } |
| 638 |
665 |
| 639 /** |
666 /** |
| 640 * \internal Rozwiązuje nazwę serwera w osobnym wątku. |
667 * \internal Rozwiązuje nazwę serwera w osobnym wątku. |
| 641 * |
668 * |
| 652 */ |
679 */ |
| 653 static int gg_resolver_win32_start(int *fd, void **priv_data, const char *hostname) |
680 static int gg_resolver_win32_start(int *fd, void **priv_data, const char *hostname) |
| 654 { |
681 { |
| 655 struct gg_resolver_win32_data *data = NULL; |
682 struct gg_resolver_win32_data *data = NULL; |
| 656 int pipes[2], new_errno; |
683 int pipes[2], new_errno; |
| |
684 CRITICAL_SECTION *mutex = NULL; |
| 657 |
685 |
| 658 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_win32_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); |
686 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_win32_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); |
| 659 |
687 |
| 660 if (fd == NULL || priv_data == NULL || hostname == NULL) { |
688 if (fd == NULL || priv_data == NULL || hostname == NULL) { |
| 661 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() invalid arguments\n"); |
689 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() invalid arguments\n"); |
| 668 if (data == NULL) { |
696 if (data == NULL) { |
| 669 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory for resolver data\n"); |
697 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory for resolver data\n"); |
| 670 return -1; |
698 return -1; |
| 671 } |
699 } |
| 672 |
700 |
| |
701 data->orphan = 0; |
| |
702 data->finished = 0; |
| |
703 |
| 673 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
704 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { |
| 674 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); |
705 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to " |
| |
706 "create pipes (errno=%d, %s)\n", |
| |
707 errno, strerror(errno)); |
| 675 free(data); |
708 free(data); |
| 676 return -1; |
709 return -1; |
| 677 } |
710 } |
| 678 |
711 |
| 679 data->hostname = strdup(hostname); |
712 data->hostname = strdup(hostname); |
| 683 new_errno = errno; |
716 new_errno = errno; |
| 684 goto cleanup; |
717 goto cleanup; |
| 685 } |
718 } |
| 686 |
719 |
| 687 data->wfd = pipes[1]; |
720 data->wfd = pipes[1]; |
| |
721 |
| |
722 mutex = &data->mutex; |
| |
723 InitializeCriticalSection(mutex); |
| 688 |
724 |
| 689 data->thread = CreateThread(NULL, 0, gg_resolver_win32_thread, data, 0, NULL); |
725 data->thread = CreateThread(NULL, 0, gg_resolver_win32_thread, data, 0, NULL); |
| 690 if (!data->thread) { |
726 if (!data->thread) { |
| 691 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create thread\n"); |
727 gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create thread\n"); |
| 692 new_errno = errno; |
728 new_errno = errno; |
| 733 |
772 |
| 734 data = (struct gg_resolver_win32_data *) *priv_data; |
773 data = (struct gg_resolver_win32_data *) *priv_data; |
| 735 *priv_data = NULL; |
774 *priv_data = NULL; |
| 736 |
775 |
| 737 if (WaitForSingleObject(data->thread, 0) == WAIT_TIMEOUT) { |
776 if (WaitForSingleObject(data->thread, 0) == WAIT_TIMEOUT) { |
| 738 if (force) |
777 int finished; |
| 739 TerminateThread(data->thread, 0); |
778 /* We cannot call TerminateThread here - it doesn't |
| |
779 * release critical section locks (see MSDN docs). |
| |
780 * if (force) TerminateThread(data->thread, 0); |
| |
781 */ |
| |
782 EnterCriticalSection(&data->mutex); |
| |
783 finished = data->finished; |
| |
784 if (!finished) |
| |
785 data->orphan = 1; |
| |
786 LeaveCriticalSection(&data->mutex); |
| |
787 if (!finished) |
| |
788 return; |
| 740 } |
789 } |
| 741 |
790 |
| 742 CloseHandle(data->thread); |
791 CloseHandle(data->thread); |
| 743 |
792 DeleteCriticalSection(&data->mutex); |
| 744 close(data->wfd); |
793 close(data->wfd); |
| 745 free(data->hostname); |
794 free(data->hostname); |
| 746 free(data); |
795 free(data); |
| 747 } |
796 } |
| 748 |
797 |
| 829 * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy |
878 * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy |
| 830 * \param resolver_cleanup Funkcja zwalniająca zasoby |
879 * \param resolver_cleanup Funkcja zwalniająca zasoby |
| 831 * |
880 * |
| 832 * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco: |
881 * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco: |
| 833 * - \c "int *fd" — wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda |
882 * - \c "int *fd" — wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda |
| 834 * - \c "void **priv_data" — wskaźnik na zmienną, gdzie można umieścić wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy |
883 * - \c "void **priv_data" — wskaźnik na zmienną, gdzie można umieścić |
| |
884 * wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy |
| 835 * - \c "const char *name" — nazwa serwera do rozwiązania |
885 * - \c "const char *name" — nazwa serwera do rozwiązania |
| 836 * |
886 * |
| 837 * Parametry funkcji zwalniającej zasoby wyglądają następująco: |
887 * Parametry funkcji zwalniającej zasoby wyglądają następująco: |
| 838 * - \c "void **priv_data" — wskaźnik na zmienną przechowującą wskaźnik do prywatnych danych, należy go ustawić na \c NULL po zakończeniu |
888 * - \c "void **priv_data" — wskaźnik na zmienną przechowującą wskaźnik |
| 839 * - \c "int force" — flaga mówiąca o tym, że zasoby są zwalniane przed zakończeniem rozwiązywania nazwy, np. z powodu zamknięcia sesji. |
889 * do prywatnych danych, należy go ustawić na \c NULL po zakończeniu |
| |
890 * - \c "int force" — flaga mówiąca o tym, że zasoby są zwalniane przed |
| |
891 * zakończeniem rozwiązywania nazwy, np. z powodu zamknięcia sesji. |
| 840 * |
892 * |
| 841 * Własny kod rozwiązywania nazwy powinien stworzyć potok, parę gniazd lub |
893 * Własny kod rozwiązywania nazwy powinien stworzyć potok, parę gniazd lub |
| 842 * inny deskryptor pozwalający na co najmniej odbiór danych i przekazać go |
894 * inny deskryptor pozwalający na co najmniej odbiór danych i przekazać go |
| 843 * w parametrze \c fd. Na platformie Windows możliwe jest przekazanie jedynie |
895 * w parametrze \c fd. Na platformie Windows możliwe jest przekazanie jedynie |
| 844 * deskryptora gniazda. Po zakończeniu rozwiązywania nazwy powinien wysłać |
896 * deskryptora gniazda. Po zakończeniu rozwiązywania nazwy powinien wysłać |
| 849 * nazwy, np. za pomocą funkcji \c gg_logoff(), funkcja zwalniająca zasoby |
901 * nazwy, np. za pomocą funkcji \c gg_logoff(), funkcja zwalniająca zasoby |
| 850 * zostanie wywołana z parametrem \c force równym \c 1. |
902 * zostanie wywołana z parametrem \c force równym \c 1. |
| 851 * |
903 * |
| 852 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
904 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
| 853 */ |
905 */ |
| 854 int gg_session_set_custom_resolver(struct gg_session *gs, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) |
906 int gg_session_set_custom_resolver(struct gg_session *gs, |
| |
907 int (*resolver_start)(int*, void**, const char*), |
| |
908 void (*resolver_cleanup)(void**, int)) |
| 855 { |
909 { |
| 856 GG_SESSION_CHECK(gs, -1); |
910 GG_SESSION_CHECK(gs, -1); |
| 857 |
911 |
| 858 if (resolver_start == NULL || resolver_cleanup == NULL) { |
912 if (resolver_start == NULL || resolver_cleanup == NULL) { |
| 859 errno = EINVAL; |
913 errno = EINVAL; |
| 954 * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy |
1008 * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy |
| 955 * \param resolver_cleanup Funkcja zwalniająca zasoby |
1009 * \param resolver_cleanup Funkcja zwalniająca zasoby |
| 956 * |
1010 * |
| 957 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
1011 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
| 958 */ |
1012 */ |
| 959 int gg_http_set_custom_resolver(struct gg_http *gh, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) |
1013 int gg_http_set_custom_resolver(struct gg_http *gh, |
| |
1014 int (*resolver_start)(int*, void**, const char*), |
| |
1015 void (*resolver_cleanup)(void**, int)) |
| 960 { |
1016 { |
| 961 if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) { |
1017 if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) { |
| 962 errno = EINVAL; |
1018 errno = EINVAL; |
| 963 return -1; |
1019 return -1; |
| 964 } |
1020 } |
| 1034 * |
1090 * |
| 1035 * Patrz \ref gg_session_set_custom_resolver. |
1091 * Patrz \ref gg_session_set_custom_resolver. |
| 1036 * |
1092 * |
| 1037 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
1093 * \return 0 jeśli się powiodło, -1 w przypadku błędu |
| 1038 */ |
1094 */ |
| 1039 int gg_global_set_custom_resolver(int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) |
1095 int gg_global_set_custom_resolver( |
| |
1096 int (*resolver_start)(int*, void**, const char*), |
| |
1097 void (*resolver_cleanup)(void**, int)) |
| 1040 { |
1098 { |
| 1041 if (resolver_start == NULL || resolver_cleanup == NULL) { |
1099 if (resolver_start == NULL || resolver_cleanup == NULL) { |
| 1042 errno = EINVAL; |
1100 errno = EINVAL; |
| 1043 return -1; |
1101 return -1; |
| 1044 } |
1102 } |