--- a/libpurple/protocols/gg/lib/resolver.c Wed Mar 12 22:56:56 2014 +0100 +++ b/libpurple/protocols/gg/lib/resolver.c Thu Mar 13 00:09:23 2014 +0100 @@ -122,11 +122,17 @@ #endif if (buf != NULL) { + while (1) { #ifndef sun - while ((ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop)) == ERANGE) { + ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop); + if (ret != ERANGE) + break; #else - while (((he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop)) == NULL) && (errno == ERANGE)) { + he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop); + if (he_ptr != NULL || errno != ERANGE) + break; #endif + buf_len *= 2; #ifdef GG_CONFIG_HAVE_PTHREAD @@ -155,8 +161,7 @@ /* Policz liczbę adresów */ - for (i = 0; he_ptr->h_addr_list[i] != NULL; i++) - ; + for (i = 0; he_ptr->h_addr_list[i] != NULL; i++); /* Zaalokuj */ @@ -225,8 +230,7 @@ /* Policz liczbę adresów */ - for (i = 0; he->h_addr_list[i] != NULL; i++) - ; + for (i = 0; he->h_addr_list[i] != NULL; i++); /* Zaalokuj */ @@ -306,8 +310,12 @@ addr_count = 1; } - 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))) + 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))) + { res = -1; + } #ifdef GG_CONFIG_HAVE_PTHREAD if (pthread) @@ -364,7 +372,7 @@ * * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania * nazwy serwera. W tym celu tworzona jest para gniazd, nowy proces i dopiero - * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu + * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu * zapisuje się w strukturze sieci i czeka na dane w postaci struktury * \c in_addr. Jeśli nie znaleziono nazwy, zwracana jest \c INADDR_NONE. * @@ -396,7 +404,9 @@ } if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable " + "to create pipes (errno=%d, %s)\n", + errno, strerror(errno)); free(data); return -1; } @@ -564,7 +574,9 @@ } if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable " + "to create pipes (errno=%d, %s)\n", + errno, strerror(errno)); free(data); return -1; } @@ -615,8 +627,11 @@ */ struct gg_resolver_win32_data { HANDLE thread; /*< Uchwyt wątku */ + CRITICAL_SECTION mutex; /*< Semafor wątku */ char *hostname; /*< Nazwa serwera */ int wfd; /*< Deskryptor do zapisu */ + int orphan; /*< Wątek powinien sam po sobie posprzątać */ + int finished; /*< Wątek już skończył pracę */ }; /** @@ -627,13 +642,25 @@ static DWORD WINAPI gg_resolver_win32_thread(void *arg) { struct gg_resolver_win32_data *data = arg; + int result, is_orphan; - if (gg_resolver_run(data->wfd, data->hostname, 0) == -1) - ExitThread(-1); - else - ExitThread(0); + result = gg_resolver_run(data->wfd, data->hostname, 0); + + EnterCriticalSection(&data->mutex); + is_orphan = data->orphan; + data->finished = 1; + LeaveCriticalSection(&data->mutex); - return 0; /* żeby kompilator nie marudził */ + if (is_orphan) { + CloseHandle(data->thread); + DeleteCriticalSection(&data->mutex); + close(data->wfd); + free(data->hostname); + free(data); + } + + ExitThread(result); + return 0; /* żeby kompilator nie marudził */ } /** @@ -654,6 +681,7 @@ { struct gg_resolver_win32_data *data = NULL; int pipes[2], new_errno; + CRITICAL_SECTION *mutex = NULL; gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_win32_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); @@ -670,8 +698,13 @@ return -1; } + data->orphan = 0; + data->finished = 0; + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to " + "create pipes (errno=%d, %s)\n", + errno, strerror(errno)); free(data); return -1; } @@ -686,6 +719,9 @@ data->wfd = pipes[1]; + mutex = &data->mutex; + InitializeCriticalSection(mutex); + data->thread = CreateThread(NULL, 0, gg_resolver_win32_thread, data, 0, NULL); if (!data->thread) { gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create thread\n"); @@ -709,6 +745,9 @@ close(pipes[0]); close(pipes[1]); + if (mutex) + DeleteCriticalSection(mutex); + errno = new_errno; return -1; @@ -735,12 +774,22 @@ *priv_data = NULL; if (WaitForSingleObject(data->thread, 0) == WAIT_TIMEOUT) { - if (force) - TerminateThread(data->thread, 0); + int finished; + /* We cannot call TerminateThread here - it doesn't + * release critical section locks (see MSDN docs). + * if (force) TerminateThread(data->thread, 0); + */ + EnterCriticalSection(&data->mutex); + finished = data->finished; + if (!finished) + data->orphan = 1; + LeaveCriticalSection(&data->mutex); + if (!finished) + return; } CloseHandle(data->thread); - + DeleteCriticalSection(&data->mutex); close(data->wfd); free(data->hostname); free(data); @@ -831,12 +880,15 @@ * * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco: * - \c "int *fd" — wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda - * - \c "void **priv_data" — wskaźnik na zmienną, gdzie można umieścić wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy + * - \c "void **priv_data" — wskaźnik na zmienną, gdzie można umieścić + * wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy * - \c "const char *name" — nazwa serwera do rozwiązania * * Parametry funkcji zwalniającej zasoby wyglądają następująco: - * - \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 - * - \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. + * - \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 + * - \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. * * Własny kod rozwiązywania nazwy powinien stworzyć potok, parę gniazd lub * inny deskryptor pozwalający na co najmniej odbiór danych i przekazać go @@ -851,7 +903,9 @@ * * \return 0 jeśli się powiodło, -1 w przypadku błędu */ -int gg_session_set_custom_resolver(struct gg_session *gs, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +int gg_session_set_custom_resolver(struct gg_session *gs, + int (*resolver_start)(int*, void**, const char*), + void (*resolver_cleanup)(void**, int)) { GG_SESSION_CHECK(gs, -1); @@ -956,7 +1010,9 @@ * * \return 0 jeśli się powiodło, -1 w przypadku błędu */ -int gg_http_set_custom_resolver(struct gg_http *gh, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +int gg_http_set_custom_resolver(struct gg_http *gh, + int (*resolver_start)(int*, void**, const char*), + void (*resolver_cleanup)(void**, int)) { if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) { errno = EINVAL; @@ -1036,7 +1092,9 @@ * * \return 0 jeśli się powiodło, -1 w przypadku błędu */ -int gg_global_set_custom_resolver(int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +int gg_global_set_custom_resolver( + int (*resolver_start)(int*, void**, const char*), + void (*resolver_cleanup)(void**, int)) { if (resolver_start == NULL || resolver_cleanup == NULL) { errno = EINVAL; @@ -1067,4 +1125,3 @@ return recv(fd, buf, len, 0); #endif } -