Пример #1
0
/*
 * gethostbyname_thread() resolves a name and then exits.
 */
static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  struct thread_data *td = tsd->td;

  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);

  if(!tsd->res) {
    tsd->sock_error = SOCKERRNO;
    if(tsd->sock_error == 0)
      tsd->sock_error = RESOLVER_ENOMEM;
  }

  Curl_mutex_acquire(tsd->mtx);
  if(tsd->done) {
    /* too late, gotta clean up the mess */
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);
  }

  return 0;
}
Пример #2
0
/*
 * destroy_async_data() cleans up async resolver data and thread handle.
 */
static void destroy_async_data (struct Curl_async *async)
{
  if(async->os_specific) {
    struct thread_data *td = (struct thread_data*) async->os_specific;
    int done;

    /*
     * if the thread is still blocking in the resolve syscall, detach it and
     * let the thread do the cleanup...
     */
    Curl_mutex_acquire(td->tsd.mtx);
    done = td->tsd.done;
    td->tsd.done = 1;
    Curl_mutex_release(td->tsd.mtx);

    if(!done) {
      Curl_thread_destroy(td->thread_hnd);
    }
    else {
      if(td->thread_hnd != curl_thread_t_null)
        Curl_thread_join(&td->thread_hnd);

      destroy_thread_sync_data(&td->tsd);

      free(async->os_specific);
    }
  }
  async->os_specific = NULL;

  free(async->hostname);
  async->hostname = NULL;
}
Пример #3
0
/*
 * getaddrinfo_thread() resolves a name and then exits.
 *
 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
 * and wait on it.
 */
static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
  struct thread_data *td = tsd->td;
  char service[12];
  int rc;

  snprintf(service, sizeof(service), "%d", tsd->port);

  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);

  if(rc != 0) {
    tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
    if(tsd->sock_error == 0)
      tsd->sock_error = RESOLVER_ENOMEM;
  }
  else {
    Curl_addrinfo_set_port(tsd->res, tsd->port);
  }

  Curl_mutex_acquire(tsd->mtx);
  if(tsd->done) {
    /* too late, gotta clean up the mess */
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);
  }

  return 0;
}
Пример #4
0
/*
 * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
 * exits.
 *
 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
 * and wait on it.
 */
static unsigned __stdcall getaddrinfo_thread (void *arg)
{
  struct connectdata *conn = (struct connectdata*) arg;
  struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
  struct addrinfo    *res;
  char   service [NI_MAXSERV];
  int    rc;
  struct addrinfo hints = td->hints;

  /* Duplicate the passed mutex handle.
   * This allows us to use it even after the container gets destroyed
   * due to a resolver timeout.
   */
  struct thread_sync_data tsd = { 0,0,0,NULL };
  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
    /* thread synchronization data initialization failed */
    return -1;
  }

#ifndef _WIN32_WCE
  *stderr = *td->stderr_file;
#endif

  itoa(conn->async.port, service, 10);

  WSASetLastError(conn->async.status = NO_DATA); /* pending status */

  /* Signaling that we have initialized all copies of data and handles we
     need */
  SetEvent(td->event_thread_started);

  rc = getaddrinfo(tsd.hostname, service, &hints, &res);

  /* is parent thread waiting for us and are we able to access conn members? */
  if (acquire_thread_sync(&tsd)) {
    /* Mark that we have obtained the information, and that we are calling
       back with it. */
    SetEvent(td->event_resolved);

    if (rc == 0) {
#ifdef DEBUG_THREADING_GETADDRINFO
      dump_addrinfo (conn, res);
#endif
      rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
    }
    else {
      rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
      TRACE(("Winsock-error %d, no address\n", conn->async.status));
    }
    release_thread_sync(&tsd);
  }

  /* clean up */
  destroy_thread_sync_data(&tsd);

  return (rc);
  /* An implicit _endthreadex() here */
}
Пример #5
0
/* Initialize resolver thread synchronization data */
static
BOOL init_thread_sync_data(struct thread_data * td,
						   const char * hostname,
						   struct thread_sync_data * tsd)
{
	HANDLE curr_proc = GetCurrentProcess();

	MEMSET(tsd, 0, sizeof(*tsd));
	if (!DuplicateHandle(curr_proc, td->mutex_waiting,
						 curr_proc, &tsd->mutex_waiting, 0, FALSE,
						 DUPLICATE_SAME_ACCESS))
	{
		/* failed to duplicate the mutex, no point in continuing */
		destroy_thread_sync_data(tsd);
		return FALSE;
	}
	if (!DuplicateHandle(curr_proc, td->mutex_terminate,
						 curr_proc, &tsd->mutex_terminate, 0, FALSE,
						 DUPLICATE_SAME_ACCESS))
	{
		/* failed to duplicate the mutex, no point in continuing */
		destroy_thread_sync_data(tsd);
		return FALSE;
	}
	if (!DuplicateHandle(curr_proc, td->event_terminate,
						 curr_proc, &tsd->event_terminate, 0, FALSE,
						 DUPLICATE_SAME_ACCESS))
	{
		/* failed to duplicate the event, no point in continuing */
		destroy_thread_sync_data(tsd);
		return FALSE;
	}
	/* Copying hostname string because original can be destroyed by parent
	 * thread during gethostbyname execution.
	 */
	tsd->hostname = strdup(hostname);
	if (!tsd->hostname)
	{
		/* Memory allocation failed */
		destroy_thread_sync_data(tsd);
		return FALSE;
	}
	return TRUE;
}
Пример #6
0
/*
 * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
 * exits.
 *
 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
 * and wait on it.
 */
static unsigned __stdcall getaddrinfo_thread (void *arg)
{
	struct connectdata *conn = (struct connectdata*) arg;
	struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
	Curl_addrinfo      *res;
	char   service [NI_MAXSERV];
	int    rc;
	struct addrinfo hints = td->hints;

	/* Duplicate the passed mutex handle.
	 * This allows us to use it even after the container gets destroyed
	 * due to a resolver timeout.
	 */
	struct thread_sync_data tsd = { 0, 0, 0, NULL };

	if (!init_thread_sync_data(td, conn->async.hostname, &tsd))
	{
		/* thread synchronization data initialization failed */
		return -1;
	}

	itoa(conn->async.port, service, 10);

	conn->async.status = NO_DATA;  /* pending status */
	SET_SOCKERRNO(conn->async.status);

	/* Signaling that we have initialized all copies of data and handles we
	   need */
	SetEvent(td->event_thread_started);

	rc = Curl_getaddrinfo_ex(tsd.hostname, service, &hints, &res);

	/* is parent thread waiting for us and are we able to access conn members? */
	if (acquire_thread_sync(&tsd))
	{
		/* Mark that we have obtained the information, and that we are calling
		   back with it. */
		SetEvent(td->event_resolved);

		if (rc == 0)
		{
			rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
		}
		else
		{
			rc = Curl_addrinfo6_callback(conn, SOCKERRNO, NULL);
		}
		release_thread_sync(&tsd);
	}

	/* clean up */
	destroy_thread_sync_data(&tsd);

	return (rc);
	/* An implicit _endthreadex() here */
}
Пример #7
0
/*
 * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
 * and then exits.
 *
 * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
 * it.
 */
static unsigned __stdcall gethostbyname_thread (void *arg)
{
  struct connectdata *conn = (struct connectdata*) arg;
  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
  struct hostent *he;
  int    rc = 0;

  /* Duplicate the passed mutex and event handles.
   * This allows us to use it even after the container gets destroyed
   * due to a resolver timeout.
   */
  struct thread_sync_data tsd = { 0,0,0,NULL };
  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
    /* thread synchronization data initialization failed */
    return -1;
  }

  /* Sharing the same _iob[] element with our parent thread should
   * hopefully make printouts synchronised. I'm not sure it works
   * with a static runtime lib (MSVC's libc.lib).
   */
#ifndef _WIN32_WCE
  *stderr = *td->stderr_file;
#endif

  WSASetLastError (conn->async.status = NO_DATA); /* pending status */

  /* Signaling that we have initialized all copies of data and handles we
     need */
  SetEvent(td->event_thread_started);

  he = gethostbyname (tsd.hostname);

  /* is parent thread waiting for us and are we able to access conn members? */
  if (acquire_thread_sync(&tsd)) {
    /* Mark that we have obtained the information, and that we are calling
     * back with it. */
    SetEvent(td->event_resolved);
    if (he) {
      rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
    }
    else {
      rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
    }
    TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
           he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
    release_thread_sync(&tsd);
  }

  /* clean up */
  destroy_thread_sync_data(&tsd);

  return (rc);
  /* An implicit _endthreadex() here */
}
Пример #8
0
/*
 * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
 * and then exits.
 *
 * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
 * it.
 */
static unsigned __stdcall gethostbyname_thread (void *arg)
{
  struct connectdata *conn = (struct connectdata*) arg;
  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
  struct hostent *he;
  int    rc = 0;

  /* Duplicate the passed mutex and event handles.
   * This allows us to use it even after the container gets destroyed
   * due to a resolver timeout.
   */
  struct thread_sync_data tsd = { 0,0,0,NULL };

  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
    /* thread synchronization data initialization failed */
    return (unsigned)-1;
  }

  conn->async.status = NO_DATA;  /* pending status */
  SET_SOCKERRNO(conn->async.status);

  /* Signaling that we have initialized all copies of data and handles we
     need */
  SetEvent(td->event_thread_started);

  he = gethostbyname (tsd.hostname);

  /* is parent thread waiting for us and are we able to access conn members? */
  if (acquire_thread_sync(&tsd)) {
    /* Mark that we have obtained the information, and that we are calling
     * back with it. */
    SetEvent(td->event_resolved);
    if (he) {
      rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
    }
    else {
      rc = Curl_addrinfo4_callback(conn, SOCKERRNO, NULL);
    }
    TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
           he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
    release_thread_sync(&tsd);
  }

  /* clean up */
  destroy_thread_sync_data(&tsd);

  return (rc);
  /* An implicit _endthreadex() here */
}
Пример #9
0
/* Initialize resolver thread synchronization data */
static
int init_thread_sync_data(struct thread_data * td,
                           const char *hostname,
                           int port,
                           const struct addrinfo *hints)
{
  struct thread_sync_data *tsd = &td->tsd;

  memset(tsd, 0, sizeof(*tsd));

  tsd->td = td;
  tsd->port = port;
  /* Treat the request as done until the thread actually starts so any early
   * cleanup gets done properly.
   */
  tsd->done = 1;
#ifdef HAVE_GETADDRINFO
  DEBUGASSERT(hints);
  tsd->hints = *hints;
#else
  (void) hints;
#endif

  tsd->mtx = malloc(sizeof(curl_mutex_t));
  if(tsd->mtx == NULL)
    goto err_exit;

  Curl_mutex_init(tsd->mtx);

  tsd->sock_error = CURL_ASYNC_SUCCESS;

  /* Copying hostname string because original can be destroyed by parent
   * thread during gethostbyname execution.
   */
  tsd->hostname = strdup(hostname);
  if(!tsd->hostname)
    goto err_exit;

  return 1;

 err_exit:
  /* Memory allocation failed */
  destroy_thread_sync_data(tsd);
  return 0;
}
Пример #10
0
/*
 * destroy_async_data() cleans up async resolver data and thread handle.
 */
static void destroy_async_data (struct Curl_async *async)
{
  if(async->hostname)
    free(async->hostname);

  if(async->os_specific) {
    struct thread_data *td = (struct thread_data*) async->os_specific;

    if(td->thread_hnd != curl_thread_t_null)
      Curl_thread_join(&td->thread_hnd);

    destroy_thread_sync_data(&td->tsd);

    free(async->os_specific);
  }
  async->hostname = NULL;
  async->os_specific = NULL;
}
Пример #11
0
/*
 * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
 * Complementary of ares_destroy.
 */
void Curl_destroy_thread_data (struct Curl_async *async)
{
  if(async->hostname)
    free(async->hostname);

  if(async->os_specific) {
    struct thread_data *td = (struct thread_data*) async->os_specific;

    if (td->dummy_sock != CURL_SOCKET_BAD)
      sclose(td->dummy_sock);

    if (td->thread_hnd != curl_thread_t_null)
      Curl_thread_join(&td->thread_hnd);
 
    destroy_thread_sync_data(&td->tsd);
    
    free(async->os_specific);
  }
  async->hostname = NULL;
  async->os_specific = NULL;
}
Пример #12
0
/* Initialize resolver thread synchronization data */
static
int init_thread_sync_data(struct thread_sync_data * tsd,
                           const char * hostname,
                           int port,
                           const struct addrinfo *hints)
{
  memset(tsd, 0, sizeof(*tsd));

  tsd->port = port;
#ifdef CURLRES_IPV6
  DEBUGASSERT(hints);
  tsd->hints = *hints;
#else
  (void) hints;
#endif

  tsd->mtx = malloc(sizeof(curl_mutex_t));
  if(tsd->mtx == NULL)
    goto err_exit;

  Curl_mutex_init(tsd->mtx);

  tsd->sock_error = CURL_ASYNC_SUCCESS;

  /* Copying hostname string because original can be destroyed by parent
   * thread during gethostbyname execution.
   */
  tsd->hostname = strdup(hostname);
  if(!tsd->hostname)
    goto err_exit;

  return 1;

 err_exit:
  /* Memory allocation failed */
  destroy_thread_sync_data(tsd);
  return 0;
}