libpurple/protocols/gg/lib/resolver.c

changeset 35630
8e5d0d726b09
parent 35620
fb20cfee648a
parent 35627
fd11790cc4d6
child 35686
cae91a875b23
--- 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" &mdash; wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
- *  - \c "void **priv_data" &mdash; wskaźnik na zmienną, gdzie można umieścić wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy
+ *  - \c "void **priv_data" &mdash; wskaźnik na zmienną, gdzie można umieścić
+ *    wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy
  *  - \c "const char *name" &mdash; nazwa serwera do rozwiązania
  *
  * Parametry funkcji zwalniającej zasoby wyglądają następująco:
- *  - \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
- *  - \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.
+ *  - \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
+ *  - \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.
  *
  * 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
 }
-

mercurial