コード例 #1
0
ファイル: outbound.c プロジェクト: FreeMCU/freemcu
/** Process response to REGISTER request */
int outbound_register_response(outbound_t *ob,
			       int terminating,
			       sip_t const *request,
			       sip_t const *response)
{
  int status, reregister;

  if (!ob)
    return 0;

  if (terminating) {
    ob->ob_registering = ob->ob_registered = 0;
    return 0;			/* Cleanup is done separately */
  }

  if (!response || !request)
    return 0;

  assert(request->sip_request); assert(response->sip_status);

  status = response->sip_status->st_status;

  if (status < 300) {
    if (request->sip_contact && response->sip_contact) {
      sip_contact_t *m;

      if (ob->ob_rcontact != NULL) {
        msg_header_free(ob->ob_home, (msg_header_t *)ob->ob_rcontact);
        ob->ob_rcontact = NULL;
      }

      /* Ignore the contacts that were unregistered, if any */
      for (m = request->sip_contact; m; m = m->m_next) {
        if (!m->m_expires || strtoul(m->m_expires, NULL, 10) != 0)
          break;
      }
      assert (!ob->ob_registering || m != NULL);

      if (m)
        ob->ob_rcontact = (sip_contact_t *)
	  msg_header_dup_one(ob->ob_home, (const msg_header_t *)m);

      ob->ob_registered = ob->ob_registering;
    } else
      ob->ob_registered = 0;
  }

  reregister = outbound_check_for_nat(ob, request, response);
  if (reregister)
    return reregister;

  if (ob->ob_previous && status < 300) {
    msg_header_free(ob->ob_home, (void *)ob->ob_previous);
    ob->ob_previous = NULL;
  }

  return 0;
}
コード例 #2
0
static int nua_refer_server_preprocess(nua_server_request_t *sr)
{
  nua_handle_t *nh = sr->sr_owner;
  sip_t const *sip = sr->sr_request.sip;
  struct notifier_usage *nu;
  sip_event_t *o;

  if (nh->nh_ds->ds_got_referrals || NH_PGET(nh, refer_with_id))
    o = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq);
  else
    o = sip_event_make(nh->nh_home, "refer");

  if (o) {
    sr->sr_usage = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o);
    msg_header_free(nh->nh_home, (msg_header_t *)o);
  }

  if (!sr->sr_usage)
    return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);

  nu = nua_dialog_usage_private(sr->sr_usage);
  nu->nu_requested = sip_now() + NH_PGET(nh, refer_expires);

  return 0;
}
コード例 #3
0
int
s2_save_register(struct message *rm)
{
  sip_contact_t *contact, *m, **m_prev;
  sip_expires_t const *ex;
  sip_date_t const *date;
  sip_time_t now = rm->when.tv_sec, expires;

  msg_header_free_all(s2->home, (msg_header_t *)s2->registration->aor);
  msg_header_free_all(s2->home, (msg_header_t *)s2->registration->contact);
  tport_unref(s2->registration->tport);

  s2->registration->aor = NULL;
  s2->registration->contact = NULL;
  s2->registration->tport = NULL;

  if (rm == NULL)
    return 0;

  assert(rm && rm->sip && rm->sip->sip_request);
  assert(rm->sip->sip_request->rq_method == sip_method_register);

  ex = rm->sip->sip_expires;
  date = rm->sip->sip_date;

  contact = sip_contact_dup(s2->home, rm->sip->sip_contact);

  for (m_prev = &contact; *m_prev;) {
    m = *m_prev;

    expires = sip_contact_expires(m, ex, date,
				  s2_default_registration_duration,
				  now);
    if (expires) {
      char *p = su_sprintf(s2->home, "expires=%lu", (unsigned long)expires);
      msg_header_add_param(s2->home, m->m_common, p);
      m_prev = &m->m_next;
    }
    else {
      *m_prev = m->m_next;
      m->m_next = NULL;
      msg_header_free(s2->home, (msg_header_t *)m);
    }
  }

  if (contact == NULL)
    return 0;

  s2->registration->aor = sip_to_dup(s2->home, rm->sip->sip_to);
  s2->registration->contact = contact;
  s2->registration->tport = tport_ref(rm->tport);

  s2sip->sut.aor = s2->registration->aor;
  s2sip->sut.contact = s2->registration->contact;
  s2sip->sut.tport = s2->registration->tport;

  return 0;
}
コード例 #4
0
ファイル: nua_dialog.c プロジェクト: SteveAyre/mod_handsfree
/** Remove dialog information. */
int nua_dialog_zap(nua_owner_t *own,
		   nua_dialog_state_t *ds)
{
  /* zap peer info */
  nua_dialog_store_peer_info(own, ds, NULL);
  /* Local Contact */
  msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL;
  /* Leg */
  nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
  /* Remote tag */
  su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
  /* Ready to set route/remote target */
  ds->ds_route = 0;

  return 0;
}
コード例 #5
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;
}
コード例 #6
0
ファイル: outbound.c プロジェクト: FreeMCU/freemcu
/** Convert "gruu" parameter returned by registrar to Contact header. */
int outbound_gruuize(outbound_t *ob, sip_t const *sip)
{
  sip_contact_t *m = NULL;
  char *gruu;

  if (!ob)
    return 0;

  if (ob->ob_rcontact == NULL)
    return -1;

  if (!ob->ob_prefs.gruuize && ob->ob_instance) {
    char const *my_instance, *my_reg_id = NULL;
    char const *instance, *reg_id;

    m = ob->ob_rcontact;
    my_instance = msg_header_find_param(m->m_common, "+sip.instance=");
    if (my_instance)
      my_reg_id = msg_header_find_param(m->m_common, "reg-id=");

    for (m = sip->sip_contact; m; m = m->m_next) {
      if (my_instance) {
	instance = msg_header_find_param(m->m_common, "+sip.instance=");
	if (!instance || strcmp(instance, my_instance))
	  continue;
	if (my_reg_id) {
	  reg_id = msg_header_find_param(m->m_common, "reg-id=");
	  if (!reg_id || strcmp(reg_id, my_reg_id))
	    continue;
	}
      }

      if (url_cmp_all(ob->ob_rcontact->m_url, m->m_url) == 0)
	break;
    }
  }

  if (m == NULL) {
    if (ob->ob_gruu)
      msg_header_free(ob->ob_home, (void *)ob->ob_gruu), ob->ob_gruu = NULL;
    return 0;
  }

  gruu = (char *)msg_header_find_param(m->m_common, "pub-gruu=");

  if (gruu == NULL || gruu[0] == '\0')
    gruu = (char *)msg_header_find_param(m->m_common, "gruu=");

  if (gruu == NULL || gruu[0] == '\0')
    return 0;

  gruu = msg_unquote_dup(NULL, gruu);
  m = gruu ? sip_contact_format(ob->ob_home, "<%s>", gruu) : NULL;
  su_free(NULL, gruu);

  if (!m)
    return -1;

  if (ob->ob_gruu)
    msg_header_free(ob->ob_home, (void *)ob->ob_gruu);
  ob->ob_gruu = m;

  return 0;
}
コード例 #7
0
ファイル: outbound.c プロジェクト: FreeMCU/freemcu
/**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;
}
コード例 #8
0
ファイル: outbound.c プロジェクト: FreeMCU/freemcu
/**@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;
}
コード例 #9
0
ファイル: nua_client.c プロジェクト: Deepwalker/FreeSWITCH
/**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;
}