/* 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;
}
Esempio n. 2
0
/**Set new contact.
 *
 * @retval 0 when successful
 * @retval -1 error setting contact
 */
int outbound_set_contact(outbound_t *ob,
			 sip_contact_t const *application_contact,
			 sip_via_t const *v,
			 int terminating)
{
  su_home_t *home = ob->ob_home;
  sip_contact_t *rcontact = NULL, *dcontact = NULL, *previous = NULL;
  sip_contact_t *m1, *m2, *m3;
  int contact_uri_changed = 0;

  m1 = ob->ob_rcontact;
  m2 = ob->ob_dcontact;
  m3 = ob->ob_previous;

  if (terminating) {
    if (ob->ob_by_stack && application_contact == NULL)
      return 0;

    if (ob->ob_contacts)
      previous = ob->ob_rcontact;
  }
  else if (application_contact) {
    rcontact = sip_contact_dup(home, application_contact);

    if (!ob->ob_rcontact ||
	url_cmp_all(ob->ob_rcontact->m_url, application_contact->m_url)) {
      contact_uri_changed = 1;
      previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
    }
  }
  else if (ob->ob_by_stack) {
    return 0;    /* Xyzzy - nothing happens */
  }
  else if (v) {
    char const *tport = !v->v_next ? v->v_protocol : NULL;
    char reg_id_param[20];

    dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1,
				     v, tport, NULL);
    if (!dcontact)
      return -1;

    if (ob->ob_instance && ob->ob_reg_id != 0)
      snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);

    rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0,
				     v, v->v_protocol,
				     ob->ob_instance, reg_id_param, NULL);
    if (!rcontact)
      return -1;

    if (!ob->ob_rcontact ||
	url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url)) {
      contact_uri_changed = 1;
      previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
    }
  }

  if (previous)
    msg_header_replace_param(home, (msg_common_t *)previous, "expires=0");

  ob->ob_by_stack = application_contact == NULL;

  ob->ob_contacts = rcontact != NULL;

  ob->ob_rcontact = rcontact;
  ob->ob_dcontact = dcontact;
  ob->ob_previous = previous;

  if (contact_uri_changed) {
    ob->ob_registering = 0;
    ob->ob_registered = 0;
    ob->ob_validated = 0;
    ob->ob_once_validated = 0;
  }

  if (m1 != previous)
    msg_header_free(home, (void *)m1);
  if (m2 != m1 && m2 != m3)
    msg_header_free(home, (void *)m2);
  msg_header_free(home, (void *)m3);

  return 0;
}
Esempio n. 3
0
/**@internal
 * Create contacts for outbound.
 *
 * There are two contacts:
 * one suitable for registrations (ob_rcontact) and another that can be used
 * in dialogs (ob_dcontact).
 */
int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via)
{
  su_home_t *home = ob->ob_home;
  sip_contact_t *rcontact, *dcontact;
  char reg_id_param[20] = "";
  sip_contact_t *previous_previous, *previous_rcontact, *previous_dcontact;
  sip_via_t *v, v0[1], *previous_via;
  int contact_uri_changed;

  if (!via)
    return -1;

  v = v0; *v0 = *via; v0->v_next = NULL;

  dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1,
				   v, v->v_protocol, NULL);

  if (ob->ob_instance && ob->ob_reg_id != 0)
    snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);

  rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0,
				   v, v->v_protocol,
				   ob->ob_instance, reg_id_param, NULL);

  v = sip_via_dup(home, v);

  if (!rcontact || !dcontact || !v) {
    msg_header_free(home, (void *)dcontact);
    if (rcontact != dcontact)
      msg_header_free(home, (void *)rcontact);
    msg_header_free(home, (void *)v);
    return -1;
  }

  contact_uri_changed = !ob->ob_rcontact ||
    url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url);

  if (contact_uri_changed) {
    previous_previous = ob->ob_previous;
    previous_dcontact = ob->ob_dcontact;
    previous_via = ob->ob_via;

    if (ob->ob_registered
        /* && (ob->ob_reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported)
         * XXX - multiple connections not yet supported
	 */)
      previous_rcontact = NULL, ob->ob_previous = ob->ob_rcontact;
    else
      previous_rcontact = ob->ob_rcontact, ob->ob_previous = NULL;

    if (ob->ob_previous)
      msg_header_replace_param(home, (void*)ob->ob_previous, "expires=0");
  }
  else {
    previous_previous = ob->ob_rcontact;
    previous_rcontact = NULL;
    previous_dcontact = ob->ob_dcontact;
    previous_via = ob->ob_via;
  }

  ob->ob_contacts = 1;

  ob->ob_rcontact = rcontact;
  ob->ob_dcontact = dcontact;
  ob->ob_via = v;

  if (contact_uri_changed) {
    ob->ob_registering = 0;
    ob->ob_registered = 0;
    ob->ob_validated = 0;
  }

  msg_header_free(home, (void *)previous_rcontact);
  msg_header_free(home, (void *)previous_previous);
  if (previous_dcontact != ob->ob_previous &&
      previous_dcontact != previous_rcontact &&
      previous_dcontact != previous_previous)
    msg_header_free(home, (void *)previous_dcontact);
  msg_header_free(home, (void *)previous_via);

  return 0;
}
Esempio n. 4
0
/**@ingroup sip_caller_prefs
 *
 * Add a parameter to a @AcceptContact or @RejectContact header object.
 *
 * @note This function does not duplicate @p param.
 *
 * @param home   memory home
 * @param cp     pointer to #sip_accept_contact_t or #sip_reject_contact_t
 * @param param  parameter string
 *
 * @retval 0 when successful
 * @retval -1 upon an error
 *
 * @deprecated Use msg_header_replace_param() instead.
 */
int sip_caller_prefs_add_param(su_home_t *home,
			       sip_caller_prefs_t *cp,
			       char const *param)
{
  return  msg_header_replace_param(home, cp->cp_common, param);
}
Esempio n. 5
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);
}