예제 #1
0
/** Add a Content-Length and separator to a message */
int http_message_complete(msg_t *msg, http_t *http)
{
#if 1
  if (!http->http_content_length) {
    http_content_length_t *l;
    http_payload_t *pl;
    size_t len = 0;

    for (pl = http->http_payload; pl; pl = pl->pl_next)
      len += pl->pl_len;

    if (len > UINT32_MAX)
      return -1;

    l = http_content_length_create(msg_home(msg), (uint32_t)len);

    if (msg_header_insert(msg, http, (http_header_t *)l) < 0)
      return -1;
  }
#endif

  if (!http->http_separator) {
    http_separator_t *sep = http_separator_create(msg_home(msg));
    if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
      return -1;
  }

  return 0;
}
예제 #2
0
/** Complete a HTTP request. */
int http_request_complete(msg_t *msg)
{
  size_t len = 0;
  http_t *http = http_object(msg);
  http_payload_t const *pl;
  su_home_t *home = msg_home(msg);

  if (!http)
    return -1;
  if (!http->http_request)
    return -1;
  if (!http->http_host)
    return -1;

    for (pl = http->http_payload; pl; pl = pl->pl_next)
      len += pl->pl_len;

  if (len > UINT32_MAX)
    return -1;

  if (!http->http_content_length) {
    http->http_content_length = http_content_length_create(home, (uint32_t)len);
  }
  else {
    if (http->http_content_length->l_length != len) {
      http->http_content_length->l_length = (uint32_t)len;
      msg_fragment_clear(http->http_content_length->l_common);
    }
  }

  if (!http->http_separator)
    http->http_separator = http_separator_create(home);

  return 0;
}
예제 #3
0
/** Copy a complete message, not keeping the header chain structure.
 *
 * @retval 0 when successful
 * @retval -1 upon an error
 */
static
int msg_dup_or_copy_all(msg_t *msg,
			msg_t const *original,
			msg_header_t *(*copy_one)(su_home_t *h,
						  msg_header_t const *))
{
  su_home_t *home = msg_home(msg);
  msg_pub_t *dst = msg->m_object;

  msg_pub_t const *src = original->m_object;
  msg_header_t * const *ssh;
  msg_header_t * const *end;
  msg_header_t const *sh;
  msg_header_t **hh;

  msg_header_t *h;

  assert(copy_one);

  end = (msg_header_t**)((char *)src + src->msg_size);

  for (ssh = &src->msg_request; ssh < end; ssh++) {
    sh = *ssh;
    if (!sh)
      continue;

    hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
    if (hh == NULL)
	return -1;

    for (; sh; sh = sh->sh_next) {
      h = copy_one(home, sh);
      if (h == NULL)
	return -1;

      if (*hh) {
	/* If there is multiple instances of single headers,
	   put the extra headers into the list of erroneous headers */
	if (msg_is_single(h)) {
	  msg_error_t **e;
	  for (e = &dst->msg_error; *e; e = &(*e)->er_next)
	    ;
	  *e = (msg_error_t *)h;
	  continue;
	}

	while (*hh)
	  hh = &(*hh)->sh_next;
      }
      *hh = h;

      if (msg_is_list(sh))
	/* Copy only first list entry */
	break;
    }
  }

  return 0;
}
예제 #4
0
/** Add a duplicate of header object to a HTTP message. */
int http_add_dup(msg_t *msg,
		 http_t *http,
		 http_header_t const *o)
{
  if (o == HTTP_NONE)
    return 0;

  if (msg == NULL || o == NULL)
    return -1;

  return msg_header_insert(msg, http, msg_header_dup(msg_home(msg), o));
}
예제 #5
0
int http_add_make(msg_t *msg,
		 http_t *http,
		 msg_hclass_t *hc,
		 char const *s)
{
  if (s == NULL)
    return 0;

  if (msg == NULL)
    return -1;

  return msg_header_insert(msg, http, msg_header_make(msg_home(msg), hc, s));
}
예제 #6
0
/** Fork an outgoing request (stdarg version of nta_outgoing_fork()). 
 *
 * @deprecated
 * Use nta_outgoing_mcreate() instead.
 */
nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq,
				   nta_response_f *callback,
				   nta_outgoing_magic_t *magic,
				   url_string_t const *route_url,
				   url_string_t const *request_uri,
				   void const *extra,
				   va_list headers)
{
  nta_outgoing_t * orq;
  msg_t *msg, *imsg;
  sip_t *sip, *isip;
  nta_agent_t *agent;
  su_home_t *home;

  if (!old_orq || !old_orq->orq_request || !request_uri)
    return NULL;

  agent = old_orq->orq_agent;
  imsg = old_orq->orq_request;
  
  if (!(msg = nta_msg_create(agent, 0)))
    return NULL;

  msg_clone(msg, imsg);

  sip = sip_object(msg); isip = sip_object(imsg);
  home = msg_home(msg);

  /* Copy the SIP headers from the imsg message */
  if (sip_copy_all(msg, sip, isip) < 0)
    orq = NULL;
  else if (sip_via_remove(msg, sip) == NULL)
    orq = NULL;
  else if (sip_add_dup(msg, sip_object(msg), 
		       (sip_header_t const *)
		       sip_request_create(home,
					  sip->sip_request->rq_method, 
					  sip->sip_request->rq_method_name, 
					  request_uri,
					  NULL)) < 0)
    orq = NULL;
  else if (sip_add_headers(msg, sip, extra, headers) < 0)
    orq = NULL;
  else
    orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg);

  if (!orq)
    msg_destroy(msg);

  return orq;
}
예제 #7
0
/** Add headers from the request to the response message. */
int http_complete_response(msg_t *msg,
			   int status, char const *phrase,
			   http_t const *request)
{
  su_home_t *home = msg_home(msg);
  http_t *http = msg_object(msg);

  if (!http || !request || !request->http_request)
    return -1;

  if (!http->http_status)
    http->http_status = http_status_create(home, status, phrase, NULL);

  if (!http->http_status)
    return -1;

  if (!http->http_separator) {
    http_separator_t *sep = http_separator_create(msg_home(msg));
    if (msg_header_insert(msg, http, (http_header_t *)sep) < 0)
      return -1;
  }

  return 0;
}
예제 #8
0
/**@ingroup sip_route
 *
 * Get first route header and rewrite the RequestURI.
 */
sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip)
{
  if (sip->sip_route) {
    /* XXX - in case of outbound proxy, route may contain our address */

    sip_route_t *r = sip_route_remove(msg, sip);
    sip_request_t *rq = sip->sip_request;

    rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name,
			    (url_string_t const *)r->r_url, rq->rq_version);
    url_strip_transport(rq->rq_url);

    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq);

    return r;
  }
  return NULL;
}
예제 #9
0
/** Send a BYE to an INVITE.
 *
 * @deprecated
 * This function should used only if application requires 
 * RFC2543 compatibility.
 */
nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq,
				  nta_response_f *callback,
				  nta_outgoing_magic_t *magic,
				  url_string_t const *route_url,
				  tag_type_t tag, tag_value_t value, ...)
{
  msg_t *msg;
  sip_t *sip, *inv;
  sip_cseq_t *cs;
  sip_request_t *rq;
  su_home_t *home;
  url_string_t *url;

  if (orq == NULL || orq->orq_method != sip_method_invite)
    return NULL;

  inv = sip_object(orq->orq_request);
  msg = nta_msg_create(orq->orq_agent, 0);
  home = msg_home(msg);
  sip = sip_object(msg);

  if (inv == NULL || sip == NULL) {
    msg_destroy(msg);
    return NULL;
  }

  sip_add_tl(msg, sip,
	     SIPTAG_TO(inv->sip_to),
	     SIPTAG_FROM(inv->sip_from),
	     SIPTAG_CALL_ID(inv->sip_call_id),
	     SIPTAG_ROUTE(inv->sip_route),
	     TAG_END());

  url = (url_string_t *)inv->sip_request->rq_url;

  rq = sip_request_create(home, SIP_METHOD_BYE, url, NULL);
  sip_header_insert(msg, sip, (sip_header_t*)rq);

  cs = sip_cseq_create(home, inv->sip_cseq->cs_seq + 1, SIP_METHOD_BYE);
  sip_header_insert(msg, sip, (sip_header_t*)cs);

  return nta_outgoing_mcreate(orq->orq_agent, callback, magic, 
			      route_url, msg);
}
예제 #10
0
/* Return Via that looks very natted */
static sip_via_t *natted_via(struct message *m, const char *receive_natted)
{
  su_home_t *h;
  sip_via_t *via;

  h = msg_home(m->msg);
  via = sip_via_dup(h, m->sip->sip_via);
  msg_header_replace_param(h, via->v_common, receive_natted);

  if (via->v_protocol == sip_transport_udp)
    msg_header_replace_param(h, via->v_common, "rport=9");

  if (via->v_protocol == sip_transport_tcp && via->v_rport) {
    tp_name_t const *tpn = tport_name(m->tport);
    char *rport = su_sprintf(h, "rport=%s", tpn->tpn_port);
    msg_header_replace_param(h, via->v_common, rport);
  }

  return via;
}
예제 #11
0
int http_add_format(msg_t *msg,
		    http_t *http,
		    msg_hclass_t *hc,
		    char const *fmt,
		    ...)
{
  http_header_t *h;
  va_list ap;

  if (fmt == NULL)
    return 0;

  if (msg == NULL)
    return -1;

  va_start(ap, fmt);
  h = http_header_vformat(msg_home(msg), hc, fmt, ap);
  va_end(ap);

  return msg_header_insert(msg, http, h);
}
예제 #12
0
/** Copy header chain.
 *
 * @retval 0 when successful
 * @retval -1 upon an error
 */
static
int msg_copy_chain(msg_t *msg, msg_t const *original)
{
  su_home_t *home = msg_home(msg);
  msg_pub_t *dst = msg->m_object;
  msg_header_t **tail;
  msg_header_t *dh;
  msg_header_t const *sh;
  msg_header_t **hh;

  tail = msg->m_tail;

  for (sh = original->m_chain; sh; sh = (msg_header_t const *)sh->sh_succ) {
    hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
    if (!hh)
      break;
    while (*hh)
      hh = &(*hh)->sh_next;

    dh = msg_header_copy_one(home, sh);
    if (!dh)
      break;

    dh->sh_prev = tail, *tail = dh, tail = &dh->sh_succ;

    *hh = dh;
  }

  msg->m_tail = tail;

  if (sh)
    return -1;

  return 0;

}
예제 #13
0
/** Respond without creating a request structure */
static void server_reply(server_t *srv, tport_t *tport,
			 msg_t *request, msg_t *response,
			 int status, char const *phrase)
{
  http_t *http;
  http_payload_t *pl;
  int close;
  http_status_t st[1];
  char const *req_version = NULL;

  if (status < 200 || status >= 600)
    status = 500, phrase = http_500_internal_server;

  http = http_object(request);

  if (http && http->http_request)
    req_version = http->http_request->rq_version;

  close = status >= 200 &&
    (!srv->srv_persistent
     || status == 400
     || (http && http->http_request &&
	 http->http_request->rq_version != http_version_1_1)
     || (http && http->http_connection &&
	 msg_params_find(http->http_connection->k_items, "close")));

  msg_destroy(request);

  http = http_object(response);

  pl = http_payload_format(msg_home(response),
			   "<html>\n"
			   "<head><title>%u %s</title></head>\n"
			   "<body><h2>%u %s</h2></body>\n"
			   "</html>\n", status, phrase, status, phrase);

  msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl);

  if (req_version != http_version_0_9) {
    http_status_init(st);
    st->st_version = http_version_1_1;
    st->st_status = status;
    st->st_phrase = phrase;

    http_add_tl(response, http,
		HTTPTAG_STATUS(st),
		HTTPTAG_SERVER(srv->srv_server),
		HTTPTAG_CONTENT_TYPE_STR("text/html"),
		HTTPTAG_SEPARATOR_STR("\r\n"),
		TAG_IF(close, HTTPTAG_CONNECTION_STR("close")),
		TAG_END());

    msg_serialize(response, (msg_pub_t *)http);
  } else {
    /* Just send the response */
    *msg_chain_head(response) = (msg_header_t *)pl;
    close = 1;
  }

  if (tport_tqsend(tport, response, NULL,
		   TPTAG_CLOSE_AFTER(close),
		   TAG_END()) == -1) {
    SU_DEBUG_3(("server_reply(): cannot queue response\n"));
    tport_shutdown(tport, 2);
  }

  msg_destroy(response);
}
예제 #14
0
int nth_request_treply(nth_request_t *req,
		       int status, char const *phrase,
		       tag_type_t tag, tag_value_t value, ...)
{
  msg_t *response, *next = NULL;
  http_t *http;
  int retval = -1;
  int req_close, close;
  ta_list ta;
  http_header_t const *as_info = NULL;

  if (req == NULL || status < 100 || status >= 600) {
    return -1;
  }

  response = req->req_response;
  http = http_object(response);

  if (status >= 200 && req->req_as)
    as_info = (http_header_t const *)req->req_as->as_info;

  ta_start(ta, tag, value);

  http_add_tl(response, http,
	      HTTPTAG_SERVER(req->req_server->srv_server),
	      HTTPTAG_HEADER(as_info),
	      ta_tags(ta));

  if (http->http_payload && !http->http_content_length) {
    http_content_length_t *l;
    http_payload_t *pl;
    size_t len = 0;

    for (pl = http->http_payload; pl; pl = pl->pl_next)
      len += pl->pl_len;

    if (len > UINT32_MAX)
      goto fail;

    l = http_content_length_create(msg_home(response), (uint32_t)len);

    msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)l);
  }

  if (req->req_method == http_method_head && http->http_payload) {
    http_payload_t *pl;

    for (pl = http->http_payload; pl; pl = pl->pl_next)
      msg_header_remove(response, (msg_pub_t *)http, (msg_header_t *)pl);
  }

  http_complete_response(response, status, phrase,
			 http_object(req->req_request));

  if (!http->http_date) {
    http_date_t date[1];
    http_date_init(date)->d_time = msg_now();
    msg_header_add_dup(response, (msg_pub_t *)http, (msg_header_t*)date);
  }

  if (status < 200) {
    close = 0;
    next = server_msg_create(req->req_server, 0, NULL, 0, NULL, NULL);
  }
  else {
    req_close = req->req_close;

    close = (http->http_connection &&
	     msg_params_find(http->http_connection->k_items, "close"));

    if (req_close && !close && status >= 200) {
      close = 1;
      http_add_tl(response, http, HTTPTAG_CONNECTION_STR("close"), TAG_END());
    }
  }

  msg_serialize(response, (msg_pub_t *)http);

  retval = tport_tqsend(req->req_tport, response, next,
			TAG_IF(close, TPTAG_CLOSE_AFTER(1)),
			ta_tags(ta));

 fail:
  ta_end(ta);

  if (retval == 0)
    req->req_status = status;

  return retval;
}
예제 #15
0
static
int nua_notify_client_request(nua_client_request_t *cr,
			      msg_t *msg, sip_t *sip,
			      tagi_t const *tags)
{
  nua_dialog_usage_t *du = cr->cr_usage;
  struct notifier_usage *nu = nua_dialog_usage_private(du);
  su_home_t *home = msg_home(msg);
  sip_time_t now = sip_now();
  sip_subscription_state_t *ss = sip->sip_subscription_state;
  char const *expires;

  if (du == NULL)		/* Subscription has been terminated */
    return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);

  assert(du && nu);

  if (du && nua_client_bind(cr, du) < 0)
    return -1;

  if (nu->nu_requested)
    nu->nu_expires = nu->nu_requested;
  nu->nu_requested = 0;

  if (nu->nu_expires <= now || du->du_shutdown) {
    nu->nu_substate = nua_substate_terminated;
    expires = "expires=0";
  }
  else {
    expires = su_sprintf(home, "expires=%lu", nu->nu_expires - now);
  }

  if (ss == NULL || nua_substate_make(ss->ss_substate) != nu->nu_substate) {
    if (nu->nu_substate == nua_substate_terminated)
      expires = nu->nu_expires > now ? "reason=noresource" : "reason=timeout";

    ss = sip_subscription_state_format(home, "%s;%s",
				       nua_substate_name(nu->nu_substate),
				       expires);

    msg_header_insert(msg, (void *)sip, (void *)ss);
  }
  else if (nu->nu_substate != nua_substate_terminated) {
    msg_header_replace_param(home, ss->ss_common, expires);
  }

#if SU_HAVE_EXPERIMENTAL
  if (nu->nu_tag && !sip->sip_etag)
    msg_header_add_make(msg, (void *)sip, sip_etag_class, nu->nu_tag);

  if (nu->nu_no_body) {
    nu->nu_no_body = 0;
    msg_header_remove(msg, (void *)sip, (void *)sip->sip_payload);
    msg_header_remove(msg, (void *)sip, (void *)sip->sip_content_length);
  }
#endif

  if (nu->nu_substate == nua_substate_terminated)
    nua_client_set_terminating(cr, 1);

  if (cr->cr_terminating) {
    nua_server_request_t *sr;
    for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) {
      if (sr->sr_usage == du) {
	/* If subscribe has not been responded, don't terminate usage by NOTIFY */
	sr->sr_terminating = 1;
	nua_client_set_terminating(cr, 0);
	break;
      }
    }
  }

  if (du->du_event && !sip->sip_event)
    sip_add_dup(cr->cr_msg, sip, (sip_header_t *)du->du_event);

  return nua_base_client_request(cr, msg, sip, tags);
}
예제 #16
0
/**Forward a request belonging to the leg 
 * (stdarg version of nta_outgoing_forward()).
 *
 * @deprecated
 * Use nta_outgoing_mcreate() instead.
 */
nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
				      nta_response_f *callback,
				      nta_outgoing_magic_t *magic,
				      url_string_t const *route_url,
				      url_string_t const *request_uri,
				      nta_incoming_t const *ireq,
				      sip_t const *isip,
				      void const *extra,
				      va_list headers)
{
  nta_agent_t *agent = leg->leg_agent;
  nta_outgoing_t *orq = NULL;
  msg_t *msg, *imsg;
  sip_t *sip;
  su_home_t *home;

  assert(leg); assert(ireq); 

  if (isip == NULL) 
    imsg = ireq->irq_request, isip = sip_object(ireq->irq_request);
  else if (isip == sip_object(ireq->irq_request))
    imsg = ireq->irq_request;
  else if (isip == sip_object(ireq->irq_request2))
    imsg = ireq->irq_request2;
  else {
    SU_DEBUG_3(("nta_outgoing_forward: invalid arguments\n"));
    return NULL;
  }

  assert(isip); assert(isip->sip_request);

  if (!route_url)
    route_url = (url_string_t *)agent->sa_default_proxy;

  if (!(msg = nta_msg_create(agent, 0)))
    return NULL;

  msg_clone(msg, imsg);

  sip = sip_object(msg); 
  home = msg_home(msg);
  
  /* Copy the SIP headers from the @c imsg message */
  do {
    if (sip_copy_all(msg, sip, isip) < 0)
      break;
    if (sip_add_headers(msg, sip, extra, headers) < 0)
      break;
    if (!route_url && sip->sip_route) {
      request_uri = (url_string_t *)sip->sip_route->r_url;
      if (!sip_route_remove(msg, sip))
	break;
    }
    if (request_uri) {
      sip_request_t *rq;

      rq = sip_request_create(home,
			      sip->sip_request->rq_method, 
			      sip->sip_request->rq_method_name, 
			      request_uri,
			      NULL);

      if (!rq || sip_header_insert(msg, sip, (sip_header_t *)rq) < 0)
	break;
    }
    
    if ((orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg)))
      return orq;

  } while (0);

  msg_destroy(msg);
  return NULL;
}
예제 #17
0
/** @internal Send an event to the application. */
int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
		    nua_event_t event, int status, char const *phrase,
		    tagi_t const *tags)
{
  su_msg_r sumsg = SU_MSG_R_INIT;
  size_t e_len, len, xtra, p_len;

  if (event == nua_r_ack || event == nua_i_none)
    return event;

  if (nh == nua->nua_dhandle)
    nh = NULL;

  if (nua_log->log_level >= 5) {
    char const *name = nua_event_name(event) + 4;
    char const *p = phrase ? phrase : "";

    if (status == 0)
      SU_DEBUG_5(("nua(%p): event %s %s\n", (void *)nh, name, p));
    else
      SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)nh, name, status, p));
  }

  if (event == nua_r_destroy) {
    if (msg)
      msg_destroy(msg);
    if (status >= 200) {
      nh_destroy(nua, nh);
    }
    return event;
  }

  if ((event > nua_r_authenticate && event <= nua_r_ack)
      || event < nua_i_error
      || (nh && !nh->nh_valid)
      || (nua->nua_shutdown && event != nua_r_shutdown &&
	  !nua->nua_prefs->ngp_shutdown_events)) {
    if (msg)
      msg_destroy(msg);
    return event;
  }

  if (tags) {
    e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
    len = tl_len(tags);
    xtra = tl_xtra(tags, len);
  }
  else {
    e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0;
  }
  p_len = phrase ? strlen(phrase) + 1 : 1;

  if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) {
    nua_ee_data_t *ee = su_msg_data(sumsg);
    nua_event_data_t *e = ee->ee_data;
    void *p;

    if (tags) {
      tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len);
      void *b = t_end, *end = (char *)b + xtra;

      t = tl_dup(t, tags, &b); p = b;
      assert(t == t_end); assert(b == end); (void)end;
    }
    else
      p = e + 1;

    ee->ee_nua = nua_stack_ref(nua);
    e->e_event = event;
    e->e_nh = nh ? nua_handle_ref(nh) : NULL;
    e->e_status = status;
    e->e_phrase = strcpy(p, phrase ? phrase : "");
    if (msg)
      e->e_msg = msg, su_home_threadsafe(msg_home(msg));

    su_msg_deinitializer(sumsg, nua_event_deinit);

    su_msg_send_to(sumsg, nua->nua_client, nua_application_event);
  }

  return event;
}
예제 #18
0
파일: outbound.c 프로젝트: FreeMCU/freemcu
/** @internal Create a message template for keepalive. */
static int create_keepalive_message(outbound_t *ob, sip_t const *regsip)
{
  msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous;
  sip_t *osip = sip_object(msg);
  sip_contact_t *m = ob->ob_rcontact;

  unsigned d = ob->ob_keepalive.interval;

  if (msg == NULL)
    return -1;

  assert(regsip); assert(regsip->sip_request);

  if (m && m->m_params) {
    sip_accept_contact_t *ac;
    size_t i;
    int features = 0;

    ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit");

    for (i = 0; m->m_params[i]; i++) {
      char const *s = m->m_params[i];
      if (!sip_is_callerpref(s))
	continue;
      features++;
      s = su_strdup(msg_home(msg), s);
      msg_header_add_param(msg_home(msg), ac->cp_common, s);
    }

    if (features)
      msg_header_insert(msg, NULL, (void *)ac);
    else
      msg_header_free(msg_home(msg), (void *)ac);
  }

  if (0 >
      /* Duplicate essential headers from REGISTER request: */
      sip_add_tl(msg, osip,
		 SIPTAG_TO(regsip->sip_to),
		 SIPTAG_FROM(regsip->sip_from),
		 /* XXX - we should only use loose routing here */
		 /* XXX - if we used strict routing,
		    the route header/request_uri must be restored
		 */
		 SIPTAG_ROUTE(regsip->sip_route),
		 /* Add Max-Forwards 0 */
		 TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")),
		 TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")),
		 SIPTAG_CALL_ID_STR(ob->ob_cookie),
		 SIPTAG_ACCEPT_STR(outbound_content_type),
		 TAG_END()) ||
      /* Create request-line, Call-ID, CSeq */
      nta_msg_request_complete(msg,
       			nta_default_leg(ob->ob_nta),
       			SIP_METHOD_OPTIONS,
       			(void *)regsip->sip_to->a_url) < 0 ||
      msg_serialize(msg, (void *)osip) < 0 ||
      msg_prepare(msg) < 0)
    return msg_destroy(msg), -1;

  previous = ob->ob_keepalive.msg;
  ob->ob_keepalive.msg = msg;
  msg_destroy(previous);

  return 0;
}
예제 #19
0
/**Send a request message.
 *
 * @retval 0 if request is pending
 * @retval >=1 if error event has been sent
 * @retval < 0 if no error event has been sent
 */
static
int nua_client_request_sendmsg(nua_client_request_t *cr)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_state_t *ds = nh->nh_ds;
  sip_method_t method = cr->cr_method;
  char const *name = cr->cr_method_name;
  url_string_t const *url = (url_string_t *)cr->cr_target;
  nta_leg_t *leg;
  msg_t *msg;
  sip_t *sip;
  int error;

  assert(cr->cr_orq == NULL);

  cr->cr_offer_sent = cr->cr_answer_recv = 0;
  cr->cr_offer_recv = cr->cr_answer_sent = 0;

  if (!ds->ds_leg && cr->cr_dialog) {
    ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta,
				 nua_stack_process_request, nh,
				 SIPTAG_CALL_ID(cr->cr_sip->sip_call_id),
				 SIPTAG_FROM(cr->cr_sip->sip_from),
				 SIPTAG_TO(cr->cr_sip->sip_to),
				 SIPTAG_CSEQ(cr->cr_sip->sip_cseq),
				 TAG_END());
    if (!ds->ds_leg)
      return -1;
  }

  if (cr->cr_sip->sip_from && ds->ds_leg) {
    if (cr->cr_sip->sip_from->a_tag == NULL) {
      if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from,
		       nta_leg_tag(ds->ds_leg, NULL)) < 0) {
	return -1;
      }
    }
  }

  cr->cr_retry_count++;

  if (ds->ds_leg)
    leg = ds->ds_leg;
  else
    leg = nh->nh_nua->nua_dhandle->nh_ds->ds_leg; /* Default leg */

  msg = msg_copy(cr->cr_msg), sip = sip_object(msg);

  if (msg == NULL)
    return -1;

  if (nua_dialog_is_established(ds)) {
    while (sip->sip_route)
      sip_route_remove(msg, sip);
  }
  else if (!ds->ds_route) {
    sip_route_t *initial_route = NH_PGET(nh, initial_route);

    if (initial_route) {
      initial_route = sip_route_dup(msg_home(msg), initial_route);
      if (!initial_route) return -1;
      msg_header_prepend(msg, (msg_pub_t*)sip,
			 /* This should be
			    (msg_header_t **)&sip->sip_route
			  * but directly casting pointer &sip->sip_route gives
			  * spurious type-punning warning */
			 (msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)),
			 (msg_header_t *)initial_route);
    }
  }


  /**
   * For in-dialog requests, the request URI is taken from the @Contact
   * header received from the remote party during dialog establishment,
   * and the NUTAG_URL() is ignored.
   *
   * Also, the @CallID and @CSeq headers and @From and @To tags are
   * generated based on the dialog information and added to the request.
   * If the dialog has a route, it is added to the request, too.
   */
  if (nta_msg_request_complete(msg, leg, method, name, url) < 0) {
    msg_destroy(msg);
    return -1;
  }

  /**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
   * also added now, if it does not exist.
   */

  if (!ds->ds_remote)
    ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to);
  if (!ds->ds_local)
    ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from);

  /**
   * Next, values previously set with nua_set_params() or nua_set_hparams()
   * are used: @Allow, @Supported, @Organization, @UserAgent and
   * @AllowEvents headers are added to the request if they are not already
   * set.
   */
  if (!sip->sip_allow)
    sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow));

  if (!sip->sip_supported && NH_PGET(nh, supported))
    sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported));

  if (method == sip_method_register && NH_PGET(nh, path_enable) &&
      !sip_has_feature(sip->sip_supported, "path") &&
      !sip_has_feature(sip->sip_require, "path"))
    sip_add_make(msg, sip, sip_supported_class, "path");

  if (!sip->sip_organization && NH_PGET(nh, organization))
    sip_add_make(msg, sip, sip_organization_class, NH_PGET(nh, organization));

  if (!sip->sip_user_agent && NH_PGET(nh, user_agent))
    sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent));

  /** Any node implementing one or more event packages SHOULD include an
   * appropriate @AllowEvents header indicating all supported events in
   * all methods which initiate dialogs and their responses (such as
   * INVITE) and OPTIONS responses.
   */
  if (!sip->sip_allow_events &&
      NH_PGET(nh, allow_events) &&
      (method == sip_method_notify || /* Always in NOTIFY */
       (!ds->ds_remote_tag &&	      /* And in initial requests */
	(method == sip_method_subscribe || method == sip_method_refer ||
	 method == sip_method_options ||
	 method == sip_method_invite))))
    sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events));

  /**
   * Next, the stack generates a @Contact header for the request (unless
   * the application already gave a @Contact header or it does not want to
   * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
   * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the
   * application has registered the URI in @From header, the @Contact
   * header used with registration is used. Otherwise, the @Contact header
   * is generated from the local IP address and port number.
   */

  /**For the initial requests, @ServiceRoute set that was received from the
   * registrar is also added to the request message.
   */
  if (cr->cr_method != sip_method_register) {
    if (cr->cr_contactize && cr->cr_has_contact) {
      sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact);
      if (ds->ds_ltarget)
	msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget);
      ds->ds_ltarget = ltarget;
    }

    if (ds->ds_ltarget && !cr->cr_has_contact)
      sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget);

    if (nua_registration_add_contact_to_request(nh, msg, sip,
						cr->cr_contactize &&
						!cr->cr_has_contact &&
						!ds->ds_ltarget,
						!ds->ds_route) < 0) {
      msg_destroy(msg);
      return -1;
    }
  }

  cr->cr_wait_for_cred = 0;

  if (cr->cr_methods->crm_send)
    error = cr->cr_methods->crm_send(cr, msg, sip, NULL);
  else
    error = nua_base_client_request(cr, msg, sip, NULL);

  if (error == -1)
    msg_destroy(msg);

  return error;
}
예제 #20
0
/**Add message separator, then test if message is complete.
 *
 * Add sip_content_length and sip_separator if they are missing.
 * The test that all necessary message components ( @From, @To,
 * @CSeq, @CallID, @ContentLength and message separator are present.
 *
 * @retval 0 when successful
 * @retval -1 upon an error: headers are missing and they could not be added
 */
int sip_complete_message(msg_t *msg)
{
  sip_t *sip = sip_object(msg);
  su_home_t *home = msg_home(msg);
  size_t len = 0;
  ssize_t mplen;

  if (sip == NULL)
    return -1;

  if (!sip->sip_separator)
    sip->sip_separator = sip_separator_create(msg_home(msg));

  if (sip->sip_multipart) {
    sip_content_type_t *c = sip->sip_content_type;
    msg_multipart_t *mp = sip->sip_multipart;
    sip_common_t *head;

    if (!c || msg_multipart_complete(msg_home(msg), c, mp) < 0)
      return -1;

    if (sip->sip_payload)
      head = sip->sip_payload->pl_common;
    else
      head = sip->sip_separator->sep_common;

    if (!head || !msg_multipart_serialize(&head->h_succ, mp))
      return -1;

    mplen = msg_multipart_prepare(msg, mp, sip->sip_flags);
    if (mplen == -1)
      return -1;
    len = (size_t)mplen;
  }

  if (sip->sip_payload)
    len += sip->sip_payload->pl_len;

  if (len > UINT32_MAX)
    return -1;

  if (!sip->sip_content_length) {
    msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t*)
		      sip_content_length_create(home, (uint32_t)len));
  }
  else {
    if (sip->sip_content_length->l_length != len) {
      sip->sip_content_length->l_length = (uint32_t)len;
      sip_fragment_clear(sip->sip_content_length->l_common);
    }
  }

  if (!sip->sip_cseq ||
      !sip->sip_call_id ||
      !sip->sip_to ||
      !sip->sip_from ||
      !sip->sip_separator ||
      !sip->sip_content_length)
    return -1;

  return 0;
}
예제 #21
0
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;
}