예제 #1
0
파일: hostip.c 프로젝트: 4ker/CMake
/*
 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
 *
 * Curl_resolv() checks initially and multi_runsingle() checks each time
 * it discovers the handle in the state WAITRESOLVE whether the hostname
 * has already been resolved and the address has already been stored in
 * the DNS cache. This short circuits waiting for a lot of pending
 * lookups for the same hostname requested by different handles.
 *
 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
 */
struct Curl_dns_entry *
Curl_fetch_addr(struct connectdata *conn,
                const char *hostname,
                int port, int *stale)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  struct SessionHandle *data = conn->data;

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if(!entry_id)
    return dns;

  entry_len = strlen(entry_id);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

  /* free the allocated entry_id again */
  free(entry_id);

  /* See whether the returned entry is stale. Done before we release lock */
  *stale = remove_entry_if_stale(data, dns);
  if(*stale)
    dns = NULL; /* the memory deallocation is being handled by the hash */

  return dns;
}
예제 #2
0
파일: conncache.c 프로젝트: 4honor/QConf
struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
                                                 char *hostname)
{
  struct connectbundle *bundle = NULL;

  if(connc)
    bundle = Curl_hash_pick(connc->hash, hostname, strlen(hostname)+1);

  return bundle;
}
예제 #3
0
파일: http2.c 프로젝트: wchingwei/curl
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                              int32_t stream_id,
                              const uint8_t *data, size_t len, void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct HTTP *stream;
  struct SessionHandle *data_s;
  size_t nread;
  (void)session;
  (void)flags;
  (void)data;
  DEBUGF(infof(conn->data, "on_data_chunk_recv() "
               "len = %u, stream %u\n", len, stream_id));

  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */

  /* get the stream from the hash based on Stream ID */
  data_s = Curl_hash_pick(&conn->proto.httpc.streamsh, &stream_id,
                          sizeof(stream_id));
  if(!data_s) {
    /* Receiving a Stream ID not in the hash should not happen, this is an
       internal error more than anything else! */
    failf(conn->data, "Received frame on Stream ID: %x not in stream hash!",
          stream_id);
    return NGHTTP2_ERR_CALLBACK_FAILURE;
  }
  stream = data_s->req.protop;

  nread = MIN(stream->len, len);
  memcpy(&stream->mem[stream->memlen], data, nread);

  stream->len -= nread;
  stream->memlen += nread;

  data_s->state.drain++;
  Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
                             immediately? */

  DEBUGF(infof(data_s, "%zu data received for stream %u "
               "(%zu left in buffer %p, total %zu)\n",
               nread, stream_id,
               stream->len, stream->mem,
               stream->memlen));

  if(nread < len) {
    stream->pausedata = data + nread;
    stream->pauselen = len - nread;
    DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
                 ", stream %u\n",
                 len - nread, stream_id));
    conn->proto.httpc.pause_stream_id = stream_id;
    return NGHTTP2_ERR_PAUSE;
  }
  return 0;
}
예제 #4
0
파일: http2.c 프로젝트: wchingwei/curl
static ssize_t data_source_read_callback(nghttp2_session *session,
                                         int32_t stream_id,
                                         uint8_t *buf, size_t length,
                                         uint32_t *data_flags,
                                         nghttp2_data_source *source,
                                         void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct http_conn *c = &conn->proto.httpc;
  struct SessionHandle *data_s;
  struct HTTP *stream = NULL;
  size_t nread;
  (void)session;
  (void)stream_id;
  (void)source;

  if(stream_id) {
    /* get the stream from the hash based on Stream ID, stream ID zero is for
       connection-oriented stuff */
    data_s = Curl_hash_pick(&c->streamsh, &stream_id, sizeof(stream_id));
    if(!data_s) {
      /* Receiving a Stream ID not in the hash should not happen, this is an
         internal error more than anything else! */
      failf(conn->data, "Asked for data to stream %u not in hash!", stream_id);
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }
    stream = data_s->req.protop;
  }
  else {
    failf(conn->data, "nghttp2 confusion");
    return NGHTTP2_ERR_INVALID_ARGUMENT;
  }

  nread = MIN(stream->upload_len, length);
  if(nread > 0) {
    memcpy(buf, stream->upload_mem, nread);
    stream->upload_mem += nread;
    stream->upload_len -= nread;
    stream->upload_left -= nread;
  }

  if(stream->upload_left == 0)
    *data_flags = 1;
  else if(nread == 0)
    return NGHTTP2_ERR_DEFERRED;

  DEBUGF(infof(data_s, "data_source_read_callback: "
               "returns %zu bytes stream %u\n",
               nread, stream_id));

  return nread;
}
예제 #5
0
/* Look up the bundle with all the connections to the same host this
   connectdata struct is setup to use.

   **NOTE**: When it returns, it holds the connection cache lock! */
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
                                                 struct conncache *connc)
{
  struct connectbundle *bundle = NULL;
  CONN_LOCK(conn->data);
  if(connc) {
    char key[128];
    hashkey(conn, key, sizeof(key));
    bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
  }

  return bundle;
}
예제 #6
0
파일: conncache.c 프로젝트: AnnaSerg/curl
/* Look up the bundle with all the connections to the same host this
   connectdata struct is setup to use. */
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
                                                 struct conncache *connc)
{
  struct connectbundle *bundle = NULL;
  if(connc) {
    char *key = hashkey(conn);
    if(key) {
      bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
      free(key);
    }
  }

  return bundle;
}
예제 #7
0
파일: hostip.c 프로젝트: 54chen/curl
/* lookup address, returns entry if found and not stale */
static struct Curl_dns_entry *
fetch_addr(struct connectdata *conn,
                const char *hostname,
                int port)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  struct SessionHandle *data = conn->data;

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if(!entry_id)
    return dns;

  entry_len = strlen(entry_id);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

  if(dns && (data->set.dns_cache_timeout != -1))  {
    /* See whether the returned entry is stale. Done before we release lock */
    struct hostcache_prune_data user;

    time(&user.now);
    user.cache_timeout = data->set.dns_cache_timeout;

    if(hostcache_timestamp_remove(&user, dns)) {
      infof(data, "Hostname in DNS cache was stale, zapped\n");
      dns = NULL; /* the memory deallocation is being handled by the hash */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
    }
  }

  /* free the allocated entry_id again */
  free(entry_id);

  return dns;
}
예제 #8
0
파일: http2.c 프로젝트: wchingwei/curl
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
                           uint32_t error_code, void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct SessionHandle *data_s;
  struct HTTP *stream;
  (void)session;
  (void)stream_id;
  DEBUGF(infof(conn->data, "on_stream_close(), error_code = %d, stream %u\n",
               error_code, stream_id));

  if(stream_id) {
    /* get the stream from the hash based on Stream ID, stream ID zero is for
       connection-oriented stuff */
    data_s = Curl_hash_pick(&conn->proto.httpc.streamsh, &stream_id,
                            sizeof(stream_id));
    if(!data_s) {
      /* We could get stream ID not in the hash.  For example, if we
         decided to reject stream (e.g., PUSH_PROMISE).  We call infof
         as a debugging purpose for now. */
      infof(conn->data,
            "Received frame on Stream ID: %x not in stream hash!\n",
            stream_id);
      return 0;
    }
    stream = data_s->req.protop;

    stream->error_code = error_code;
    stream->closed = TRUE;

    /* remove the entry from the hash as the stream is now gone */
    Curl_hash_delete(&conn->proto.httpc.streamsh,
                     &stream_id, sizeof(stream_id));
    DEBUGF(infof(conn->data, "Removed stream %u hash!\n", stream_id));
  }
  return 0;
}
예제 #9
0
/* Resolve a name and return a pointer in the 'entry' argument if one
   is available.

   Return codes:

   -1 = error, no pointer
   0 = OK, pointer provided
   1 = waiting for response, no pointer
*/
int Curl_resolv(struct connectdata *conn,
                char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  int wait;
  struct SessionHandle *data = conn->data;
  CURLcode result;

  /* default to failure */
  int rc = -1;
  *entry = NULL;

#ifdef HAVE_SIGSETJMP
  /* this allows us to time-out from the name resolver, as the timeout
     will generate a signal and we will siglongjmp() from that here */
  if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
    /* this is coming from a siglongjmp() */
    failf(data, "name lookup timed out");
    return -1;
  }
#endif

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port, &entry_len);
  /* If we can't create the entry id, fail */
  if (!entry_id)
    return -1;

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
  
  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  /* free the allocated entry_id again */
  free(entry_id);

  if (!dns) {
    /* The entry was not in the cache. Resolve it to IP address */
      
    /* If my_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
       value indicating that we need to wait for the response to the resolve
       call */
    Curl_addrinfo *addr = my_getaddrinfo(conn, hostname, port, &wait);
    
    if (!addr) {
      if(wait) {
        /* the response to our resolve call will come asynchronously at 
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_is_resolved(conn, &dns);
        if(result) /* error detected */
          return -1;
        if(dns)
          rc = 0; /* pointer provided */
        else
          rc = 1; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = cache_resolv_response(data, addr, hostname, port);
      
      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = 0;
    }
  }
  else {
    dns->inuse++; /* we use it! */
    rc = 0;
  }

  *entry = dns;

  return rc;
}
예제 #10
0
int Curl_resolv(struct connectdata *conn,
                const char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  struct SessionHandle *data = conn->data;
  CURLcode result;
  int rc = CURLRESOLV_ERROR; /* default to failure */

  *entry = NULL;

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if(!entry_id)
    return rc;

  entry_len = strlen(entry_id);

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

  /* free the allocated entry_id again */
  free(entry_id);

  /* See whether the returned entry is stale. Done before we release lock */
  if( remove_entry_if_stale(data, dns) )
    dns = NULL; /* the memory deallocation is being handled by the hash */

  if(dns) {
    dns->inuse++; /* we use it! */
    rc = CURLRESOLV_RESOLVED;
  }

  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  if(!dns) {
    /* The entry was not in the cache. Resolve it to IP address */

    Curl_addrinfo *addr;
    int respwait;

    /* Check what IP specifics the app has requested and if we can provide it.
     * If not, bail out. */
    if(!Curl_ipvalid(conn))
      return CURLRESOLV_ERROR;

    /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
       non-zero value indicating that we need to wait for the response to the
       resolve call */
    addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
                            (data->set.str[STRING_DEVICE]
                             && !strcmp(data->set.str[STRING_DEVICE],
                                        "LocalHost"))?"localhost":
#endif
                            hostname, port, &respwait);

    if(!addr) {
      if(respwait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_is_resolved(conn, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = CURLRESOLV_RESOLVED;
    }
  }

  *entry = dns;

  return rc;
}
예제 #11
0
파일: hostip.c 프로젝트: 54chen/curl
CURLcode Curl_loadhostpairs(struct SessionHandle *data)
{
  struct curl_slist *hostp;
  char hostname[256];
  char address[256];
  int port;

  for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
    if(!hostp->data)
      continue;
    if(hostp->data[0] == '-') {
      char *entry_id;
      size_t entry_len;

      if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
        infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
              hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* delete entry, ignore if it didn't exist */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      /* free the allocated entry_id again */
      free(entry_id);
    }
    else {
      struct Curl_dns_entry *dns;
      Curl_addrinfo *addr;
      char *entry_id;
      size_t entry_len;

      if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
                     address)) {
        infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
              hostp->data);
        continue;
      }

      addr = Curl_str2addr(address, port);
      if(!addr) {
        infof(data, "Address in '%s' found illegal!\n", hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if its already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

      /* free the allocated entry_id again */
      free(entry_id);

      if(!dns) {
        /* if not in the cache already, put this host in the cache */
        dns = Curl_cache_addr(data, addr, hostname, port);
        if(dns) {
          dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
          /* release the returned reference; the cache itself will keep the
           * entry alive: */
          dns->inuse--;
        }
      }
      else
        /* this is a duplicate, free it again */
        Curl_freeaddrinfo(addr);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }
      infof(data, "Added %s:%d:%s to DNS cache\n",
            hostname, port, address);
    }
  }
  data->change.resolve = NULL; /* dealt with now */

  return CURLE_OK;
}
예제 #12
0
파일: http2.c 프로젝트: wchingwei/curl
/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
                     const uint8_t *name, size_t namelen,
                     const uint8_t *value, size_t valuelen,
                     uint8_t flags,
                     void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct HTTP *stream;
  struct SessionHandle *data_s;
  int32_t stream_id = frame->hd.stream_id;

  (void)session;
  (void)frame;
  (void)flags;

  /* Ignore PUSH_PROMISE for now */
  if(frame->hd.type != NGHTTP2_HEADERS) {
    return 0;
  }

  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */

  /* get the stream from the hash based on Stream ID */
  data_s = Curl_hash_pick(&conn->proto.httpc.streamsh, &stream_id,
                          sizeof(stream_id));
  if(!data_s) {
    /* Receiving a Stream ID not in the hash should not happen, this is an
       internal error more than anything else! */
    failf(conn->data, "Received frame on Stream ID: %x not in stream hash!",
          stream_id);
    return NGHTTP2_ERR_CALLBACK_FAILURE;
  }
  stream = data_s->req.protop;

  if(stream->bodystarted)
    /* Ignore trailer or HEADERS not mapped to HTTP semantics.  The
       consequence is handled in on_frame_recv(). */
    return 0;

  if(namelen == sizeof(":status") - 1 &&
     memcmp(":status", name, namelen) == 0) {
    /* nghttp2 guarantees :status is received first and only once, and
       value is 3 digits status code, and decode_status_code always
       succeeds. */
    stream->status_code = decode_status_code(value, valuelen);
    DEBUGASSERT(stream->status_code != -1);

    Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9);
    Curl_add_buffer(stream->header_recvbuf, value, valuelen);
    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
    data_s->state.drain++;
    Curl_expire(data_s, 1);

    DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n",
                 stream->status_code));
    return 0;
  }

  /* nghttp2 guarantees that namelen > 0, and :status was already
     received, and this is not pseudo-header field . */
  /* convert to a HTTP1-style header */
  Curl_add_buffer(stream->header_recvbuf, name, namelen);
  Curl_add_buffer(stream->header_recvbuf, ":", 1);
  Curl_add_buffer(stream->header_recvbuf, value, valuelen);
  Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
  data_s->state.drain++;
  Curl_expire(data_s, 1);

  DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
               value));

  return 0; /* 0 is successful */
}
예제 #13
0
파일: http2.c 프로젝트: wchingwei/curl
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
                         void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct http_conn *httpc = &conn->proto.httpc;
  struct SessionHandle *data_s = NULL;
  struct HTTP *stream = NULL;
  int rv;
  size_t left, ncopy;
  int32_t stream_id = frame->hd.stream_id;

  (void)session;
  (void)frame;
  DEBUGF(infof(conn->data, "on_frame_recv() header %x stream %x\n",
               frame->hd.type, stream_id));

  if(stream_id) {
    /* get the stream from the hash based on Stream ID, stream ID zero is for
       connection-oriented stuff */
    data_s = Curl_hash_pick(&httpc->streamsh, &stream_id,
                            sizeof(stream_id));
    if(!data_s) {
      /* Receiving a Stream ID not in the hash should not happen, this is an
         internal error more than anything else! */
      failf(conn->data, "Received frame on Stream ID: %x not in stream hash!",
            stream_id);
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }
    stream = data_s->req.protop;
  }

  switch(frame->hd.type) {
  case NGHTTP2_DATA:
    /* If body started on this stream, then receiving DATA is illegal. */
    if(!stream->bodystarted) {
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     stream_id, NGHTTP2_PROTOCOL_ERROR);

      if(nghttp2_is_fatal(rv)) {
        return NGHTTP2_ERR_CALLBACK_FAILURE;
      }
    }
    break;
  case NGHTTP2_HEADERS:
    if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
      break;

    if(stream->bodystarted) {
      /* Only valid HEADERS after body started is trailer HEADERS.  We
         ignores trailer HEADERS for now.  nghttp2 guarantees that it
         has END_STREAM flag set. */
      break;
    }

    /* nghttp2 guarantees that :status is received, and we store it to
       stream->status_code */
    DEBUGASSERT(stream->status_code != -1);

    /* Only final status code signals the end of header */
    if(stream->status_code / 100 != 1) {
      stream->bodystarted = TRUE;
      stream->status_code = -1;
    }

    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);

    left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
    ncopy = MIN(stream->len, left);

    memcpy(&stream->mem[stream->memlen],
           stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
           ncopy);
    stream->nread_header_recvbuf += ncopy;

    DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
                 ncopy, stream_id, stream->mem));

    stream->len -= ncopy;
    stream->memlen += ncopy;

    data_s->state.drain++;
    Curl_expire(data_s, 1);
    break;
  case NGHTTP2_PUSH_PROMISE:
    DEBUGF(infof(data_s, "Got PUSH_PROMISE, RST_STREAM it!\n"));
    rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                   frame->push_promise.promised_stream_id,
                                   NGHTTP2_CANCEL);
    if(nghttp2_is_fatal(rv)) {
      return rv;
    }
    break;
  case NGHTTP2_SETTINGS:
  {
    uint32_t max_conn = httpc->settings.max_concurrent_streams;
    DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id));
    httpc->settings.max_concurrent_streams =
      nghttp2_session_get_remote_settings(
        session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
    httpc->settings.enable_push =
      nghttp2_session_get_remote_settings(
        session, NGHTTP2_SETTINGS_ENABLE_PUSH);
    DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
                 httpc->settings.max_concurrent_streams));
    DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
                 httpc->settings.enable_push?"TRUE":"false"));
    if(max_conn != httpc->settings.max_concurrent_streams) {
      /* only signal change if the value actually changed */
      infof(conn->data,
            "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
      Curl_multi_connchanged(conn->data->multi);
    }
  }
  break;
  default:
    DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
                 frame->hd.type, stream_id));
    break;
  }
  return 0;
}
예제 #14
0
파일: hostip.c 프로젝트: 4ker/CMake
CURLcode Curl_loadhostpairs(struct SessionHandle *data)
{
  struct curl_slist *hostp;
  char hostname[256];
  char address[256];
  int port;

  for(hostp = data->change.resolve; hostp; hostp = hostp->next ) {
    if(!hostp->data)
      continue;
    if(hostp->data[0] == '-') {
      /* TODO: mark an entry for removal */
    }
    else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
                        address)) {
      struct Curl_dns_entry *dns;
      Curl_addrinfo *addr;
      char *entry_id;
      size_t entry_len;

      addr = Curl_str2addr(address, port);
      if(!addr) {
        infof(data, "Resolve %s found illegal!\n", hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if its already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

      /* free the allocated entry_id again */
      free(entry_id);

      if(!dns)
        /* if not in the cache already, put this host in the cache */
        dns = Curl_cache_addr(data, addr, hostname, port);
      else
        /* this is a duplicate, free it again */
        Curl_freeaddrinfo(addr);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }
      infof(data, "Added %s:%d:%s to DNS cache\n",
            hostname, port, address);
    }
  }
  data->change.resolve = NULL; /* dealt with now */

  return CURLE_OK;
}
예제 #15
0
int Curl_resolv(struct connectdata *conn,
                const char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  int wait;
  struct SessionHandle *data = conn->data;
  CURLcode result;
  int rc;
  *entry = NULL;

#ifdef HAVE_SIGSETJMP
  /* this allows us to time-out from the name resolver, as the timeout
     will generate a signal and we will siglongjmp() from that here */
  if(!data->set.no_signal) {
    if (sigsetjmp(curl_jmpenv, 1)) {
      /* this is coming from a siglongjmp() */
      failf(data, "name lookup timed out");
      return CURLRESOLV_ERROR;
    }
  }
#endif

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if (!entry_id)
    return CURLRESOLV_ERROR;

  entry_len = strlen(entry_id);

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  /* free the allocated entry_id again */
  free(entry_id);

  /* See whether the returned entry is stale. Deliberately done after the
     locked block */
  if ( remove_entry_if_stale(data,dns) )
    dns = NULL; /* the memory deallocation is being handled by the hash */

  rc = CURLRESOLV_ERROR; /* default to failure */

  if (!dns) {
    /* The entry was not in the cache. Resolve it to IP address */

    Curl_addrinfo *addr;

    /* Check what IP specifics the app has requested and if we can provide it.
     * If not, bail out. */
    if(!Curl_ipvalid(data))
      return CURLRESOLV_ERROR;

    /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
       value indicating that we need to wait for the response to the resolve
       call */
    addr = Curl_getaddrinfo(conn, hostname, port, &wait);

    if (!addr) {
      if(wait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_is_resolved(conn, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = CURLRESOLV_RESOLVED;
    }
  }
  else {
    if(data->share)
      Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
    dns->inuse++; /* we use it! */
    if(data->share)
      Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    rc = CURLRESOLV_RESOLVED;
  }

  *entry = dns;

  return rc;
}