Example #1
0
/**
 * @return TRUE if the request was sent succesfully.  FALSE
 *         if the request could not be sent.  This isn't
 *         necessarily an error.  If the child has expired,
 *         for example, we won't be able to send the message.
 */
static gboolean
send_dns_request_to_child(PurpleDnsQueryData *query_data,
		PurpleDnsQueryResolverProcess *resolver)
{
	pid_t pid;
	dns_params_t dns_params;
	ssize_t rc;

	/* This waitpid might return the child's PID if it has recently
	 * exited, or it might return an error if it exited "long
	 * enough" ago that it has already been reaped; in either
	 * instance, we can't use it. */
	pid = waitpid(resolver->dns_pid, NULL, WNOHANG);
	if (pid > 0) {
		purple_debug_warning("dns", "DNS child %d no longer exists\n",
				resolver->dns_pid);
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	} else if (pid < 0) {
		purple_debug_warning("dns", "Wait for DNS child %d failed: %s\n",
				resolver->dns_pid, g_strerror(errno));
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}

	/* Copy the hostname and port into a single data structure */
	strncpy(dns_params.hostname, query_data->hostname, sizeof(dns_params.hostname) - 1);
	dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0';
	dns_params.port = query_data->port;

	/* Send the data structure to the child */
	rc = write(resolver->fd_in, &dns_params, sizeof(dns_params));
	if (rc < 0) {
		purple_debug_error("dns", "Unable to write to DNS child %d: %s\n",
				resolver->dns_pid, g_strerror(errno));
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}
	if ((gsize)rc < sizeof(dns_params)) {
		purple_debug_error("dns", "Tried to write %" G_GSSIZE_FORMAT
				" bytes to child but only wrote %" G_GSSIZE_FORMAT "\n",
				sizeof(dns_params), rc);
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}

	purple_debug_info("dns",
			"Successfully sent DNS request to child %d\n",
			resolver->dns_pid);

	query_data->resolver = resolver;

	return TRUE;
}
Example #2
0
void
purple_dnsquery_uninit(void)
{
#if defined(__unix__) || defined(__APPLE__)
	while (free_dns_children != NULL)
	{
		purple_dnsquery_resolver_destroy(free_dns_children->data);
		free_dns_children = g_slist_remove(free_dns_children, free_dns_children->data);
	}
#endif
}
Example #3
0
void
purple_dnsquery_uninit(void)
{
#if defined(PURPLE_DNSQUERY_USE_FORK)
	while (free_dns_children != NULL)
	{
		purple_dnsquery_resolver_destroy(free_dns_children->data);
		free_dns_children = g_slist_remove(free_dns_children, free_dns_children->data);
	}
#endif /* end PURPLE_DNSQUERY_USE_FORK */
}
Example #4
0
static PurpleDnsQueryResolverProcess *
purple_dnsquery_resolver_new(gboolean show_debug)
{
	PurpleDnsQueryResolverProcess *resolver;
	int child_out[2], child_in[2];

	/* Create pipes for communicating with the child process */
	if (pipe(child_out) || pipe(child_in)) {
		purple_debug_error("dns",
				   "Could not create pipes: %s\n", strerror(errno));
		return NULL;
	}

	resolver = g_new(PurpleDnsQueryResolverProcess, 1);
	resolver->inpa = 0;

	cope_with_gdb_brokenness();

	/* "Go fork and multiply." --Tommy Caldwell (Emily's dad, not the climber) */
	resolver->dns_pid = fork();

	/* If we are the child process... */
	if (resolver->dns_pid == 0) {
		/* We should not access the parent's side of the pipes, so close them */
		close(child_out[0]);
		close(child_in[1]);

		purple_dnsquery_resolver_run(child_out[1], child_in[0], show_debug);
		/* The thread calls _exit() rather than returning, so we never get here */
	}

	/* We should not access the child's side of the pipes, so close them */
	close(child_out[1]);
	close(child_in[0]);
	if (resolver->dns_pid == -1) {
		purple_debug_error("dns",
				   "Could not create child process for DNS: %s\n",
				   strerror(errno));
		purple_dnsquery_resolver_destroy(resolver);
		return NULL;
	}

	resolver->fd_out = child_out[0];
	resolver->fd_in = child_in[1];
	number_of_dns_children++;
	purple_debug_info("dns",
			   "Created new DNS child %d, there are now %d children.\n",
			   resolver->dns_pid, number_of_dns_children);

	return resolver;
}
Example #5
0
void
purple_dnsquery_destroy(PurpleDnsQueryData *query_data)
{
	PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();

	if (ops && ops->destroy)
		ops->destroy(query_data);

#if defined(PURPLE_DNSQUERY_USE_FORK)
	queued_requests = g_slist_remove(queued_requests, query_data);

	if (query_data->resolver != NULL)
		/*
		 * This is only non-NULL when we're cancelling an in-progress
		 * query.  Ideally we would tell our resolver child to stop
		 * resolving shit and then we would add it back to the
		 * free_dns_children linked list.  However, it's hard to tell
		 * children stuff, they just don't listen.  So we'll just
		 * kill the process and allow a new child to be started if we
		 * have more stuff to resolve.
		 */
		purple_dnsquery_resolver_destroy(query_data->resolver);
#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
	if (query_data->resolver != NULL)
	{
		/*
		 * It's not really possible to kill a thread.  So instead we
		 * just set the callback to NULL and let the DNS lookup
		 * finish.
		 */
		query_data->callback = NULL;
		return;
	}

	while (query_data->hosts != NULL)
	{
		/* Discard the length... */
		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
		/* Free the address... */
		g_free(query_data->hosts->data);
		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
	}
	g_free(query_data->error_message);
#endif /* end _WIN32 */

	if (query_data->timeout > 0)
		purple_timeout_remove(query_data->timeout);

	g_free(query_data->hostname);
	g_free(query_data);
}
Example #6
0
void
purple_dnsquery_destroy(PurpleDnsQueryData *query_data)
{
	PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();

	if (ops && ops->destroy)
		ops->destroy(query_data);

#if defined(__unix__) || defined(__APPLE__)
	queued_requests = g_slist_remove(queued_requests, query_data);

	if (query_data->resolver != NULL)
		/*
		 * Ideally we would tell our resolver child to stop resolving
		 * shit and then we would add it back to the free_dns_children
		 * linked list.  However, it's hard to tell children stuff,
		 * they just don't listen.
		 */
		purple_dnsquery_resolver_destroy(query_data->resolver);
#elif defined _WIN32 /* end __unix__ || __APPLE__ */
	if (query_data->resolver != NULL)
	{
		/*
		 * It's not really possible to kill a thread.  So instead we
		 * just set the callback to NULL and let the DNS lookup
		 * finish.
		 */
		query_data->callback = NULL;
		return;
	}

	while (query_data->hosts != NULL)
	{
		/* Discard the length... */
		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
		/* Free the address... */
		g_free(query_data->hosts->data);
		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
	}
	g_free(query_data->error_message);
#endif

	if (query_data->timeout > 0)
		purple_timeout_remove(query_data->timeout);

	g_free(query_data->hostname);
	g_free(query_data);
}
Example #7
0
/**
 * @return TRUE if the request was sent succesfully.  FALSE
 * 		if the request could not be sent.  This isn't
 * 		necessarily an error.  If the child has expired,
 * 		for example, we won't be able to send the message.
 */
static gboolean
send_dns_request_to_child(PurpleDnsQueryData *query_data,
		PurpleDnsQueryResolverProcess *resolver)
{
	pid_t pid;
	dns_params_t dns_params;
	int rc;
	char ch;

	/* This waitpid might return the child's PID if it has recently
	 * exited, or it might return an error if it exited "long
	 * enough" ago that it has already been reaped; in either
	 * instance, we can't use it. */
	pid = waitpid(resolver->dns_pid, NULL, WNOHANG);
	if (pid > 0) {
		purple_debug_warning("dns", "DNS child %d no longer exists\n",
				resolver->dns_pid);
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	} else if (pid < 0) {
		purple_debug_warning("dns", "Wait for DNS child %d failed: %s\n",
				resolver->dns_pid, strerror(errno));
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}

	/* Copy the hostname and port into a single data structure */
	strncpy(dns_params.hostname, query_data->hostname, sizeof(dns_params.hostname) - 1);
	dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0';
	dns_params.port = query_data->port;

	/* Send the data structure to the child */
	rc = write(resolver->fd_in, &dns_params, sizeof(dns_params));
	if (rc < 0) {
		purple_debug_error("dns", "Unable to write to DNS child %d: %d\n",
				resolver->dns_pid, strerror(errno));
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}

	g_return_val_if_fail(rc == sizeof(dns_params), -1);

	/* Did you hear me? (This avoids some race conditions) */
	rc = read(resolver->fd_out, &ch, sizeof(ch));
	if (rc != 1 || ch != 'Y')
	{
		purple_debug_warning("dns",
				"DNS child %d not responding. Killing it!\n",
				resolver->dns_pid);
		purple_dnsquery_resolver_destroy(resolver);
		return FALSE;
	}

	purple_debug_info("dns",
			"Successfully sent DNS request to child %d\n",
			resolver->dns_pid);

	query_data->resolver = resolver;

	return TRUE;
}