int nth_site_get_params(nth_site_t const *site,
			tag_type_t tag, tag_value_t value, ...)
{
  int n;
  ta_list ta;
  server_t *server;
  int master;
  msg_mclass_t const *mclass;

  if (site == NULL)
    return (errno = EINVAL), -1;

  server = site->site_server;
  master = site == server->srv_sites;

  if (master && server->srv_mclass != http_default_mclass())
    mclass = server->srv_mclass;
  else
    mclass = NULL;

  ta_start(ta, tag, value);

  n = tl_tgets(ta_args(ta),
	       TAG_IF(master, NTHTAG_MCLASS(mclass)),
	       TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags)),
	       TAG_END());

  ta_end(ta);

  return n;
}
int nth_engine_get_params(nth_engine_t const *he,
			  tag_type_t tag, tag_value_t value, ...)
{
  int n;
  ta_list ta;
  msg_mclass_t const *mclass;

  if (he == NULL)
    return (errno = EINVAL), -1;

  if (he->he_mclass != http_default_mclass())
    mclass = he->he_mclass;
  else
    mclass = NULL;

  ta_start(ta, tag, value);

  n = tl_tgets(ta_args(ta),
	       NTHTAG_ERROR_MSG(he->he_error_msg),
	       NTHTAG_MCLASS(mclass),
	       NTHTAG_MFLAGS(he->he_mflags),
	       NTHTAG_EXPIRES(he->he_expires),
	       NTHTAG_STREAMING(he->he_streaming),
	       NTHTAG_PROXY((url_string_t *) he->he_default_proxy),
	       TAG_END());

  ta_end(ta);

  return n;
}
int nth_engine_set_params(nth_engine_t * he,
			  tag_type_t tag, tag_value_t value, ...)
{
  int n;
  ta_list ta;
  unsigned expires;
  int error_msg;
  msg_mclass_t const *mclass;
  int mflags;
  int streaming;
  url_string_t const *proxy;

  if (he == NULL)
    return (errno = EINVAL), -1;

  ta_start(ta, tag, value);

  expires = he->he_expires;
  error_msg = he->he_error_msg;
  mclass = he->he_mclass;
  mflags = he->he_mflags;
  streaming = he->he_streaming;
  proxy = (void *) he->he_default_proxy;

  n = tl_gets(ta_args(ta),
	      NTHTAG_EXPIRES_REF(expires),
	      NTHTAG_ERROR_MSG_REF(error_msg),
	      NTHTAG_MCLASS_REF(mclass),
	      NTHTAG_MFLAGS_REF(mflags),
	      NTHTAG_STREAMING_REF(streaming),
	      NTHTAG_PROXY_REF(proxy), TAG_END());

  if (n > 0) {
    if (proxy->us_url != he->he_default_proxy) {
      url_t *copy = url_hdup(he->he_home, proxy->us_url);

      if (proxy && !copy) {
	n = -1;
      } else {
	su_free(he->he_home, (void *) he->he_default_proxy);
	he->he_default_proxy = copy;
      }
    }
  }

  if (n > 0) {
    he->he_expires = expires;
    he->he_error_msg = error_msg != 0;
    if (mclass)
      he->he_mclass = mclass;
    else
      he->he_mclass = http_default_mclass();
    he->he_mflags = mflags;
    he->he_streaming = streaming != 0;
  }

  ta_end(ta);

  return n;
}
nth_engine_t *nth_engine_create(su_root_t *root,
				tag_type_t tag, tag_value_t value, ...)
{
  nth_engine_t *he;
  ta_list ta;

  if ((he = su_home_new(sizeof(*he)))) {
    he->he_root = root;
    he->he_mflags = MSG_DO_CANONIC;
    he->he_mclass = http_default_mclass();
    he->he_expires = 32000;

    ta_start(ta, tag, value);

    if (hc_htable_resize(he->he_home, he->he_clients, 0) < 0 ||
	he_create_tports(he, ta_args(ta)) < 0 ||
	he_timer_init(he) < 0 || nth_engine_set_params(he, ta_tags(ta)) < 0) {
      nth_engine_destroy(he), he = NULL;
    }

    ta_end(ta);
  }

  return he;
}
int nth_site_set_params(nth_site_t *site,
			tag_type_t tag, tag_value_t value, ...)
{
  int n;
  ta_list ta;

  server_t *server;
  int master;
  msg_mclass_t const *mclass;
  int mflags;
  auth_mod_t *am;

  if (site == NULL)
    return (errno = EINVAL), -1;

  server = site->site_server;
  master = site == server->srv_sites;
  am = site->site_auth;

  mclass = server->srv_mclass;
  mflags = server->srv_mflags;

  ta_start(ta, tag, value);

  n = tl_gets(ta_args(ta),
	      TAG_IF(master, NTHTAG_MCLASS_REF(mclass)),
	      TAG_IF(master, NTHTAG_MFLAGS_REF(mflags)),
	      NTHTAG_AUTH_MODULE_REF(am),
	      TAG_END());

  if (n > 0) {
    if (mclass)
      server->srv_mclass = mclass;
    else
      server->srv_mclass = http_default_mclass();
    server->srv_mflags = mflags;
    auth_mod_ref(am), auth_mod_unref(site->site_auth), site->site_auth = am;
  }

  ta_end(ta);

  return n;
}
server_t *server_create(url_t const *url,
			tag_type_t tag, tag_value_t value, ...)
{
  server_t *srv;
  msg_mclass_t const *mclass = NULL;
  tp_name_t tpn[1] = {{ NULL }};
  su_root_t *root = NULL;
  http_server_t const *server = NULL;
  int persistent = 0;
  char const *server_str = SERVER_VERSION;
  ta_list ta;

  ta_start(ta, tag, value);
  tl_gets(ta_args(ta),
	  NTHTAG_ROOT_REF(root),
	  NTHTAG_MCLASS_REF(mclass),
	  TPTAG_REUSE_REF(persistent),
	  HTTPTAG_SERVER_REF(server),
	  HTTPTAG_SERVER_STR_REF(server_str),
	  TAG_END());

  if (!root || !url ||
      (url->url_type != url_http && url->url_type != url_https)
      || !(srv = su_home_new(sizeof(*srv)))) {
    ta_end(ta);
    return NULL;
  }

  tpn->tpn_proto = url_tport_default((enum url_type_e)url->url_type);
  tpn->tpn_canon = url->url_host;
  tpn->tpn_host =  url->url_host;
  tpn->tpn_port = url_port(url);

  srv->srv_tports = tport_tcreate(srv, nth_server_class, root,
				  TPTAG_IDLE(600000),
				  TPTAG_TIMEOUT(300000),
				  ta_tags(ta));

  srv->srv_persistent = persistent;
  srv->srv_max_bodylen = 1 << 30; /* 1 GB */

  if (tport_tbind(srv->srv_tports, tpn, http_tports,
		  TAG_END()) >= 0 ||
      tport_tbind(srv->srv_tports, tpn, http_no_tls_tports,
		  TAG_END()) >= 0) {
    srv->srv_root = root;
    srv->srv_mclass = mclass ? mclass : http_default_mclass();
    srv->srv_mflags = MSG_DO_CANONIC;

    if (server)
      srv->srv_server = http_server_dup(srv->srv_home, server);
    else
      srv->srv_server = http_server_make(srv->srv_home, server_str);

    tport_get_params(srv->srv_tports,
		     TPTAG_QUEUESIZE_REF(srv->srv_queuesize),
		     TAG_END());
  }
  else {
    SU_DEBUG_1(("nth_server_create: cannot bind transports "
		URL_FORMAT_STRING "\n",
		URL_PRINT_ARGS(url)));
    server_destroy(srv), srv = NULL;
  }

  ta_end(ta);

  return srv;
}
static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai,
				   tp_name_t const *tpn)
{
  tport_http_connect_t *thc = (tport_http_connect_t *)pri;
  tport_http_connect_instance_t *thci;
  tport_master_t *mr = pri->pri_master;

  msg_t *msg, *response;

  char hostport[TPORT_HOSTPORTSIZE];

  tport_t *tport;
  http_request_t *rq;

  msg = msg_create(http_default_mclass(), 0);

  if (!msg)
    return NULL;

  tport_hostport(hostport, sizeof hostport, (void *)ai->ai_addr, 1);

  rq = http_request_format(msg_home(msg), "CONNECT %s HTTP/1.1", hostport);

  if (msg_header_insert(msg, NULL, (void *)rq) < 0
      || msg_header_add_str(msg, NULL,
			    "User-Agent: Sofia-SIP/" VERSION "\n") < 0
      || msg_header_add_str(msg, NULL, "Proxy-Connection: keepalive\n") < 0
      || msg_header_add_make(msg, NULL, http_host_class, hostport) < 0
      || msg_header_add_make(msg, NULL, http_separator_class, "\r\n") < 0
      || msg_serialize(msg, NULL) < 0
      || msg_prepare(msg) < 0)
    return (void)msg_destroy(msg), NULL;

  /*
   * Create a response message that ignores the body
   * if there is no Content-Length
   */
  response = msg_create(http_default_mclass(), mr->mr_log | MSG_FLG_MAILBOX);

  tport = tport_base_connect(pri, thc->thc_proxy, ai, tpn);
  if (!tport) {
    msg_destroy(msg); msg_destroy(response);
    return tport;
  }

  thci = (tport_http_connect_instance_t*)tport;

  thci->thci_response = response;
  tport->tp_msg = response;
  msg_set_next(response, thci->thci_stackmsg = tport_msg_alloc(tport, 512));

  if (tport_send_msg(tport, msg, tpn, NULL) < 0) {
    SU_DEBUG_9(("tport_send_msg failed in tpot_http_connect\n" VA_NONE));
    msg_destroy(msg);
    tport_zap_secondary(tport);
    return NULL;
  }

  tport_set_secondary_timer(tport);

  return tport;
}