Ejemplo n.º 1
0
/** Check that we allow the request method.
 *
 * The request-method is compared with the list of supported methods in @a
 * allow. If match is found, 0 is is returned. Otherwise, if the
 * request-method is well-known, 405 is returned. If the request-method is
 * unknown, 501 is returned. If @a irq is non-NULL, the 405 or 501 response
 * message is sent to the client, too.
 *
 * @param irq 	incoming transaction object (may be NULL).
 * @param sip 	contents of the SIP message
 * @param allow   list of allowed methods
 * @param tag, value, ...   optional list of tagged arguments used
 *                          when responding to the transaction
 *
 * @return 0 if successful, 405 is request-method is not allowed, 501 if
 * request-method is unknown.
 */
int nta_check_method(nta_incoming_t *irq,
		     sip_t const *sip,
		     sip_allow_t const *allow,
		     tag_type_t tag, tag_value_t value, ...)
{
  /* Check extensions */
  sip_method_t method = sip->sip_request->rq_method;
  char const *name = sip->sip_request->rq_method_name;

  if (sip_is_allowed(allow, method, name))
    return 0;

  if (irq) {
    ta_list ta;
    ta_start(ta, tag, value);

    if (method != sip_method_unknown)
      /* Well-known method */
      nta_incoming_treply(irq,
			  SIP_405_METHOD_NOT_ALLOWED,
			  SIPTAG_ALLOW(allow),
			  ta_tags(ta));
    else
      /* Completeley unknown method */
      nta_incoming_treply(irq,
			  SIP_501_NOT_IMPLEMENTED,
			  SIPTAG_ALLOW(allow),
			  ta_tags(ta));
    ta_end(ta);
  }

  return method != sip_method_unknown ? 405 : 501;
}
Ejemplo n.º 2
0
/**Create an authentication plugin module.
 *
 * The function auth_mod_create() creates a module used to authenticate the
 * requests.
 *
 * @param root pointer to a su_root_t object
 * @param tag,value,... tagged argument list
 *
 * @TAGS
 * AUTHTAG_METHOD(), AUTHTAG_REALM(), AUTHTAG_DB(), AUTHTAG_ALLOW(),
 * AUTHTAG_QOP(), AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(),
 * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
 * AUTHTAG_REMOTE().
 */
auth_mod_t *auth_mod_create(su_root_t *root,
			    tag_type_t tag, tag_value_t value, ...)
{
  auth_mod_t *am = NULL;

  ta_list ta;

  char const *method = NULL;

  ta_start(ta, tag, value);

  tl_gets(ta_args(ta),
	  AUTHTAG_METHOD_REF(method),
	  TAG_NULL());

  if (method) {
    auth_scheme_t *bscheme = NULL;
    char const *base;
    size_t len;

    base = strrchr(method, '+');
    if (base)
      len = base++ - method;
    else
      len = strlen(method);

    if (base == NULL)
      ;
    else if (su_casematch(base, "Basic"))
      bscheme = auth_scheme_basic;
    else if (su_casematch(base, "Digest"))
      bscheme = auth_scheme_digest;

    if (base == NULL || bscheme) {
      int i;

      for (i = 0; schemes[i] && i < N; i++) {
	if (su_casenmatch(schemes[i]->asch_method, method, len) &&
	    schemes[i]->asch_method[len] == 0) {
	  am = auth_mod_alloc(schemes[i], ta_tags(ta));
	  if (schemes[i]->asch_init(am, bscheme, root, ta_tags(ta)) == -1) {
	    auth_mod_destroy(am), am = NULL;
	  }
	  break;
	}
      }
    }
  }

  ta_end(ta);

  return am;
}
Ejemplo n.º 3
0
static struct event *
subscription_by_nua(nua_handle_t *nh,
                    enum nua_substate current,
                    tag_type_t tag, tag_value_t value, ...)
{
    struct message *subscribe;
    struct event *notify, *event;
    ta_list ta;
    enum nua_substate substate = nua_substate_active;
    char const *substate_str = subscription_state;
    char const *expires = "600";

    subscribe = s2_sip_wait_for_request(SIP_METHOD_SUBSCRIBE);
    if (event_type)
        fail_if(!subscribe->sip->sip_event ||
                strcmp(event_type, subscribe->sip->sip_event->o_type));

    if (subscribe->sip->sip_expires && subscribe->sip->sip_expires->ex_delta == 0) {
        substate = nua_substate_terminated;
        substate_str = "terminated;reason=timeout";
        expires = "0";
    }

    ta_start(ta, tag, value);

    if (send_notify_before_response) {
        s2_sip_save_uas_dialog(dialog, subscribe->sip);
        notify = notify_to_nua(substate,
                               SIPTAG_EVENT(subscribe->sip->sip_event),
                               SIPTAG_SUBSCRIPTION_STATE_STR(substate_str),
                               ta_tags(ta));
        event = respond_to_subscribe(subscribe, nua_r_subscribe, substate,
                                     SIP_200_OK,
                                     SIPTAG_EXPIRES_STR(expires),
                                     TAG_END());
        s2_free_event(event);
    }
    else {
        event = respond_to_subscribe(subscribe, nua_r_subscribe, current,
                                     SIP_202_ACCEPTED,
                                     SIPTAG_EXPIRES_STR(expires),
                                     TAG_END());
        s2_free_event(event);
        notify = notify_to_nua(substate,
                               SIPTAG_EVENT(subscribe->sip->sip_event),
                               SIPTAG_SUBSCRIPTION_STATE_STR(substate_str),
                               ta_tags(ta));
    }

    s2_sip_free_message(subscribe);

    return notify;
}
Ejemplo n.º 4
0
nua_handle_t *
subscribe_to_nua(char const *event,
                 tag_type_t tag, tag_value_t value, ...)
{
    ta_list ta;
    struct event *subscribe;
    struct message *response;
    nua_handle_t *nh;

    nua_set_params(nua, NUTAG_APPL_METHOD("SUBSCRIBE"),
                   SIPTAG_ALLOW_EVENTS_STR(event),
                   TAG_END());
    fail_unless_event(nua_r_set_params, 200);

    ta_start(ta, tag, value);
    s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL,
                      SIPTAG_EVENT_STR(event),
                      ta_tags(ta));
    ta_end(ta);

    subscribe = s2_wait_for_event(nua_i_subscribe, 100);
    nh = subscribe->nh;
    nua_respond(nh, SIP_202_ACCEPTED,
                NUTAG_WITH_SAVED(subscribe->event),
                TAG_END());
    s2_free_event(subscribe);

    response = s2_sip_wait_for_response(202, SIP_METHOD_SUBSCRIBE);
    s2_sip_update_dialog(dialog, response);
    fail_unless(response->sip->sip_expires != NULL);
    s2_sip_free_message(response);

    return nh;
}
Ejemplo n.º 5
0
/**Check that we support all features which UAC requires.
 *
 * The list of supported features is compared with the list of features
 * required by the UAC. If some features are not listed as supported, return
 * 420. If @a irq is non-NULL, the 420 response message is sent to the
 * client along with list of unsupported features in the @Unsupported
 * header, too.
 *
 * @param   irq incoming transaction object (may be NULL).
 * @param   sip contents of the SIP message
 * @param supported   list of protocol features supported
 * @param tag, value, ... optional list of tagged arguments used
 *                        when responding to the transaction
 *
 * @return 0 if successful.
 * 420 if any of the required features is not supported.
 */
int nta_check_required(nta_incoming_t *irq,
		       sip_t const *sip,
		       sip_supported_t const *supported,
		       tag_type_t tag, tag_value_t value, ...)
{
  int status = 0;

  if (sip->sip_require) {
    su_home_t home[SU_HOME_AUTO_SIZE(512)];
    sip_unsupported_t *us;

    su_home_auto(home, sizeof home);

    us = sip_has_unsupported(home, supported, sip->sip_require);

    if (us) {
      status = 420;
      if (irq) {
	ta_list ta;
	ta_start(ta, tag, value);
	nta_incoming_treply(irq,
			    SIP_420_BAD_EXTENSION,
			    SIPTAG_UNSUPPORTED(us),
			    SIPTAG_SUPPORTED(supported),
			    ta_tags(ta));
	ta_end(ta);
      }
    }

    su_home_deinit(home);
  }

  return status;
}
Ejemplo n.º 6
0
/**Check @SessionExpires header.
 *
 * If the proposed session-expiration time is smaller than @MinSE or our
 * minimal session expiration time, respond with 422 containing shortest
 * acceptable session expiration time in @MinSE header.
 *
 * @param irq 	incoming transaction object (may be NULL).
 * @param sip 	contents of the SIP message
 * @param my_min_se   minimal session expiration time in seconds
 * @param tag, value, ...   optional list of tagged arguments used
 *                          when responding to the transaction
 *
 * @return 422 if session expiration time is too small, 0 when successful.
 */
int nta_check_session_expires(nta_incoming_t *irq,
			      sip_t const *sip,
			      sip_time_t my_min_se,
			      tag_type_t tag, tag_value_t value, ...)
{
  unsigned long min_se = my_min_se;

  if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
    min_se = sip->sip_min_se->min_delta;

  if (sip->sip_session_expires->x_delta >= min_se)
    return 0;

  if (irq) {
    ta_list ta;
    sip_min_se_t min_se0[1];

    ta_start(ta, tag, value);

    sip_min_se_init(min_se0)->min_delta = min_se;

    nta_incoming_treply(irq,
			SIP_422_SESSION_TIMER_TOO_SMALL,
			SIPTAG_MIN_SE(min_se0),
			ta_tags(ta));
    ta_end(ta);
  }

  return 422;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
/**Forward a request.
 *
 * @deprecated
 * Use nta_outgoing_mcreate() instead.
 */
nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent,
				    nta_response_f *callback,
				    nta_outgoing_magic_t *magic,
				    url_string_t const *route_url,
				    msg_t *parent,
				    tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  msg_t *msg;
  nta_outgoing_t *orq = NULL;

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

  ta_start(ta, tag, value);

  msg_clone(msg, parent);

  if (parent && sip_copy_all(msg, sip_object(msg), sip_object(parent)) < 0)
    ;
  else if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) < 0)
    ;
  else
    orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); 

  ta_end(ta);

  if (!orq)
    msg_destroy(msg);

  return orq;
  
}
Ejemplo n.º 9
0
static struct event *
notify_to_nua(enum nua_substate expect_substate,
              tag_type_t tag, tag_value_t value, ...)
{
    struct event *event;
    struct message *response;
    ta_list ta;
    int status;

    ta_start(ta, tag, value);
    fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
                              SIPTAG_CONTENT_TYPE_STR(event_mime_type),
                              SIPTAG_PAYLOAD_STR(event_state),
                              ta_tags(ta)));
    ta_end(ta);

    response = s2_sip_wait_for_response(0, SIP_METHOD_NOTIFY);
    fail_if(!response);
    status = response->sip->sip_status->st_status;
    fail_unless(status == 200);
    s2_sip_free_message(response);

    event = s2_wait_for_event(nua_i_notify, 200);
    fail_if(!event);
    fail_unless(s2_check_substate(event, expect_substate));

    return event;
}
Ejemplo n.º 10
0
/** Check that we understand session content in the request.
 *
 * If there is no @ContentDisposition header or the @ContentDisposition
 * header indicated "session", the message body and content-type is compared
 * with the acceptable session content-types listed in @a session_accepts.
 * (typically, @c "application/sdp"). If no match is found, a 415 is
 * returned. If @a irq is non-NULL, the 415 response message is sent to the
 * client, too.
 *
 * If the @ContentDisposition header indicates something else but "session",
 * and it does not contain "handling=optional" parameter, a 415 response is
 * returned, too.
 *
 * Also, the @ContentEncoding header is checked. If it is not empty
 * (indicating no content-encoding), a 415 response is returned, too.
 *
 * @param irq 	incoming (server) transaction object (may be NULL).
 * @param sip 	contents of the SIP message
 * @param session_accepts   list of acceptable content-types for "session"
 *                          content disposition
 * @param tag, value, ...   optional list of tagged arguments used
 *                          when responding to the transaction
 *
 * @return 0 if successful, 415 if content-type is not acceptable.
 */
int nta_check_session_content(nta_incoming_t *irq,
			      sip_t const *sip,
			      sip_accept_t const *session_accepts,
			      tag_type_t tag, tag_value_t value, ...)
{
  sip_content_type_t const *c = sip->sip_content_type;
  sip_content_disposition_t const *cd = sip->sip_content_disposition;
  int acceptable_type = 0, acceptable_encoding = 0;

  if (sip->sip_payload == NULL)
    return 0;

  if (cd == NULL || su_casematch(cd->cd_type, "session")) {
    sip_accept_t const *ab = session_accepts;
    char const *c_type;

    if (c)
      c_type = c->c_type;
    else if (sip->sip_payload->pl_len > 3 &&
	     su_casenmatch(sip->sip_payload->pl_data, "v=0", 3))
      /* Missing Content-Type, but it looks like SDP  */
      c_type = application_sdp;
    else
      /* No chance */
      ab = NULL, c_type = NULL;

    for (; ab; ab = ab->ac_next) {
      if (su_casematch(c_type, ab->ac_type))
	break;
    }

    if (ab)
      acceptable_type = 1;
  }
  else if (cd->cd_optional)
    acceptable_type = 1;

  /* Empty or missing Content-Encoding */
  if (!sip->sip_content_encoding ||
      !sip->sip_content_encoding->k_items ||
      !sip->sip_content_encoding->k_items[0] ||
      !sip->sip_content_encoding->k_items[0][0])
    acceptable_encoding = 1;

  if (acceptable_type && acceptable_encoding)
    return 0;

  if (irq) {
    ta_list ta;
    ta_start(ta, tag, value);
    nta_incoming_treply(irq,
			SIP_415_UNSUPPORTED_MEDIA,
			SIPTAG_ACCEPT(session_accepts),
			ta_tags(ta));
    ta_end(ta);
  }

  return 415;
}
Ejemplo n.º 11
0
/** @internal
 * Post signal to stack itself
 */
void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
			   tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  ta_start(ta, tag, value);
  nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));
  ta_end(ta);
}
Ejemplo n.º 12
0
/**Check that UAC accepts one of listed MIME content-types.
 *
 * The list of acceptable content-types are compared with the acceptable
 * content-types. If match is found, it is returned in @a return_acceptable.
 * If no match is found, a 406 is returned. If @a irq is non-NULL, the 406
 * response message is sent to the client, too.
 *
 * @param irq incoming transaction object (may be NULL).
 * @param sip contents of the SIP message
 * @param acceptable list of acceptable content types
 * @param return_acceptable optional return-value parameter for
 *                          matched content-type
 * @param tag, value, ... optional list of tagged arguments used
 *                        when responding to the transaction
 *
 * @return 406 if no content-type is acceptable by client, 0 if successful.
 */
int nta_check_accept(nta_incoming_t *irq,
		     sip_t const *sip,
		     sip_accept_t const *acceptable,
		     sip_accept_t const **return_acceptable,
		     tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  sip_accept_t const *ac, *ab;
  sip_method_t method;

  if (!acceptable)
    return 0;

  if (sip->sip_request)
    method = sip->sip_request->rq_method;
  else /* if (sip->sip_cseq) */
    method = sip->sip_cseq->cs_method;

  /* Missing Accept header implies support for SDP in INVITE and OPTIONS
   * (and PRACK and UPDATE?)
   */
  if (!sip->sip_accept && (method == sip_method_invite ||
			   method == sip_method_options ||
			   method == sip_method_prack ||
			   method == sip_method_update)) {
    for (ab = acceptable; ab; ab = ab->ac_next)
      if (su_casematch(application_sdp, ab->ac_type)) {
	if (return_acceptable) *return_acceptable = ab;
	return 0;
      }
  }

  for (ac = sip->sip_accept; ac; ac = ac->ac_next) {
    if (sip_q_value(ac->ac_q) == 0 || !ac->ac_type)
      continue;

    for (ab = acceptable; ab; ab = ab->ac_next)
      if (su_casematch(ac->ac_type, ab->ac_type)) {
	if (return_acceptable) *return_acceptable = ab;
	return 0;
      }
  }

  if (irq) {
    ta_start(ta, tag, value);
    nta_incoming_treply(irq,
			SIP_406_NOT_ACCEPTABLE,
			SIPTAG_ACCEPT(acceptable),
			ta_tags(ta));
    ta_end(ta);
  }

  return 406;
}
Ejemplo n.º 13
0
END_TEST


static nua_handle_t *make_auth_natted_register(
    nua_handle_t *nh,
    tag_type_t tag, tag_value_t value, ...)
{
    struct message *m;

    ta_list ta;
    ta_start(ta, tag, value);
    nua_register(nh, ta_tags(ta));
    ta_end(ta);

    m = s2_sip_wait_for_request(SIP_METHOD_REGISTER);
    fail_if(!m);
    s2_sip_respond_to(m, NULL,
                      SIP_401_UNAUTHORIZED,
                      SIPTAG_WWW_AUTHENTICATE_STR(s2_auth_digest_str),
                      SIPTAG_VIA(natted_via(m, receive_natted)),
                      TAG_END());
    s2_sip_free_message(m);

    fail_unless_event(nua_r_register, 401);

    /* NAT detected event */
    fail_unless_event(nua_i_outbound, 101);

    nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END());

    m = s2_sip_wait_for_request(SIP_METHOD_REGISTER);
    fail_if(!m);
    fail_if(!m->sip->sip_authorization);
    /* should not unregister the previous contact
     * as it has not been successfully registered */
    fail_if(!m->sip->sip_contact);
    fail_if(m->sip->sip_contact->m_next);
    s2_save_register(m);

    s2_sip_respond_to(m, NULL,
                      SIP_200_OK,
                      SIPTAG_CONTACT(s2->registration->contact),
                      SIPTAG_VIA(natted_via(m, receive_natted)),
                      TAG_END());
    s2_sip_free_message(m);

    assert(s2->registration->contact != NULL);
    fail_unless_event(nua_r_register, 200);

    return nh;
}
Ejemplo n.º 14
0
static struct message *
invite_sent_by_nua(nua_handle_t *nh,
                   tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  ta_start(ta, tag, value);
  nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
             ta_tags(ta));
  ta_end(ta);

  fail_unless(s2_check_callstate(nua_callstate_calling));

  return s2_sip_wait_for_request(SIP_METHOD_INVITE);
}
Ejemplo n.º 15
0
static void
bye_by_nua(struct dialog *dialog, nua_handle_t *nh,
	   tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  struct message *bye;

  ta_start(ta, tag, value);
  nua_bye(nh, ta_tags(ta));
  ta_end(ta);

  bye = s2_sip_wait_for_request(SIP_METHOD_BYE);
  fail_if(!bye);
  s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END());
  s2_sip_free_message(bye);
  fail_unless_event(nua_r_bye, 200);
  fail_unless(s2_check_callstate(nua_callstate_terminated));
}
Ejemplo n.º 16
0
nua_t *s2_nua_setup(char const *label,
		    tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;

  s2_setup(label);

  s2 = su_home_new(sizeof *s2);

  s2_dns_setup(s2base->root);

  s2_setup_logs(0);
  s2_sip_setup("example.org", NULL, TAG_END());
  assert(s2sip->contact);

  s2_dns_domain("example.org", 1,
		"s2", 1, s2sip->udp.contact->m_url,
		"s2", 1, s2sip->tcp.contact->m_url,
		NULL);

  /* enable/disable multithreading */
  su_root_threading(s2base->root, s2_nua_thread);

  ta_start(ta, tag, value);
  s2->nua =
    nua_create(s2base->root,
	       s2_nua_callback,
	       s2,
	       SIPTAG_FROM_STR("Alice <sip:[email protected]>"),
	       /* NUTAG_PROXY((url_string_t *)s2sip->contact->m_url), */
	       /* Use internal DNS server */
	       NUTAG_PROXY("sip:example.org"),
	       /* Force sresolv to use localhost and s2dns as DNS server */
#if HAVE_WIN32
	       SRESTAG_RESOLV_CONF("NUL"),
#else
	       SRESTAG_RESOLV_CONF("/dev/null"),
#endif
	       ta_tags(ta));
  ta_end(ta);

  return s2->nua;
}
Ejemplo n.º 17
0
/** Check that UAC supports all the required features.
 *
 * The list of required features is compared with the features supported by
 * the UAC. If some features are not supported, return 421. If @a irq is
 * non-NULL, the 421 response message is sent to the client, too.
 *
 * @param irq incoming transaction object (may be NULL).
 * @param sip contents of the SIP message
 * @param require   list of required protocol features
 * @param tag, value, ... optional list of tagged arguments used
 *                        when responding to the transaction
 *
 * @return 0 if successful.
 * 421 if any of the required features is not supported.
 */
int nta_check_supported(nta_incoming_t *irq,
			sip_t const *sip,
			sip_require_t *require,
			tag_type_t tag, tag_value_t value, ...)
{
  if (!sip_has_unsupported(NULL, sip->sip_supported, require))
    return 0;

  if (irq) {
    ta_list ta;
    ta_start(ta, tag, value);
    nta_incoming_treply(irq,
			SIP_421_EXTENSION_REQUIRED,
			SIPTAG_REQUIRE(require),
			ta_tags(ta));
    ta_end(ta);
  }

  return 421;
}
Ejemplo n.º 18
0
static struct event *
respond_to_subscribe(struct message *subscribe,
                     nua_event_t expect_event,
                     enum nua_substate expect_substate,
                     int status, char const *phrase,
                     tag_type_t tag, tag_value_t value, ...)
{
    struct event *event;
    ta_list ta;

    ta_start(ta, tag, value);
    s2_sip_respond_to(subscribe, dialog, status, phrase,
                      ta_tags(ta));
    ta_end(ta);

    event = s2_wait_for_event(expect_event, status);
    fail_if(!event);
    fail_unless(s2_check_substate(event, expect_substate));
    return event;
}
Ejemplo n.º 19
0
static void
respond_with_sdp(struct message *request,
		 struct dialog *dialog,
		 int status, char const *phrase,
		 tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;

  char const *body;
  isize_t bodylen;

  fail_if(soa_get_local_sdp(soa, NULL, &body, &bodylen) != 1);

  ta_start(ta, tag, value);
  s2_sip_respond_to(request, dialog, status, phrase,
		SIPTAG_CONTENT_TYPE_STR("application/sdp"),
		SIPTAG_PAYLOAD_STR(body),
		SIPTAG_CONTENT_DISPOSITION_STR("session"),
		ta_tags(ta));
  ta_end(ta);
}
static int delayed_auth_init(auth_mod_t *am,
			     auth_scheme_t *base,
			     su_root_t *root,
			     tag_type_t tag, tag_value_t value, ...)
{
  auth_plugin_t *ap = AUTH_PLUGIN(am);
  int retval = -1;
  ta_list ta;

  ta_start(ta, tag, value);

  if (root && base && auth_init_default(am, base, root, ta_tags(ta)) != -1) {
    ap->ap_root = root;
    ap->ap_base = base;
    ap->ap_tail = &ap->ap_list;

    retval = 0;
  }

  ta_end(ta);

  return retval;
}
Ejemplo n.º 21
0
/** @internal Shutdown notifier object */
int nh_notifier_shutdown(nua_handle_t *nh,
			 nea_event_t *ev,
			 tag_type_t t,
			 tag_value_t v, ...)
{
  nea_server_t *nes = nh->nh_notifier;
  nea_subnode_t const **subs;
  int busy = 0;

  if (nes == NULL)
    return 0;

  subs = nea_server_get_subscribers(nes, ev);

  if (subs) {
    int i;
    ta_list ta;

    ta_start(ta, t, v);

    for (i = 0; subs[i]; i++)
      nea_sub_auth(subs[i]->sn_subscriber, nea_terminated, ta_tags(ta));

    ta_end(ta);

    busy++;
  }

  nea_server_free_subscribers(nes, subs);

  nea_server_flush(nh->nh_notifier, NULL);

  if (ev == NULL)
    nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL;

  return busy;
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 23
0
/** Create a http site object.
 *
 * The function nth_site_create() allocates and initializes a web site
 * object. A web site object can be either
 * - a primary http server (@a parent is NULL),
 * - a virtual http server (@a address contains hostpart), or
 * - a site within a server
 *   (@a address does not have hostpart, only path part).
 *
 * @param parent pointer to parent site
 *               (NULL when creating a primary server object)
 * @param callback pointer to callback function called when
 *                 a request is received
 * @param magic    application context included in callback parameters
 * @param address  absolute or relative URI specifying the address of
 *                 site
 * @param tag, value, ... list of tagged parameters
 *
 * @TAGS
 * If the @a parent is NULL, the list of tagged parameters must contain
 * NTHTAG_ROOT() used to create the server engine. Tags supported when @a
 * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(),
 * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to
 * tport_tcreate() and tport_tbind(), too.
 *
 * @since Support for multiple sites was added to @VERSION_1_12_4
 */
nth_site_t *nth_site_create(nth_site_t *parent,
			    nth_request_f *callback,
			    nth_site_magic_t *magic,
			    url_string_t const *address,
			    tag_type_t tag, tag_value_t value,
			    ...)
{
  nth_site_t *site = NULL, **prev = NULL;
  su_home_t home[SU_HOME_AUTO_SIZE(256)];
  url_t *url, url0[1];
  server_t *srv = NULL;
  ta_list ta;
  char *path = NULL;
  size_t usize;
  int is_host, is_path, wildcard = 0;

  su_home_auto(home, sizeof home);

  if (parent && url_is_string(address)) {
    char const *s = (char const *)address;
    size_t sep = strcspn(s, "/:");

    if (parent->site_path) {
      /* subpath */
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_path = s;
      address = (url_string_t*)url0;
    }
    else if (s[sep] == ':')
      /* absolute URL with scheme */;
    else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) {
      /* looks like a domain name */;
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_host = s;
      address = (url_string_t*)url0;
    }
    else {
      /* looks like a path */
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_path = s;
      address = (url_string_t*)url0;
    }
  }

  url = url_hdup(home, address->us_url);

  if (!url || !callback)
    return NULL;

  is_host = url->url_host != NULL;
  is_path = url->url_path != NULL;

  if (is_host && is_path) {
    SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n"));
    errno = EINVAL;
    goto error;
  }

  if (!parent && !is_host) {
    SU_DEBUG_3(("nth_site_create(): host is required\n"));
    errno = EINVAL;
    goto error;
  }

  if (parent) {
    if (!parent->site_isdir) {
      SU_DEBUG_3(("nth_site_create(): invalid parent resource \n"));
      errno = EINVAL;
      goto error;
    }

    srv = parent->site_server; assert(srv);
    if (is_host) {
      prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port);

      if (prev == NULL) {
	SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n",
		    url->url_host, url->url_port ? url->url_port : ""));
	errno = EEXIST;
	goto error;
      }
    }
    else {
      size_t i, j;

      path = (char *)url->url_path;
      while (path[0] == '/')
	path++;

      /* Remove duplicate // */
      for (i = j = 0; path[i];) {
	while (path[i] == '/' && path[i + 1] == '/')
	  i++;
	path[j++] = path[i++];
      }
      path[j] = path[i];

      url = url0, *url = *parent->site_url;

      if (url->url_path) {
	url->url_path = su_strcat(home, url->url_path, path);
	if (!url->url_path)
	  goto error;
	path = (char *)url->url_path + strlen(parent->site_url->url_path);
      }
      else
	url->url_path = path;

      prev = site_get_rslot(parent, path, &path);

      if (!prev || path[0] == '\0') {
	SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n",
		    url->url_path));
	errno = EEXIST;
	goto error;
      }
    }
  }

  if (!parent) {
    if (strcmp(url->url_host, "*") == 0 ||
	host_cmp(url->url_host, "0.0.0.0") == 0 ||
	host_cmp(url->url_host, "::") == 0)
      wildcard = 1, url->url_host = "*";
  }

  usize = sizeof(*url) + url_xtra(url);

  ta_start(ta, tag, value);

  if (!parent) {
    srv = server_create(url, ta_tags(ta));
    prev = &srv->srv_sites;
  }

  if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) {
    site->site_url = (url_t *)(site + 1);
    url_dup((void *)(site->site_url + 1), usize - sizeof(*url),
	    site->site_url, url);

    assert(prev);
    if ((site->site_next = *prev))
      site->site_next->site_prev = &site->site_next;
    *prev = site, site->site_prev = prev;
    site->site_server = srv;

    if (path) {
      size_t path_len;

      site->site_path = site->site_url->url_path + (path - url->url_path);
      path_len = strlen(site->site_path); assert(path_len > 0);
      if (path_len > 0 && site->site_path[path_len - 1] == '/')
	path_len--, site->site_isdir = 1;
      site->site_path_len = path_len;
    }
    else {
      site->site_isdir = is_host;
      site->site_path = "";
      site->site_path_len = 0;
    }

    site->site_wildcard = wildcard;
    site->site_callback = callback;
    site->site_magic = magic;

    if (parent)
      site->site_auth = parent->site_auth;

    nth_site_set_params(site, ta_tags(ta));
  }

  ta_end(ta);

 error:
  su_home_deinit(home);
  return site;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
0
/**
 * Creates a new operation object and stores it the list of
 * active operations for 'cli'.
 */
ssc_oper_t *ssc_oper_create(ssc_t *ssc,
                            sip_method_t method,
                            char const *name,
                            char const *address,
                            tag_type_t tag, tag_value_t value, ...)
{
    ssc_oper_t *op, *old;

    ta_list ta;

    enter;

    for (old = ssc->ssc_operations; old; old = old->op_next)
        if (!old->op_persistent)
            break;

    if (address) {
        int have_url = 1;
        sip_to_t *to;

        to = sip_to_make(ssc->ssc_home, address);

        if (to == NULL) {
            printf("%s: %s: invalid address: %s\n", ssc->ssc_name, name, address);
            return NULL;
        }

        /* Try to make sense out of the URL */
        if (url_sanitize(to->a_url) < 0) {
            printf("%s: %s: invalid address\n", ssc->ssc_name, name);
            return NULL;
        }

        if (!(op = su_zalloc(ssc->ssc_home, sizeof(*op)))) {
            printf("%s: %s: cannot create handle\n", ssc->ssc_name, name);
            return NULL;
        }

        op->op_next = ssc->ssc_operations;
        op->op_prev_state = -1;
        op->op_ssc = ssc;
        ssc->ssc_operations = op;

        if (method == sip_method_register)
            have_url = 0;

        ta_start(ta, tag, value);

        op->op_handle = nua_handle(ssc->ssc_nua, op,
                                   TAG_IF(have_url, NUTAG_URL(to->a_url)),
                                   SIPTAG_TO(to),
                                   ta_tags(ta));

        ta_end(ta);

        op->op_ident = sip_header_as_string(ssc->ssc_home, (sip_header_t *)to);

        ssc_oper_assign(op, method, name);

        if (!op->op_persistent) {
            ssc_oper_t *old_next;
            for (; old; old = old_next) {      /* Clean old handles */
                old_next = old->op_next;
                if (!old->op_persistent && !old->op_callstate)
                    ssc_oper_destroy(ssc, old);
            }
        }

        su_free(ssc->ssc_home, to);
    }
    else if (method || name)
        ssc_oper_assign(op = old, method, name);
    else
        return old;

    if (!op) {
        if (address)
            printf("%s: %s: invalid destination\n", ssc->ssc_name, name);
        else
            printf("%s: %s: no destination\n", ssc->ssc_name, name);
        return NULL;
    }

    return op;
}