Example #1
0
/** @internal Create a handle for processing incoming request */
nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
					nta_incoming_t *irq,
					sip_t const *sip,
					int create_dialog)
{
  nua_handle_t *nh;
  url_t const *url;
  sip_to_t to[1];
  sip_from_t from[1];

  assert(sip && sip->sip_from && sip->sip_to);

  if (sip->sip_contact)
    url = sip->sip_contact->m_url;
  else
    url = sip->sip_from->a_url;

  /* Strip away parameters */
  sip_from_init(from)->a_display = sip->sip_to->a_display;
  *from->a_url = *sip->sip_to->a_url;

  sip_to_init(to)->a_display = sip->sip_from->a_display;
  *to->a_url = *sip->sip_from->a_url;

  nh = nh_create(nua,
		 NUTAG_URL((url_string_t *)url), /* Remote target */
		 SIPTAG_TO(to), /* Local AoR */
		 SIPTAG_FROM(from), /* Remote AoR */
		 TAG_END());

  if (nh && nua_stack_init_handle(nua, nh, NULL) < 0)
    nh_destroy(nua, nh), nh = NULL;

  if (nh && create_dialog) {
    struct nua_dialog_state *ds = nh->nh_ds;

    nua_dialog_store_peer_info(nh, ds, sip);

    ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh,
				 SIPTAG_CALL_ID(sip->sip_call_id),
				 SIPTAG_FROM(sip->sip_to),
				 SIPTAG_TO(sip->sip_from),
				 NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq),
				 TAG_END());

    if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL)))
      nh_destroy(nua, nh), nh = NULL;
  }

  if (nh)
    nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);

  return nh;
}
Example #2
0
/**
 * Create a new leg object for incoming request message.
 *
 * @param agent    agent object
 * @param callback function which is called for each 
 *                 incoming request belonging to this leg
 * @param magic    call leg context
 * @param msg      a request message
 *
 * @note The ownership of @a msg will pass back to NTA upon successful call
 * to the function nta_msg_leg(). In other words, if the call to @a
 * nta_msg_leg() is successful, the application may not do anything with @a
 * msg anymore.  Instead of that, NTA will create of a new incoming request
 * object for the @a msg and eventually return the request to application by
 * calling the @a callback function.
 *
 * @deprecated Use nta_leg_stateful() instead.
 */
nta_leg_t *nta_msg_leg(nta_agent_t *agent,
		       msg_t *msg,
		       nta_request_f *callback,
		       nta_leg_magic_t *magic,
		       ...)
{
  nta_leg_t *leg;
  sip_t *sip = sip_object(msg);

  SU_DEBUG_9(("\tnta_msg_leg(): called\n"));

  assert(msg && sip && sip->sip_request);

  if (!msg || !sip || !sip->sip_request || !callback)
    return NULL;

  leg = nta_leg_tcreate(agent, callback, magic,
			SIPTAG_CALL_ID(sip->sip_call_id),
			SIPTAG_FROM(sip->sip_to), /* local address */
			SIPTAG_TO(sip->sip_from), /* remote address */
			TAG_END());
  if (!leg) 
    /* xyzzy */;
  else if (nta_leg_server_route(leg, sip->sip_record_route, 
				sip->sip_contact) < 0)
    nta_leg_destroy(leg), leg = NULL;
  else if (nta_leg_stateful(leg, msg) < 0)
    nta_leg_destroy(leg), leg = NULL;

  SU_DEBUG_9(("\tnta_msg_leg(): returns %p\n", leg));

  return leg;
}
Example #3
0
/**
 * Create a new leg object
 *
 * @param agent    agent object
 * @param callback function which is called for each
 *                 incoming request belonging to this leg
 * @param magic    call leg context
 * @param i        optional @CallID
 *                 (if @c NULL, an ID generated by @b NTA is used)
 * @param from     optional @From (local address)
 * @param to       optional @To (remote address)
 * @param extra    optional extra header
 * @param headers  va_list of optional extra headers
 *
 * @deprecated Use nta_leg_tcreate() instead.
 */
nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,
			   nta_request_f *callback,
			   nta_leg_magic_t *magic,
			   sip_call_id_t const *i,
			   sip_from_t const *from,
			   sip_to_t const *to,
			   void const *extra, va_list headers)
{
  sip_route_t const *route = NULL;
  sip_cseq_t const *cseq = NULL;

  for (; extra ; extra = va_arg(headers, void *)) {
    sip_header_t const *h = (sip_header_t const *)extra;

    if (h == SIP_NONE)
      continue;
    else if (sip_call_id_p(h)) {
      if (i == NULL) i = h->sh_call_id;
    }
    else if (sip_from_p(h)) {
      if (from == NULL) from = h->sh_from;
    }
    else if (sip_to_p(h)) {
      if (to == NULL) to = h->sh_to;
    }
    else if (sip_route_p(h)) {
      route = h->sh_route;
    }
    else if (sip_cseq_p(h)) {
      cseq = h->sh_cseq;
    }
    else {
      SU_DEBUG_3(("nta_leg_create: extra header %s\n", 
		  sip_header_name(h, 0)));
    }
  }

  return nta_leg_tcreate(agent, callback, magic,
			 NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id),
			 TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)),
			 TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)),
			 TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)),
			 SIPTAG_ROUTE(route),
			 SIPTAG_CSEQ(cseq),
			 TAG_END());
}
Example #4
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);
}
Example #5
0
/** @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;
}
Example #6
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;
}
    int DrachtioController::processRequestOutsideDialog( nta_leg_t* defaultLeg, nta_incoming_t* irq, sip_t const *sip) {
        DR_LOG(log_debug) << "processRequestOutsideDialog" << endl ;
        int rc = validateSipMessage( sip ) ;
        if( 0 != rc ) {
            return rc ;
        }

        switch (sip->sip_request->rq_method ) {
            case sip_method_invite:
            {
                /* TODO:  should support optional config to only allow invites from defined addresses */

                /* system-wide minimum session-expires is 90 seconds */
                if( sip->sip_session_expires && sip->sip_session_expires->x_delta < 90 ) {
                      nta_incoming_treply( irq, SIP_422_SESSION_TIMER_TOO_SMALL, 
                        SIPTAG_MIN_SE_STR("90"),
                        TAG_END() ) ; 
                      return 0;
                } 

                string transactionId ;
                generateUuid( transactionId ) ;

                nta_incoming_treply( irq, SIP_100_TRYING, TAG_END() ) ;                
 
                 if( !m_pClientController->route_request_outside_dialog( irq, sip, transactionId ) )  {
                    DR_LOG(log_error) << "No providers available for invite" << endl ;
                    return 503 ;
                }

                nta_leg_t* leg = nta_leg_tcreate(m_nta, legCallback, this,
                                                   SIPTAG_CALL_ID(sip->sip_call_id),
                                                   SIPTAG_CSEQ(sip->sip_cseq),
                                                   SIPTAG_TO(sip->sip_from),
                                                   SIPTAG_FROM(sip->sip_to),
                                                   TAG_END());
                if( NULL == leg ) {
                    DR_LOG(log_error) << "Error creating a leg for  origination" << endl ;
                    //TODO: we got a client out there with a dead INVITE now...
                    return 500 ;
                }
                boost::shared_ptr<SipDialog> dlg = boost::make_shared<SipDialog>( leg, irq, sip ) ;
                dlg->setTransactionId( transactionId ) ;

                string contactStr ;
                generateOutgoingContact( sip->sip_contact, contactStr ) ;
                nta_leg_server_route( leg, sip->sip_record_route, sip->sip_contact ) ;

                m_pDialogController->addIncomingInviteTransaction( leg, irq, sip, transactionId, dlg ) ;


            }
            break ;

            case sip_method_ack:

                /* success case: call has been established */
                nta_incoming_destroy( irq ) ;
                return 0 ;               
            case sip_method_register:
            case sip_method_message:
            case sip_method_options:
            case sip_method_notify:
            {
                string transactionId ;
                generateUuid( transactionId ) ;

                if( !m_pClientController->route_request_outside_dialog( irq, sip, transactionId ) )  {
                    DR_LOG(log_error) << "No providers available for register" << endl ;
                    return 503 ;
                }

                m_pDialogController->addIncomingRequestTransaction( irq, transactionId ) ;
                return 0 ;
            }
            
            case sip_method_bye:
            case sip_method_cancel:
                DR_LOG(log_error) << "Received BYE or CANCEL for unknown dialog: " << sip->sip_call_id->i_id << endl ;
                return 481 ;
                
            default:
                DR_LOG(log_error) << "DrachtioController::processRequestOutsideDialog - unsupported method type: " << sip->sip_request->rq_method_name << ": " << sip->sip_call_id->i_id << endl ;
                return 501 ;
                break ;
                
        }
        
        return 0 ;
    }