text: /**
   *
   * /brief getdns core functions for synchronous use
   *
   * Originally taken from the getdns API description pseudo implementation.
   *
   */
  
  /*
   * Copyright (c) 2013, NLnet Labs, Verisign, Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   * * Redistributions of source code must retain the above copyright
   *   notice, this list of conditions and the following disclaimer.
   * * Redistributions in binary form must reproduce the above copyright
   *   notice, this list of conditions and the following disclaimer in the
   *   documentation and/or other materials provided with the distribution.
   * * Neither the names of the copyright holders nor the
   *   names of its contributors may be used to endorse or promote products
   *   derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <string.h>
  #include <unbound.h>
  #include "getdns/getdns.h"
  #include "config.h"
  #include "context.h"
  #include "general.h"
  #include "types-internal.h"
  #include "util-internal.h"
  #include "dnssec.h"
  
  #include "stub.h"
  #include "gldns/wire2str.h"
  
  typedef struct getdns_sync_loop {
  	getdns_mini_event      loop;
  	getdns_eventloop_event ub_event;
  	getdns_context        *context;
  	int                    to_run;
  	getdns_dict           *response;
  } getdns_sync_loop;
  
  static getdns_return_t
  getdns_sync_loop_init(getdns_context *context, getdns_sync_loop *loop)
  {
  	getdns_return_t r;
  	getdns_eventloop *ext = &loop->loop.loop;
  
  	loop->response = NULL;
  	loop->to_run   = 1;
  	loop->context  = context;
  
  	if ((r = getdns_mini_event_init(context, &loop->loop)))
  		return r;
  
  	loop->ub_event.userarg    = loop->context;
  	loop->ub_event.read_cb    = priv_getdns_context_ub_read_cb;
  	loop->ub_event.write_cb   = NULL;
  	loop->ub_event.timeout_cb = NULL;
  	loop->ub_event.ev         = NULL;
  
  	return ext->vmt->schedule(ext, ub_fd(context->unbound_ctx),
  	    TIMEOUT_FOREVER, &loop->ub_event);
  }
  
  static void
  getdns_sync_loop_cleanup(getdns_sync_loop *loop)
  {
  	getdns_eventloop *ext = &loop->loop.loop;
  
  	ext->vmt->clear(ext, &loop->ub_event);
  	ext->vmt->cleanup(ext);
  }
  
  static void
  getdns_sync_loop_run(getdns_sync_loop *loop)
  {
  	getdns_eventloop *ext = &loop->loop.loop;
  
  	while (loop->to_run)
  		ext->vmt->run_once(ext, 1);
  	
  	getdns_sync_loop_cleanup(loop);
  }
  
  static void
  getdns_sync_cb(getdns_context *context, getdns_callback_type_t callback_type,
      getdns_dict *response, void *userarg, getdns_transaction_t transaction_id)
  {
  	getdns_sync_loop *loop = (getdns_sync_loop *)userarg;
  
  	assert(loop);
  
  	loop->response = response;
  	loop->to_run = 0;
  }
  
  getdns_return_t
  getdns_general_sync(getdns_context *context, const char *name,
      uint16_t request_type, getdns_dict *extensions, getdns_dict **response)
  {
  	getdns_sync_loop loop;
  	getdns_return_t r;
  
  	if (!context || !name || !response)
  		return GETDNS_RETURN_INVALID_PARAMETER;
  
  	if ((r = getdns_sync_loop_init(context, &loop)))
  		return r;
  
  	if ((r = priv_getdns_general_loop(context, &loop.loop.loop, name,
  	    request_type, extensions, &loop, NULL, getdns_sync_cb, NULL))) {
  
  		getdns_sync_loop_cleanup(&loop);
  		return r;
  	}
  	getdns_sync_loop_run(&loop);
  	
  	return (*response = loop.response) ?
  	    GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
  }
  
  getdns_return_t
  getdns_address_sync(getdns_context *context, const char *name,
      getdns_dict *extensions, getdns_dict **response)
  {
  	getdns_sync_loop loop;
  	getdns_return_t r;
  
  	if (!context || !name || !response)
  		return GETDNS_RETURN_INVALID_PARAMETER;
  
  	if ((r = getdns_sync_loop_init(context, &loop)))
  		return r;
  
  	if ((r = priv_getdns_address_loop(context, &loop.loop.loop, name,
  	    extensions, &loop, NULL, getdns_sync_cb))) {
  
  		getdns_sync_loop_cleanup(&loop);
  		return r;
  	}
  	getdns_sync_loop_run(&loop);
  	
  	return (*response = loop.response) ?
  	    GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
  }
  
  getdns_return_t
  getdns_hostname_sync(getdns_context *context, getdns_dict *address,
      getdns_dict *extensions, getdns_dict **response)
  {
  	getdns_sync_loop loop;
  	getdns_return_t r;
  
  	if (!context || !address || !response)
  		return GETDNS_RETURN_INVALID_PARAMETER;
  
  	if ((r = getdns_sync_loop_init(context, &loop)))
  		return r;
  
  	if ((r = priv_getdns_hostname_loop(context, &loop.loop.loop, address,
  	    extensions, &loop, NULL, getdns_sync_cb))) {
  
  		getdns_sync_loop_cleanup(&loop);
  		return r;
  	}
  	getdns_sync_loop_run(&loop);
  	
  	return (*response = loop.response) ?
  	    GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
  }
  
  getdns_return_t
  getdns_service_sync(getdns_context *context, const char *name,
      getdns_dict *extensions, getdns_dict **response)
  {
  	getdns_sync_loop loop;
  	getdns_return_t r;
  
  	if (!context || !name || !response)
  		return GETDNS_RETURN_INVALID_PARAMETER;
  
  	if ((r = getdns_sync_loop_init(context, &loop)))
  		return r;
  
  	if ((r = priv_getdns_service_loop(context, &loop.loop.loop, name,
  	    extensions, &loop, NULL, getdns_sync_cb))) {
  
  		getdns_sync_loop_cleanup(&loop);
  		return r;
  	}
  	getdns_sync_loop_run(&loop);
  	
  	return (*response = loop.response) ?
  	    GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR;
  }
  
  void
  getdns_free_sync_request_memory(struct getdns_dict *response)
  {
  	getdns_dict_destroy(response);
  }
  
  /* getdns_core_sync.c */
  