libpurple/protocols/gg/lib/resolver.c

branch
release-2.x.y
changeset 35627
fd11790cc4d6
parent 35617
c9069e0e3c36
child 35630
8e5d0d726b09
child 35645
0143226782bb
equal deleted inserted replaced
35625:783e5cce1a46 35627:fd11790cc4d6
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);
153 if (ret == 0 && he_ptr != NULL && he_ptr->h_addr_list[0] != NULL) { 159 if (ret == 0 && he_ptr != NULL && he_ptr->h_addr_list[0] != NULL) {
154 int i; 160 int i;
155 161
156 /* Policz liczbę adresów */ 162 /* Policz liczbę adresów */
157 163
158 for (i = 0; he_ptr->h_addr_list[i] != NULL; i++) 164 for (i = 0; he_ptr->h_addr_list[i] != NULL; i++);
159 ;
160 165
161 /* Zaalokuj */ 166 /* Zaalokuj */
162 167
163 #ifdef GG_CONFIG_HAVE_PTHREAD 168 #ifdef GG_CONFIG_HAVE_PTHREAD
164 if (pthread) 169 if (pthread)
223 if (he == NULL || he->h_addr_list[0] == NULL) 228 if (he == NULL || he->h_addr_list[0] == NULL)
224 return -1; 229 return -1;
225 230
226 /* Policz liczbę adresów */ 231 /* Policz liczbę adresów */
227 232
228 for (i = 0; he->h_addr_list[i] != NULL; i++) 233 for (i = 0; he->h_addr_list[i] != NULL; i++);
229 ;
230 234
231 /* Zaalokuj */ 235 /* Zaalokuj */
232 236
233 #ifdef GG_CONFIG_HAVE_PTHREAD 237 #ifdef GG_CONFIG_HAVE_PTHREAD
234 if (pthread) 238 if (pthread)
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;
707 } 743 }
708 744
709 close(pipes[0]); 745 close(pipes[0]);
710 close(pipes[1]); 746 close(pipes[1]);
711 747
748 if (mutex)
749 DeleteCriticalSection(mutex);
750
712 errno = new_errno; 751 errno = new_errno;
713 752
714 return -1; 753 return -1;
715 } 754 }
716 755
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" &mdash; wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda 882 * - \c "int *fd" &mdash; wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
834 * - \c "void **priv_data" &mdash; wskaźnik na zmienną, gdzie można umieścić wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy 883 * - \c "void **priv_data" &mdash; 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" &mdash; nazwa serwera do rozwiązania 885 * - \c "const char *name" &mdash; 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" &mdash; 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" &mdash; wskaźnik na zmienną przechowującą wskaźnik
839 * - \c "int force" &mdash; 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" &mdash; 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 }
1065 return read(fd, buf, len); 1123 return read(fd, buf, len);
1066 #else 1124 #else
1067 return recv(fd, buf, len, 0); 1125 return recv(fd, buf, len, 0);
1068 #endif 1126 #endif
1069 } 1127 }
1070

mercurial