Exemple #1
0
static void
cogl_gst_rgb_setup_pipeline (CoglGstVideoSink *sink,
                             CoglPipeline *pipeline)
{
  CoglGstVideoSinkPrivate *priv = sink->priv;

  if (cogl_has_feature (priv->ctx, COGL_FEATURE_ID_GLSL))
    {
      static SnippetCache snippet_cache;
      SnippetCacheEntry *entry = get_cache_entry (sink, &snippet_cache);

      if (entry == NULL)
        {
          char *source;

          source =
            g_strdup_printf ("vec4\n"
                             "cogl_gst_sample_video%i (vec2 UV)\n"
                             "{\n"
                             "  return texture2D (cogl_sampler%i, UV);\n"
                             "}\n",
                             priv->custom_start,
                             priv->custom_start);

          setup_pipeline_from_cache_entry (sink, pipeline, entry, 1);
          g_free (source);
        }
    }
  else
    setup_pipeline_from_cache_entry (sink, pipeline, NULL, 1);
}
Exemple #2
0
void finger_get_response(struct connection *c, struct read_buffer *rb)
{
	struct cache_entry *e;
	int l;
	set_timeout(c);
	if (get_cache_entry(c->url, &e)) {
		setcstate(c, S_OUT_OF_MEM);
		abort_connection(c);
		return;
	}
	c->cache = e;
	if (rb->close == 2) {
		setcstate(c, S_OK);
		finger_end_request(c);
		return;
	}
	l = rb->len;
	if (c->from + l < 0) {
		setcstate(c, S_LARGE_FILE);
		abort_connection(c);
		return;
	}
	c->received += l;
	if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
	c->from += l;
	kill_buffer_data(rb, l);
	read_from_socket(c, c->sock1, rb, finger_get_response);
	setcstate(c, S_TRANS);
}
Exemple #3
0
/******************************************************************************
 *		SysFreeString	[OLEAUT32.6]
 *
 * Free a BSTR.
 *
 * PARAMS
 *  str [I] BSTR to free.
 *
 * RETURNS
 *  Nothing.
 *
 * NOTES
 *  See BSTR.
 *  str may be NULL, in which case this function does nothing.
 */
void WINAPI SysFreeString(BSTR str)
{
    bstr_cache_entry_t *cache_entry;
    bstr_t *bstr;

    if(!str)
        return;

    bstr = bstr_from_str(str);
    cache_entry = get_cache_entry(bstr->size+sizeof(WCHAR));
    if(cache_entry) {
        EnterCriticalSection(&cs_bstr_cache);

        if(cache_entry->cnt < sizeof(cache_entry->buf)/sizeof(*cache_entry->buf)) {
            cache_entry->buf[(cache_entry->head+cache_entry->cnt)%((sizeof(cache_entry->buf)/sizeof(*cache_entry->buf)))] = bstr;
            cache_entry->cnt++;

            if(WARN_ON(heap)) {
                unsigned i, n = bstr_alloc_size(bstr->size) / sizeof(DWORD) - 1;
                bstr->size = ARENA_FREE_FILLER;
                for(i=0; i<n; i++)
                    bstr->u.dwptr[i] = ARENA_FREE_FILLER;
            }

            LeaveCriticalSection(&cs_bstr_cache);
            return;
        }

        LeaveCriticalSection(&cs_bstr_cache);
    }

    HeapFree(GetProcessHeap(), 0, bstr);
}
Exemple #4
0
void
about_protocol_handler(struct connection *conn)
{
	struct cache_entry *cached = get_cache_entry(conn->uri);

	/* Only do this the first time */
	if (cached && !cached->content_type) {
#ifndef CONFIG_SMALL
		{
			const struct about_page *page = about_pages;

			for (; page->name; page++) {
				int len;
				unsigned char *str;

				if (strcmp(conn->uri->data, page->name))
					continue;

				str = page->string;
				len = strlen(str);
				add_fragment(cached, 0, str, len);
				conn->from = len;
				break;
			}
		}
#endif

		/* Set content to known type */
		mem_free_set(&cached->content_type, stracpy("text/html"));
	}

	conn->cached = cached;
	abort_connection(conn, connection_state(S_OK));
}
 result_type apply(Msg& msg) {
   idx_token_type idx_token;
   std::integral_constant<bool, has_manipulator> mutator_token;
   // returns either a reference or a new object
   using detached = decltype(detail::detach_if_needed(msg, mutator_token));
   detached mref = detail::detach_if_needed(msg, mutator_token);
   auto bitmask = get_cache_entry(mref.type_token(), mref);
   return detail::unroll_expr<result_type>(m_cases, bitmask, idx_token, mref);
 }
Exemple #6
0
void
data_protocol_handler(struct connection *conn)
{
	struct uri *uri = conn->uri;
	struct cache_entry *cached = get_cache_entry(uri);
	unsigned char *data_start, *data;
	int base64 = 0;

	if (!cached) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	conn->cached = cached;

	data_start = parse_data_protocol_header(conn, &base64);
	if (!data_start) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	/* Allocate the data string because URI decoding will possibly modify
	 * it. */
	data = memacpy(data_start, uri->datalen - (data_start - uri->data));
	if (!data) {
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}

	if (base64) {
		unsigned char *decoded = base64_encode(data);

		if (!decoded) {
			abort_connection(conn, connection_state(S_OUT_OF_MEM));
			return;
		}

		mem_free_set(&data, decoded);
	} else {
		decode_uri(data);
	}

	{
		/* Use strlen() to get the correct decoded length */
		int datalen = strlen((const char *)data);

		add_fragment(cached, conn->from, data, datalen);
		conn->from += datalen;
	}

	mem_free(data);

	abort_connection(conn, connection_state(S_OK));
}
Exemple #7
0
static bstr_t *alloc_bstr(size_t size)
{
    bstr_cache_entry_t *cache_entry = get_cache_entry(size+sizeof(WCHAR));
    bstr_t *ret;

    if(cache_entry) {
        EnterCriticalSection(&cs_bstr_cache);

        if(!cache_entry->cnt) {
            cache_entry = get_cache_entry(size+sizeof(WCHAR)+BUCKET_SIZE);
            if(cache_entry && !cache_entry->cnt)
                cache_entry = NULL;
        }

        if(cache_entry) {
            ret = cache_entry->buf[cache_entry->head++];
            cache_entry->head %= sizeof(cache_entry->buf)/sizeof(*cache_entry->buf);
            cache_entry->cnt--;
        }

        LeaveCriticalSection(&cs_bstr_cache);

        if(cache_entry) {
            if(WARN_ON(heap)) {
                size_t tail;

                memset(ret, ARENA_INUSE_FILLER, FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)]));
                tail = bstr_alloc_size(size) - FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)]);
                if(tail)
                    memset(ret->u.ptr+size+sizeof(WCHAR), ARENA_TAIL_FILLER, tail);
            }
            ret->size = size;
            return ret;
        }
    }

    ret = HeapAlloc(GetProcessHeap(), 0, bstr_alloc_size(size));
    if(ret)
        ret->size = size;
    return ret;
}
Exemple #8
0
static struct connection_state
init_nntp_header(struct connection *conn, struct read_buffer *rb)
{
	struct nntp_connection_info *nntp = conn->info;

	if (!conn->cached) {
		conn->cached = get_cache_entry(conn->uri);
		if (!conn->cached) return connection_state(S_OUT_OF_MEM);

	} else if (conn->cached->head || conn->cached->content_type) {
		/* If the head is set wipe out the content to be sure */
		delete_entry_content(conn->cached);
		mem_free_set(&conn->cached->head, NULL);
	}

	/* XXX: Override any Content-Type line in the header */
	mem_free_set(&conn->cached->content_type, stracpy("text/html"));
	if (!conn->cached->content_type)
		return connection_state(S_OUT_OF_MEM);

	switch (nntp->target) {
	case NNTP_TARGET_ARTICLE_NUMBER:
	case NNTP_TARGET_MESSAGE_ID:
	case NNTP_TARGET_GROUP_MESSAGE_ID:
	{
		unsigned char *end;

		end = get_nntp_message_header_end(rb->data, rb->length);
		if (!end) {
			/* Redo the whole cache entry thing next time */
			return connection_state(S_TRANS);
		}

		/* FIXME: Add the NNTP response code line */
		conn->cached->head = stracpy("FIXME NNTP response code\r\n");
		if (!conn->cached->head) return connection_state(S_OUT_OF_MEM);

		add_to_strn(&conn->cached->head, rb->data);

		/* ... and remove it */
		conn->received += end - rb->data;
		kill_buffer_data(rb, end - rb->data);
		break;
	}
	case NNTP_TARGET_ARTICLE_RANGE:
	case NNTP_TARGET_GROUP:
	case NNTP_TARGET_GROUPS:
	case NNTP_TARGET_QUIT:
		break;
	}

	return connection_state(S_OK);
}
Exemple #9
0
static bstr_t *alloc_bstr(size_t size)
{
    bstr_cache_entry_t *cache_entry = get_cache_entry(size);
    bstr_t *ret;

    if(cache_entry) {
        EnterCriticalSection(&cs_bstr_cache);

        if(!cache_entry->cnt) {
            cache_entry = get_cache_entry(size+BUCKET_SIZE);
            if(cache_entry && !cache_entry->cnt)
                cache_entry = NULL;
        }

        if(cache_entry) {
            ret = cache_entry->buf[cache_entry->head++];
            cache_entry->head %= BUCKET_BUFFER_SIZE;
            cache_entry->cnt--;
        }

        LeaveCriticalSection(&cs_bstr_cache);

        if(cache_entry) {
            if(WARN_ON(heap)) {
                size_t fill_size = (FIELD_OFFSET(bstr_t, u.ptr[size])+2*sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1);
                memset(ret, ARENA_INUSE_FILLER, fill_size);
                memset((char *)ret+fill_size, ARENA_TAIL_FILLER, bstr_alloc_size(size)-fill_size);
            }
            ret->size = size;
            return ret;
        }
    }

    ret = HeapAlloc(GetProcessHeap(), 0, bstr_alloc_size(size));
    if(ret)
        ret->size = size;
    return ret;
}
Exemple #10
0
/******************************************************************************
 *		SysFreeString	[OLEAUT32.6]
 *
 * Free a BSTR.
 *
 * PARAMS
 *  str [I] BSTR to free.
 *
 * RETURNS
 *  Nothing.
 *
 * NOTES
 *  See BSTR.
 *  str may be NULL, in which case this function does nothing.
 */
void WINAPI SysFreeString(BSTR str)
{
    bstr_cache_entry_t *cache_entry;
    bstr_t *bstr;

    if(!str)
        return;

    bstr = bstr_from_str(str);
    cache_entry = get_cache_entry(bstr->size+sizeof(WCHAR));
    if(cache_entry) {
        unsigned i;

        EnterCriticalSection(&cs_bstr_cache);

        /* According to tests, freeing a string that's already in cache doesn't corrupt anything.
         * For that to work we need to search the cache. */
        for(i=0; i < cache_entry->cnt; i++) {
            if(cache_entry->buf[(cache_entry->head+i) % BUCKET_BUFFER_SIZE] == bstr) {
                WARN_(heap)("String already is in cache!\n");
                LeaveCriticalSection(&cs_bstr_cache);
                return;
            }
        }

        if(cache_entry->cnt < sizeof(cache_entry->buf)/sizeof(*cache_entry->buf)) {
            cache_entry->buf[(cache_entry->head+cache_entry->cnt) % BUCKET_BUFFER_SIZE] = bstr;
            cache_entry->cnt++;

            if(WARN_ON(heap)) {
                unsigned n = bstr_alloc_size(bstr->size) / sizeof(DWORD) - 1;
                bstr->size = ARENA_FREE_FILLER;
                for(i=0; i<n; i++)
                    bstr->u.dwptr[i] = ARENA_FREE_FILLER;
            }

            LeaveCriticalSection(&cs_bstr_cache);
            return;
        }

        LeaveCriticalSection(&cs_bstr_cache);
    }

    HeapFree(GetProcessHeap(), 0, bstr);
}
Exemple #11
0
static void
cogl_gst_yv12_glsl_setup_pipeline (CoglGstVideoSink *sink,
                                   CoglPipeline *pipeline)
{
  CoglGstVideoSinkPrivate *priv = sink->priv;
  static SnippetCache snippet_cache;
  SnippetCacheEntry *entry;

  entry = get_cache_entry (sink, &snippet_cache);

  if (entry == NULL)
    {
      char *source;

      source =
        g_strdup_printf ("vec4\n"
                         "cogl_gst_sample_video%i (vec2 UV)\n"
                         "{\n"
                         "  float y = 1.1640625 * "
                         "(texture2D (cogl_sampler%i, UV).a - 0.0625);\n"
                         "  float u = texture2D (cogl_sampler%i, UV).a - 0.5;\n"
                         "  float v = texture2D (cogl_sampler%i, UV).a - 0.5;\n"
                         "  vec4 color;\n"
                         "  color.r = y + 1.59765625 * v;\n"
                         "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
                         "  color.b = y + 2.015625 * u;\n"
                         "  color.a = 1.0;\n"
                         "  return color;\n"
                         "}\n",
                         priv->custom_start,
                         priv->custom_start,
                         priv->custom_start + 1,
                         priv->custom_start + 2);

      entry = add_cache_entry (sink, &snippet_cache, source);
      g_free (source);
    }

  setup_pipeline_from_cache_entry (sink, pipeline, entry, 3);
}
Exemple #12
0
struct cache_list_entry* filesys_cache_block_get (block_sector_t sector, bool dirty){

	lock_acquire(&lock_cache);

	struct cache_list_entry *cache_entry, *reuired_cache = NULL;
	struct list_elem *cache_list_elem;

	for (cache_list_elem = list_begin(&cache_list); cache_list_elem != list_end(&cache_list);
			cache_list_elem = list_next(cache_list_elem)){

		cache_entry = list_entry(cache_list_elem, struct cache_list_entry, cache_elem);
		if (cache_entry->sector_in_cache == sector){
			reuired_cache = cache_entry;
			break;
		}
	}

	//cache hit
	if (reuired_cache){
		reuired_cache->currently_using_this_cache++;
		reuired_cache->is_dirty |= dirty;
		reuired_cache->is_accessed = true;
		lock_release(&lock_cache);
		return reuired_cache;
	}

	//cache miss. so get data in cache now
	reuired_cache = get_cache_entry(sector, dirty);

	if (!reuired_cache){
		PANIC("Out of Memory while creating cache list entry");
	}

	lock_release(&lock_cache);

	return reuired_cache;
}
static void finger_get_response(struct connection *c, struct read_buffer *rb)
{
	int l;
	int a;
	set_timeout(c);
	if (!c->cache) {
		if (get_cache_entry(c->url, &c->cache)) {
			setcstate(c, S_OUT_OF_MEM);
			abort_connection(c);
			return;
		}
		c->cache->refcount--;
	}
	if (rb->close == 2) {
		finger_end_request(c, S__OK);
		return;
	}
	l = rb->len;
	if ((off_t)(0UL + c->from + l) < 0) {
		setcstate(c, S_LARGE_FILE);
		abort_connection(c);
		return;
	}
	c->received += l;
	a = add_fragment(c->cache, c->from, rb->data, l);
	if (a < 0) {
		setcstate(c, a);
		abort_connection(c);
		return;
	}
	if (a == 1) c->tries = 0;
	c->from += l;
	kill_buffer_data(rb, l);
	read_from_socket(c, c->sock1, rb, finger_get_response);
	setcstate(c, S_TRANS);
}
/// Adds or updates an entry in the cache.
void DnsCachedResolver::add_to_cache(const std::string& domain,
                                     int dnstype,
                                     std::vector<DnsRRecord*>& records)
{
  pthread_mutex_lock(&_cache_lock);

  LOG_DEBUG("Adding cache entry %s %s",
            domain.c_str(), DnsRRecord::rrtype_to_string(dnstype).c_str());

  DnsCacheEntryPtr ce = get_cache_entry(domain, dnstype);

  if (ce == NULL)
  {
    // Create a new cache entry.
    LOG_DEBUG("Create cache entry");
    ce = create_cache_entry(domain, dnstype);
  }
  else
  {
    // Clear the existing entry of records.
    clear_cache_entry(ce);
  }

  // Copy all the records across to the cache entry.
  for (size_t ii = 0; ii < records.size(); ++ii)
  {
    add_record_to_cache(ce, records[ii]);
  }

  records.clear();

  // Finally make sure the record is in the expiry list.
  add_to_expiry_list(ce);

  pthread_mutex_unlock(&_cache_lock);
}
Exemple #15
0
/* To reduce redundant error handling code [calls to abort_connection()]
 * most of the function is build around conditions that will assign the error
 * code to @state if anything goes wrong. The rest of the function will then just
 * do the necessary cleanups. If all works out we end up with @state being S_OK
 * resulting in a cache entry being created with the fragment data generated by
 * either reading the file content or listing a directory. */
void
file_protocol_handler(struct connection *connection)
{
	unsigned char *redirect_location = NULL;
	struct string page, name;
	struct connection_state state;
	int set_dir_content_type = 0;

	if (get_cmd_opt_bool((const unsigned char *)"anonymous")) {
		if (strcmp((const char *)connection->uri->string, "file:///dev/stdin")
		    || isatty(STDIN_FILENO)) {
			abort_connection(connection,
					 connection_state(S_FILE_ANONYMOUS));
			return;
		}
	}

#ifdef CONFIG_CGI
	if (!execute_cgi(connection)) return;
#endif /* CONFIG_CGI */

	/* Treat /dev/stdin in special way */
	if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) {
		int fd = open("/dev/stdin", O_RDONLY);

		if (fd == -1) {
			abort_connection(connection, connection_state(-errno));
			return;
		}
		set_nonblocking_fd(fd);
		if (!init_http_connection_info(connection, 1, 0, 1)) {
			abort_connection(connection, connection_state(S_OUT_OF_MEM));
			close(fd);
			return;
		}
		connection->socket->fd = fd;
		connection->data_socket->fd = -1;
		read_from_stdin(connection);
		return;
	}


	/* This function works on already simplified file-scheme URI pre-chewed
	 * by transform_file_url(). By now, the function contains no hostname
	 * part anymore, possibly relative path is converted to an absolute one
	 * and uri->data is just the final path to file/dir we should try to
	 * show. */

	if (!init_string(&name)
	    || !add_uri_to_string(&name, connection->uri, URI_PATH)) {
		done_string(&name);
		abort_connection(connection, connection_state(S_OUT_OF_MEM));
		return;
	}

	decode_uri_string(&name);

	/* In Win32, file_is_dir seems to always return 0 if the name
	 * ends with a directory separator.  */
	if ((name.length > 0 && dir_sep(name.source[name.length - 1]))
	    || file_is_dir(name.source)) {
		/* In order for global history and directory listing to
		 * function properly the directory url must end with a
		 * directory separator. */
		if (name.source[0] && !dir_sep(name.source[name.length - 1])) {
			redirect_location = (unsigned char *)STRING_DIR_SEP;
			state = connection_state(S_OK);
		} else {
			state = list_directory(connection, name.source, &page);
			set_dir_content_type = 1;
		}

	} else {
		state = read_encoded_file(&name, &page);
		/* FIXME: If state is now S_ENCODE_ERROR we should try loading
		 * the file undecoded. --jonas */
	}

	done_string(&name);

	if (is_in_state(state, S_OK)) {
		struct cache_entry *cached;

		/* Try to add fragment data to the connection cache if either
		 * file reading or directory listing worked out ok. */
		cached = connection->cached = get_cache_entry(connection->uri);
		if (!connection->cached) {
			if (!redirect_location) done_string(&page);
			state = connection_state(S_OUT_OF_MEM);

		} else if (redirect_location) {
			if (!redirect_cache(cached, redirect_location, 1, 0))
				state = connection_state(S_OUT_OF_MEM);

		} else {
			add_fragment(cached, 0, page.source, page.length);
			connection->from += page.length;

			if (!cached->head && set_dir_content_type) {
				unsigned char *head;

				/* If the system charset somehow
				 * changes after the directory listing
				 * has been generated, it should be
				 * parsed with the original charset.  */
				head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=",
						  get_cp_mime_name(get_cp_index((const unsigned char *)"System")),
						  "\r\n", (unsigned char *) NULL);

				/* Not so gracefully handle failed memory
				 * allocation. */
				if (!head)
					state = connection_state(S_OUT_OF_MEM);

				/* Setup directory listing for viewing. */
				mem_free_set(&cached->head, head);
			}

			done_string(&page);
		}
	}

	abort_connection(connection, state);
}
DnsResult DnsCachedResolver::dns_query(const std::string& domain,
                                       int dnstype)
{
  DnsChannel* channel = NULL;

  pthread_mutex_lock(&_cache_lock);

  // Expire any cache entries that have passed their TTL.
  expire_cache();

  DnsCacheEntryPtr ce = get_cache_entry(domain, dnstype);

  if (ce == NULL)
  {
    // Create an empty record for this cache entry.
    LOG_DEBUG("Create cache entry pending query");
    ce = create_cache_entry(domain, dnstype);

    // Get a DNS channel to issue any queries.
    channel = get_dns_channel();

    if (channel != NULL)
    {
      // DNS server is configured, so create a Transaction for the query and
      // execute it.  Mark the entry as pending and take the lock on it
      // before doing this to prevent any other threads sending the same
      // query.
      LOG_DEBUG("Create and execute DNS query transaction");
      ce->pending_query = true;
      pthread_mutex_lock(&ce->lock);
      DnsTsx* tsx = new DnsTsx(channel, domain, dnstype);
      tsx->execute();

      LOG_DEBUG("Wait for query responses");
      pthread_mutex_unlock(&_cache_lock);
      wait_for_replies(channel);
      pthread_mutex_lock(&_cache_lock);
      LOG_DEBUG("Received all query responses");
    }
  }

  // We should now have responses for everything (unless another thread was
  // already doing a query), so get the response.
  if (ce->pending_query)
  {
    // We must release the global lock and let the other thread finish
    // the query.
    // @TODO - may need to do something with reference counting of the
    // DnsCacheEntry to make this watertight.
    pthread_mutex_unlock(&_cache_lock);
    pthread_mutex_lock(&ce->lock);
    pthread_mutex_unlock(&ce->lock);
    pthread_mutex_lock(&_cache_lock);
  }

  LOG_DEBUG("Pulling %d records from cache for %s %s",
            ce->records.size(),
            ce->domain.c_str(),
            DnsRRecord::rrtype_to_string(ce->dnstype).c_str());

  DnsResult result(ce->domain,
                   ce->dnstype,
                   ce->records,
                   ce->expires - time(NULL));

  pthread_mutex_unlock(&_cache_lock);

  return result;
}
Exemple #17
0
void file_func(struct connection *c)
{
	struct cache_entry *e;
	unsigned char *file, *name, *head;
	int fl;
	DIR *d;
	int h, r;
	struct stat stt;
	if (anonymous && !anonymousGinga) {
		setcstate(c, S_BAD_URL);
		abort_connection(c);
		return;
	}
	if (!(name = get_filename(c->url))) {
		setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
	}
	
	if (anonymousGinga && !allowedPath(name)){
		setcstate(c, S_BAD_URL);
		abort_connection(c);
		return;
	}

	if (stat(name, &stt)) {
		mem_free(name);
		setcstate(c, -errno); abort_connection(c); return;
	}
	if (!S_ISDIR(stt.st_mode) && !S_ISREG(stt.st_mode)) {
		mem_free(name);
		setcstate(c, S_FILE_TYPE); abort_connection(c); return;
	}
	if ((h = open(name, O_RDONLY | O_NOCTTY)) == -1) {
		int er = errno;
		if ((d = opendir(name))) goto dir;
		mem_free(name);
		setcstate(c, -er); abort_connection(c); return;
	}
	set_bin(h);
	if (S_ISDIR(stt.st_mode)) {
		struct dirs *dir;
		int dirl;
		int i;
		struct dirent *de;
		d = opendir(name);
		close(h);
		if (!d) {
			mem_free(name);
			setcstate(c, -errno); abort_connection(c); return;
		}
		dir:
		dir = DUMMY, dirl = 0;
		if (name[0] && !dir_sep(name[strlen(name) - 1])) {
			if (get_cache_entry(c->url, &e)) {
				mem_free(name);
				closedir(d);
				setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
			}
			c->cache = e;
			if (e->redirect) mem_free(e->redirect);
			e->redirect = stracpy(c->url);
			e->redirect_get = 1;
			add_to_strn(&e->redirect, "/");
			mem_free(name);
			closedir(d);
			goto end;
		}
		last_uid = -1;
		last_gid = -1;
		file = init_str();
		fl = 0;
		add_to_str(&file, &fl, "<html><head><title>");
		add_conv_str(&file, &fl, name, strlen(name), -1);
		add_to_str(&file, &fl, "</title></head><body><h2>Directory ");
		add_conv_str(&file, &fl, name, strlen(name), -1);
		add_to_str(&file, &fl, "</h2><pre>");
		while ((de = readdir(d))) {
			struct stat stt, *stp;
			unsigned char **p;
			int l;
			unsigned char *n;
			if (!strcmp(de->d_name, ".")) continue;
			if ((unsigned)dirl > MAXINT / sizeof(struct dirs) - 1) overalloc();
			dir = mem_realloc(dir, (dirl + 1) * sizeof(struct dirs));
			dir[dirl].f = stracpy(de->d_name);
			*(p = &dir[dirl++].s) = init_str();
			l = 0;
			n = stracpy(name);
			add_to_strn(&n, de->d_name);
#ifdef FS_UNIX_SOFTLINKS
			if (lstat(n, &stt))
#else
			if (stat(n, &stt))
#endif
			     stp = NULL;
			else stp = &stt;
			mem_free(n);
			stat_mode(p, &l, stp);
			stat_links(p, &l, stp);
			stat_user(p, &l, stp, 0);
			stat_user(p, &l, stp, 1);
			stat_size(p, &l, stp);
			stat_date(p, &l, stp);
		}
		closedir(d);
		if (dirl) qsort(dir, dirl, sizeof(struct dirs), (int(*)(const void *, const void *))comp_de);
		for (i = 0; i < dirl; i++) {
			unsigned char *lnk = NULL;
#ifdef FS_UNIX_SOFTLINKS
			if (dir[i].s[0] == 'l') {
				unsigned char *buf = NULL;
				int size = 0;
				int r;
				unsigned char *n = stracpy(name);
				add_to_strn(&n, dir[i].f);
				do {
					if (buf) mem_free(buf);
					size += ALLOC_GR;
					if ((unsigned)size > MAXINT) overalloc();
					buf = mem_alloc(size);
					r = readlink(n, buf, size);
				} while (r == size);
				if (r == -1) goto yyy;
				buf[r] = 0;
				lnk = buf;
				goto xxx;
				yyy:
				mem_free(buf);
				xxx:
				mem_free(n);
			}
#endif
			/*add_to_str(&file, &fl, "   ");*/
			add_to_str(&file, &fl, dir[i].s);
			add_to_str(&file, &fl, "<a href=\"");
			add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 1);
			if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "/");
			else if (lnk) {
				struct stat st;
				unsigned char *n = stracpy(name);
				add_to_strn(&n, dir[i].f);
				if (!stat(n, &st)) if (S_ISDIR(st.st_mode)) add_to_str(&file, &fl, "/");
				mem_free(n);
			}
			add_to_str(&file, &fl, "\">");
			/*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "<font color=\"yellow\">");*/
			add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 0);
			/*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "</font>");*/
			add_to_str(&file, &fl, "</a>");
			if (lnk) {
				add_to_str(&file, &fl, " -> ");
				add_to_str(&file, &fl, lnk);
				mem_free(lnk);
			}
			add_to_str(&file, &fl, "\n");
		}
		mem_free(name);
		for (i = 0; i < dirl; i++) mem_free(dir[i].s), mem_free(dir[i].f);
		mem_free(dir);
		add_to_str(&file, &fl, "</pre></body></html>\n");
		head = stracpy("\r\nContent-Type: text/html\r\n");
	} else {
		mem_free(name);
		/* + !stt.st_size is there because of bug in Linux. Read returns
		   -EACCES when reading 0 bytes to invalid address */
		if (stt.st_size > MAXINT) {
			close(h);
			setcstate(c, S_LARGE_FILE); abort_connection(c);
			return;
		}
		file = mem_alloc(stt.st_size + !stt.st_size);
		if ((r = read(h, file, stt.st_size)) != stt.st_size) {
			mem_free(file); close(h);
			setcstate(c, r == -1 ? -errno : S_FILE_ERROR);
			abort_connection(c); return;
		}
		close(h);
		fl = stt.st_size;
		head = stracpy("");
	}
	if (get_cache_entry(c->url, &e)) {
		mem_free(file);
		setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
	}
	if (e->head) mem_free(e->head);
	e->head = head;
	c->cache = e;
	add_fragment(e, 0, file, fl);
	truncate_entry(e, fl, 1);
	mem_free(file);
	end:
	c->cache->incomplete = 0;
	setcstate(c, S_OK);
	abort_connection(c);
}
Exemple #18
0
void show_http_error_document( struct session *ses, void *data )
{
  struct terminal *term = ses->tab->term;
  struct cache_entry *cached;
  struct cache_entry *cache = find_in_cache( &((int*)data)[1] );
  unsigned char *str;
  cached = find_in_cache( &((int*)data)[1] );
  if ( cached || get_cache_entry( &((int*)data)[1] ) )
  {
    if ( 0 != 72 )
    {
      if ( term && current_charset != get_terminal_codepage( term ) )
      {
        bind_textdomain_codeset( "elinks", get_cp_mime_name( get_terminal_codepage( term ) ) );
        current_charset = get_terminal_codepage( term );
      }
      gettext( "HTTP error %03d" );
    }
    if ( init_string( ebp_32 ) == 0 )
    {
      if ( asprintfa( (char*)gettext( "HTTP error %03d" ) ) )
        mem_free( (void*)asprintfa( (char*)gettext( "HTTP error %03d" ) ) );
    }
    else
    {
      add_format_to_string( (struct string*)asprintfa( (char*)gettext( "HTTP error %03d" ) ), asprintfa( (char*)gettext( "HTTP error %03d" ) ) );
      if ( 0 != 32 )
      {
        if ( term && current_charset != get_terminal_codepage( term ) )
        {
          bind_textdomain_codeset( "elinks", get_cp_mime_name( get_terminal_codepage( term ) ) );
          current_charset = get_terminal_codepage( term );
        }
        gettext( "  An error occurred on the server while fetching the document you\n  requested. However, the server did not send back any explanation of what\n  happened, so it is unknown what went wrong. Please contact the web\n  server administrator about this, if you believe that this error should\n  not occur since it is not a nice behaviour from the web server at all\n  and indicates that there is some much deeper problem with the web server\n  software.\n" );
      }
      add_format_to_string( ebp_32, gettext( "  An error occurred on the server while fetching the document you\n  requested. However, the server did not send back any explanation of what\n  happened, so it is unknown what went wrong. Please contact the web\n  server administrator about this, if you believe that this error should\n  not occur since it is not a nice behaviour from the web server at all\n  and indicates that there is some much deeper problem with the web server\n  software.\n" ) );
      add_format_to_string( "  &lt;/p&gt;\n  &lt;p&gt;\n  URI: &lt;a href=\"%s\"&gt;%s&lt;/a&gt;\n", *(int*)(((int*)data)[1]) );
      add_format_to_string( ebp_32, " &lt;/p&gt;\n &lt;hr /&gt;\n &lt;/body&gt;\n&lt;/html&gt;\n" );
      if ( asprintfa( (char*)gettext( "HTTP error %03d" ) ) )
        mem_free( (void*)asprintfa( (char*)gettext( "HTTP error %03d" ) ) );
      str[0] = ebp_32;
      if ( ebp_32 )
      {
        int gettext_codepage = get_terminal_codepage( term );
        if ( cached )
          delete_entry_content( &cache[0] );
        if ( cache->content_type )
          mem_free( (void*)cache->content_type );
        cache->content_type = stracpy( "text/html" );
        if ( cache->head )
          mem_free( (void*)cache->head );
        cache->head = straconcat( "\r\nContent-Type: text/html; charset=" );
        add_fragment( &cache[0], (long long)0, &str[0] );
        mem_free( &str[0] );
        draw_formatted( ses, 1 );
      }
    }
  }
  done_uri( &((int*)data)[1] );
  mem_free( &((int*)data)[0] );
  return;
}
Exemple #19
0
static void
smb_got_header(struct socket *socket, struct read_buffer *rb)
{
	struct connection *conn = socket->conn;
	struct read_buffer *buf;
	int error = 0;

	conn->cached = get_cache_entry(conn->uri);
	if (!conn->cached) {
		/* Even though these are pipes rather than real
		 * sockets, call close_socket instead of close, to
		 * ensure that abort_connection won't try to close the
		 * file descriptors again.  (Could we skip the calls
		 * and assume abort_connection will do them?)  */
		close_socket(socket);
		close_socket(conn->data_socket);
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}
	socket->state = SOCKET_END_ONCLOSE;

	if (rb->length > 0) {
		unsigned char *ctype = memacpy(rb->data, rb->length);

		if (ctype && *ctype) {
			if (!strcmp(ctype, "text/x-error")) {
				error = 1;
				mem_free(ctype);
			} else {
				if (ctype[0] >= '0' && ctype[0] <= '9') {
#ifdef HAVE_ATOLL
					conn->est_length = (off_t)atoll(ctype);
#else
					conn->est_length = (off_t)atol(ctype);
#endif
					mem_free(ctype);

					/* avoid error */
					if (!conn->est_length) {
						abort_connection(conn, connection_state(S_OK));
						return;
					}
				}
				else mem_free_set(&conn->cached->content_type, ctype);
			}
		} else {
			mem_free_if(ctype);
		}
	}

	buf = alloc_read_buffer(conn->data_socket);
	if (!buf) {
		close_socket(socket);
		close_socket(conn->data_socket);
		abort_connection(conn, connection_state(S_OUT_OF_MEM));
		return;
	}
	if (error) {
		mem_free_set(&conn->cached->content_type, stracpy("text/html"));
		read_from_socket(conn->data_socket, buf,
				 connection_state(S_CONN), smb_got_error);
	} else {
		read_from_socket(conn->data_socket, buf,
				 connection_state(S_CONN), smb_got_data);
	}
}
Exemple #20
0
void http_got_header(struct connection *c, struct read_buffer *rb)
{
    int cf;
    int state = c->state != S_PROC ? S_GETH : S_PROC;
    unsigned char *head;
    unsigned char *cookie, *ch;
    int a, h, version;
    unsigned char *d;
    struct cache_entry *e;
    struct http_connection_info *info;
    unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
    set_timeout(c);
    info = c->info;
    if (rb->close == 2) {
        unsigned char *h;
        if (!c->tries && (h = get_host_name(host))) {
            if (info->bl_flags & BL_NO_CHARSET) {
                del_blacklist_entry(h, BL_NO_CHARSET);
            } else {
                add_blacklist_entry(h, BL_NO_CHARSET);
                c->tries = -1;
            }
            mem_free(h);
        }
        setcstate(c, S_CANT_READ);
        retry_connection(c);
        return;
    }
    rb->close = 0;
again:
    if ((a = get_header(rb)) == -1) {
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (!a) {
        read_from_socket(c, c->sock1, rb, http_got_header);
        setcstate(c, state);
        return;
    }
    if (a != -2) {
        head = mem_alloc(a + 1);
        memcpy(head, rb->data, a);
        head[a] = 0;
        kill_buffer_data(rb, a);
    } else {
        head = stracpy("HTTP/0.9 200 OK\r\nContent-Type: text/html\r\n\r\n");
    }
    if (get_http_code(head, &h, &version) || h == 101) {
        mem_free(head);
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) {
        mem_free(head);
        setcstate(c, S_RESTART);
        retry_connection(c);
        return;
    }
    ch = head;
    while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) {
        unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
        set_cookie(NULL, host, cookie);
        mem_free(cookie);
    }
    if (h == 100) {
        mem_free(head);
        state = S_PROC;
        goto again;
    }
    if (h < 200) {
        mem_free(head);
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if (h == 204) {
        mem_free(head);
        setcstate(c, S_HTTP_204);
        http_end_request(c, 0);
        return;
    }
    if (h == 304) {
        mem_free(head);
        setcstate(c, S_OK);
        http_end_request(c, 1);
        return;
    }
    if ((h == 500 || h == 502 || h == 503 || h == 504) && http_bugs.retry_internal_errors && is_connection_restartable(c)) {
        /* !!! FIXME: wait some time ... */
        mem_free(head);
        setcstate(c, S_RESTART);
        retry_connection(c);
        return;
    }
    if (!c->cache && get_cache_entry(c->url, &c->cache)) {
        mem_free(head);
        setcstate(c, S_OUT_OF_MEM);
        abort_connection(c);
        return;
    }
    e = c->cache;
    e->http_code = h;
    if (e->head) mem_free(e->head);
    e->head = head;
    if ((d = parse_http_header(head, "Expires", NULL))) {
        time_t t = parse_http_date(d);
        if (t && e->expire_time != 1) e->expire_time = t;
        mem_free(d);
    }
    if ((d = parse_http_header(head, "Pragma", NULL))) {
        if (!casecmp(d, "no-cache", 8)) e->expire_time = 1;
        mem_free(d);
    }
    if ((d = parse_http_header(head, "Cache-Control", NULL))) {
        char *f = d;
        while (1) {
            while (*f && (*f == ' ' || *f == ',')) f++;
            if (!*f) break;
            if (!casecmp(f, "no-cache", 8) || !casecmp(f, "must-revalidate", 15)) {
                e->expire_time = 1;
            }
            if (!casecmp(f, "max-age=", 8)) {
                if (e->expire_time != 1) e->expire_time = time(NULL) + atoi(f + 8);
            }
            while (*f && *f != ',') f++;
        }
        mem_free(d);
    }
#ifdef HAVE_SSL
    if (c->ssl) {
        int l = 0;
        if (e->ssl_info) mem_free(e->ssl_info);
        e->ssl_info = init_str();
        add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL));
        add_to_str(&e->ssl_info, &l, "-bit ");
        add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl));
        add_to_str(&e->ssl_info, &l, " ");
        add_to_str(&e->ssl_info, &l, (unsigned  char *)SSL_get_cipher_name(c->ssl));
    }
#endif
    if (e->redirect) mem_free(e->redirect), e->redirect = NULL;
    if (h == 301 || h == 302 || h == 303 || h == 307) {
        if ((h == 302 || h == 307) && !e->expire_time) e->expire_time = 1;
        if ((d = parse_http_header(e->head, "Location", NULL))) {
            unsigned char *user, *ins;
            unsigned char *newuser, *newpassword;
            if (!parse_url(d, NULL, &user, NULL, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && !user && ins && (newuser = get_user_name(host))) {
                if (*newuser) {
                    int ins_off = ins - d;
                    newpassword = get_pass(host);
                    if (!newpassword) newpassword = stracpy("");
                    add_to_strn(&newuser, ":");
                    add_to_strn(&newuser, newpassword);
                    add_to_strn(&newuser, "@");
                    extend_str(&d, strlen(newuser));
                    ins = d + ins_off;
                    memmove(ins + strlen(newuser), ins, strlen(ins) + 1);
                    memcpy(ins, newuser, strlen(newuser));
                    mem_free(newpassword);
                }
                mem_free(newuser);
            }
            if (e->redirect) mem_free(e->redirect);
            e->redirect = d;
            e->redirect_get = h == 303;
        }
    }
    if (!e->expire_time && strchr(c->url, POST_CHAR)) e->expire_time = 1;
    info->close = 0;
    info->length = -1;
    info->version = version;
    if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) {
        if (!strcasecmp(d, "close")) info->close = 1;
        mem_free(d);
    } else if (version < 11) info->close = 1;
    cf = c->from;
    c->from = 0;
    if ((d = parse_http_header(e->head, "Content-Range", NULL))) {
        if (strlen(d) > 6) {
            d[5] = 0;
            if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') {
#if defined(HAVE_STRTOLL)
                long long f = strtoll(d + 6, NULL, 10);
#elif defined(HAVE_STRTOQ)
                longlong f = strtoq(d + 6, NULL, 10);
#else
                long f = strtol(d + 6, NULL, 10);
                if (f == MAXLONG) f = -1;
#endif
                if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f;
            }
        }
        mem_free(d);
    }
    if (cf && !c->from && !c->unrestartable) c->unrestartable = 1;
    if (c->from > cf || c->from < 0) {
        setcstate(c, S_HTTP_ERROR);
        abort_connection(c);
        return;
    }
    if ((d = parse_http_header(e->head, "Content-Length", NULL))) {
        unsigned char *ep;
#if defined(HAVE_STRTOLL)
        long long l = strtoll(d, (char **)(void *)&ep, 10);
#elif defined(HAVE_STRTOQ)
        longlong l = strtoq(d, (char **)(void *)&ep, 10);
#else
        long l = strtol(d, (char **)(void *)&ep, 10);
        if (l == MAXLONG) l = -1;
#endif
        if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) {
            if (!info->close || version >= 11) info->length = l;
            if (c->from + l >= 0) c->est_length = c->from + l;
        }
        mem_free(d);
    }
    if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) {
        if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1;
        mem_free(d);
    } else {
        if (!c->unrestartable && !c->from) c->unrestartable = 1;
    }
    if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1;
    if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) {
        if (!strcasecmp(d, "chunked")) {
            info->length = -2;
            info->chunk_remaining = -1;
        }
        mem_free(d);
    }
    if (!info->close && info->length == -1) info->close = 1;
    if ((d = parse_http_header(e->head, "Last-Modified", NULL))) {
        if (e->last_modified && strcasecmp(e->last_modified, d)) {
            delete_entry_content(e);
            if (c->from) {
                c->from = 0;
                mem_free(d);
                setcstate(c, S_MODIFIED);
                retry_connection(c);
                return;
            }
        }
        if (!e->last_modified) e->last_modified = d;
        else mem_free(d);
    }
    if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL)))
        e->last_modified = d;
    if (info->length == -1 || (version < 11 && info->close)) rb->close = 1;
    read_http_data(c, rb);
}
void DnsCachedResolver::dns_query(const std::vector<std::string>& domains,
                                  int dnstype,
                                  std::vector<DnsResult>& results)
{
  DnsChannel* channel = NULL;

  pthread_mutex_lock(&_cache_lock);

  // Expire any cache entries that have passed their TTL.
  expire_cache();

  // First see if any of the domains need to be queried.
  for (std::vector<std::string>::const_iterator i = domains.begin();
       i != domains.end();
       ++i)
  {
    LOG_VERBOSE("Check cache for %s type %d", (*i).c_str(), dnstype);
    if (get_cache_entry(*i, dnstype) == NULL)
    {
      LOG_DEBUG("No entry found in cache");

      // Create an empty record for this cache entry.
      LOG_DEBUG("Create cache entry pending query");
      DnsCacheEntryPtr ce = create_cache_entry(*i, dnstype);

      if (channel == NULL)
      {
        // Get a DNS channel to issue any queries.
        channel = get_dns_channel();
      }

      if (channel != NULL)
      {
        // DNS server is configured, so create a Transaction for the query
        // and execute it.  Mark the entry as pending and take the lock on
        // it before doing this to prevent any other threads sending the
        // same query.
        LOG_DEBUG("Create and execute DNS query transaction");
        ce->pending_query = true;
        pthread_mutex_lock(&ce->lock);
        DnsTsx* tsx = new DnsTsx(channel, *i, dnstype);
        tsx->execute();
      }
    }
  }

  if (channel != NULL)
  {
    // Issued some queries, so wait for the replies before processing the
    // request further.
    LOG_DEBUG("Wait for query responses");
    pthread_mutex_unlock(&_cache_lock);
    wait_for_replies(channel);
    pthread_mutex_lock(&_cache_lock);
    LOG_DEBUG("Received all query responses");
  }

  // We should now have responses for everything (unless another thread was
  // already doing a query), so loop collecting the responses.
  for (std::vector<std::string>::const_iterator i = domains.begin();
       i != domains.end();
       ++i)
  {
    DnsCacheEntryPtr ce = get_cache_entry(*i, dnstype);

    if (ce != NULL)
    {
      // Found the cache entry, so check whether it is still pending a query.
      if (ce->pending_query)
      {
        // We must release the global lock and let the other thread finish
        // the query.
        // @TODO - may need to do something with reference counting of the
        // DnsCacheEntry to make this watertight.
        pthread_mutex_unlock(&_cache_lock);
        pthread_mutex_lock(&ce->lock);
        pthread_mutex_unlock(&ce->lock);
        pthread_mutex_lock(&_cache_lock);
      }

      // Can now pull the information from the cache entry in to the results.
      LOG_DEBUG("Pulling %d records from cache for %s %s",
                ce->records.size(),
                ce->domain.c_str(),
                DnsRRecord::rrtype_to_string(ce->dnstype).c_str());

      results.push_back(DnsResult(ce->domain,
                                  ce->dnstype,
                                  ce->records,
                                  ce->expires - time(NULL)));
    }
    else
    {
      // This shouldn't happen, but if it does, return an empty result set.
      LOG_DEBUG("Return empty result set");
      results.push_back(DnsResult(*i, dnstype, 0));
    }
  }

  pthread_mutex_unlock(&_cache_lock);
}
/// Handles a DNS response from the server.
void DnsCachedResolver::dns_response(const std::string& domain,
                                     int dnstype,
                                     int status,
                                     unsigned char* abuf,
                                     int alen)
{
  pthread_mutex_lock(&_cache_lock);

  LOG_DEBUG("Received DNS response for %s type %s",
            domain.c_str(), DnsRRecord::rrtype_to_string(dnstype).c_str());

  // Find the relevant node in the cache.
  DnsCacheEntryPtr ce = get_cache_entry(domain, dnstype);

  // Note that if the request failed or the response failed to parse the expiry
  // time in the cache record is left unchanged.  If it is an existing record
  // it will expire according to the current expiry value, if it is a new
  // record it will expire after DEFAULT_NEGATIVE_CACHE_TTL time.
  if (status == ARES_SUCCESS)
  {
    // Create a message parser and parse the message.
    DnsParser parser(abuf, alen);
    if (parser.parse())
    {
      // Parsing was successful, so clear out any old records, then process
      // the answers and additional data.
      clear_cache_entry(ce);

      while (!parser.answers().empty())
      {
        DnsRRecord* rr = parser.answers().front();
        parser.answers().pop_front();
        if ((rr->rrtype() == ns_t_a) ||
            (rr->rrtype() == ns_t_aaaa))
        {
          // A/AAAA record, so check that RRNAME matches the question.
          if (strcasecmp(rr->rrname().c_str(), domain.c_str()) == 0)
          {
            // RRNAME matches, so add this record to the cache entry.
            add_record_to_cache(ce, rr);
          }
          else
          {
            delete rr;
          }
        }
        else
        {
          // SRV or NAPTR record, so add it to the cache entry.
          add_record_to_cache(ce, rr);
        }
      }

      // Process any additional records returned in the response, creating
      // or updating cache entries.  First we sort the records by cache key.
      std::map<DnsCacheKey, std::list<DnsRRecord*> > sorted;
      while (!parser.additional().empty())
      {
        DnsRRecord* rr = parser.additional().front();
        parser.additional().pop_front();
        if (caching_enabled(rr->rrtype()))
        {
          // Caching is enabled for this record type, so add it to sorted
          // structure.
          sorted[std::make_pair(rr->rrtype(), rr->rrname())].push_back(rr);
        }
        else
        {
          // Caching not enabled for this record, so delete it.
          delete rr;
        }
      }

      // Now update each cache record in turn.
      for (std::map<DnsCacheKey, std::list<DnsRRecord*> >::const_iterator i = sorted.begin();
           i != sorted.end();
           ++i)
      {
        DnsCacheEntryPtr ace = get_cache_entry(i->first.second, i->first.first);
        if (ace == NULL)
        {
          // No existing cache entry, so create one.
          ace = create_cache_entry(i->first.second, i->first.first);
        }
        else
        {
          // Existing cache entry so clear out any existing records.
          clear_cache_entry(ace);
        }
        for (std::list<DnsRRecord*>::const_iterator j = i->second.begin();
             j != i->second.end();
             ++j)
        {
          add_record_to_cache(ace, *j);
        }

        // Finally make sure the record is in the expiry list.
        add_to_expiry_list(ace);
      }
    }
  }

  // If there were no records set cache a negative entry to prevent 
  // immediate retries.
  if ((ce->records.empty()) &&
      (ce->expires == 0))
  {
    // We didn't get an SOA record, so use a default negative cache timeout.
    ce->expires = DEFAULT_NEGATIVE_CACHE_TTL + time(NULL);
  }

  // Add the record to the expiry list.
  add_to_expiry_list(ce);

  // Flag that the cache entry is no longer pending a query, and release
  // the lock on the cache entry.
  ce->pending_query = false;
  pthread_mutex_unlock(&ce->lock);

  pthread_mutex_unlock(&_cache_lock);
}