Beispiel #1
0
/*# Send a request to the protocol thread */
int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
	       nua_event_t event,
	       int status, char const *phrase,
	       tag_type_t tag, tag_value_t value, ...)
{
  su_msg_r sumsg = SU_MSG_R_INIT;
  size_t len, xtra, ee_len, l_len = 0, l_xtra = 0;
  ta_list ta;
  int retval = -1;

  if (nua == NULL)
    return -1;

  if (nua->nua_shutdown_started && event != nua_r_shutdown)
    return -1;

  ta_start(ta, tag, value);

  ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags);
  len = tl_len(ta_args(ta));
  xtra = tl_xtra(ta_args(ta), len);

  if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) {
    nua_ee_data_t *ee = su_msg_data(sumsg);
    nua_event_data_t *e = ee->ee_data;
    tagi_t *t = e->e_tags;
    void *b = (char *)t + len + l_len;

    tagi_t *tend = (tagi_t *)b;
    char *bend = (char *)b + xtra + l_xtra;

    t = tl_dup(t, ta_args(ta), &b);

    assert(tend == t); (void)tend; assert(b == bend); (void)bend;

    e->e_always = event == nua_r_destroy || event == nua_r_shutdown;
    e->e_event = event;
    e->e_nh = nh ? nua_handle_ref(nh) : NULL;
    e->e_status = status;
    e->e_phrase = phrase;

    su_msg_deinitializer(sumsg, nua_event_deinit);

    retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal);

    if (retval == 0){
      SU_DEBUG_7(("nua(%p): %s signal %s\n", (void *)nh,
		  "sent", nua_event_name(event) + 4));
    }
    else {
      SU_DEBUG_0(("nua(%p): %s signal %s\n", (void *)nh,
		  "FAILED TO SEND", nua_event_name(event) + 4));

    }
  }

  ta_end(ta);

  return retval;
}
Beispiel #2
0
/*# Receive event from protocol machine and hand it over to application */
static
void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee)
{
  nua_t *nua = ee->ee_nua;
  nua_event_data_t *e = ee->ee_data;
  nua_handle_t *nh = e->e_nh;

  enter;

  ee->ee_nua = NULL;
  e->e_nh = NULL;

  if (nh == NULL) {
    /* Xyzzy */
  }
  else if (nh->nh_valid) {
    if (!nh->nh_ref_by_user) {
      /* Application must now call nua_handle_destroy() */
      nh->nh_ref_by_user = 1;
      nua_handle_ref(nh);
    }
  }
  else if (!nh->nh_valid) {	/* Handle has been destroyed */
    if (nua_log->log_level >= 7) {
      char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4;
      SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
    }
    nua_handle_unref(nh);
    nua_stack_unref(nua);
    return;
  }

  if (e->e_event == nua_r_shutdown && e->e_status >= 200)
    nua->nua_shutdown_final = 1;

  if (nua->nua_callback) {
    nua_event_frame_t frame[1];

    su_msg_save(frame->nf_saved, sumsg);
    frame->nf_next = nua->nua_current, nua->nua_current = frame;

    nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase,
		      nua, nua->nua_magic,
		      nh, nh ? nh->nh_magic : NULL,
		      e->e_msg ? sip_object(e->e_msg) : NULL,
		      e->e_tags);

    su_msg_destroy(frame->nf_saved);
    nua->nua_current = frame->nf_next;
  }

  nua_handle_unref(nh);
  nua_stack_unref(nua);
}
Beispiel #3
0
static
int nh_call_pending(nua_handle_t *nh, sip_time_t now)
{
  nua_dialog_state_t *ds = nh->nh_ds;
  nua_dialog_usage_t *du;
  sip_time_t next = now + NUA_STACK_TIMER_INTERVAL / 1000;

  for (du = ds->ds_usage; du; du = du->du_next) {
    if (now == 0)
      break;
    if (du->du_refresh && du->du_refresh < next)
      break;
  }

  if (du == NULL)
    return 0;

  nua_handle_ref(nh);

  while (du) {
    nua_dialog_usage_t *du_next = du->du_next;

    nua_dialog_usage_refresh(nh, ds, du, now);

    if (du_next == NULL)
      break;

    for (du = nh->nh_ds->ds_usage; du; du = du->du_next)
      if (du == du_next)
	break;

    for (; du; du = du->du_next) {
      if (now == 0)
	break;
      if (du->du_refresh && du->du_refresh < next)
	break;
    }
  }

  nua_handle_unref(nh);

  return 1;
}
Beispiel #4
0
static void
s2_nua_callback(nua_event_t event,
		int status, char const *phrase,
		nua_t *nua, nua_magic_t *_t,
		nua_handle_t *nh, nua_hmagic_t *hmagic,
		sip_t const *sip,
		tagi_t tags[])
{
  struct event *e, **prev;

  if (event == nua_i_active || event == nua_i_terminated)
    return;

  e = calloc(1, sizeof *e);
  nua_save_event(nua, e->event);
  e->nh = nua_handle_ref(nh);
  e->data = nua_event_data(e->event);

  for (prev = &s2->events; *prev; prev = &(*prev)->next)
    ;

  *prev = e, e->prev = prev;
}
Beispiel #5
0
/* ----------------------------------------------------------------------
 * Receiving events from client
 */
static
void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
{
  nua_event_data_t *e = ee->ee_data;
  nua_handle_t *nh = e->e_nh;
  tagi_t *tags = e->e_tags;
  nua_event_t event;
  int error = 0;

  if (nh) {
    if (!nh->nh_prev)
      nh_append(nua, nh);
    if (!nh->nh_ref_by_stack) {
      /* Mark handle as used by stack */
      nh->nh_ref_by_stack = 1;
      nua_handle_ref(nh);
    }
  }

  if (nua_log->log_level >= 5) {
    char const *name = nua_event_name((enum nua_event_e)e->e_event);

    if (e->e_status == 0)
      SU_DEBUG_5(("nua(%p): %s signal %s\n", (void *)nh, "recv", name + 4));
    else
      SU_DEBUG_5(("nua(%p): recv signal %s %u %s\n",
		  (void *)nh, name + 4,
		  e->e_status, e->e_phrase ? e->e_phrase : ""));
  }

  su_msg_save(nua->nua_signal, msg);

  event = (enum nua_event_e)e->e_event;

  if (nua->nua_shutdown && !e->e_always) {
    /* Shutting down */
    nua_stack_event(nua, nh, NULL, event,
		    901, "Stack is going down",
		    NULL);
  }
  else switch (event) {
  case nua_r_get_params:
    nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags);
    break;
  case nua_r_set_params:
    nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, event, tags);
    break;
  case nua_r_shutdown:
    nua_stack_shutdown(nua);
    break;
  case nua_r_register:
  case nua_r_unregister:
    nua_stack_register(nua, nh, event, tags);
    break;
  case nua_r_invite:
    error = nua_stack_invite(nua, nh, event, tags);
    break;
  case nua_r_cancel:
    error = nua_stack_cancel(nua, nh, event, tags);
    break;
  case nua_r_bye:
    error = nua_stack_bye(nua, nh, event, tags);
    break;
  case nua_r_options:
    error = nua_stack_options(nua, nh, event, tags);
    break;
  case nua_r_refer:
    error = nua_stack_refer(nua, nh, event, tags);
    break;
  case nua_r_publish:
  case nua_r_unpublish:
    error = nua_stack_publish(nua, nh, event, tags);
    break;
  case nua_r_info:
    error = nua_stack_info(nua, nh, event, tags);
    break;
  case nua_r_prack:
    error = nua_stack_prack(nua, nh, event, tags);
    break;
  case nua_r_update:
    error = nua_stack_update(nua, nh, event, tags);
    break;
  case nua_r_message:
    error = nua_stack_message(nua, nh, event, tags);
    break;
  case nua_r_subscribe:
  case nua_r_unsubscribe:
    error = nua_stack_subscribe(nua, nh, event, tags);
    break;
  case nua_r_notify:
    error = nua_stack_notify(nua, nh, event, tags);
    break;
  case nua_r_notifier:
    nua_stack_notifier(nua, nh, event, tags);
    break;
  case nua_r_terminate:
    nua_stack_terminate(nua, nh, event, tags);
    break;
  case nua_r_method:
    error = nua_stack_method(nua, nh, event, tags);
    break;
  case nua_r_authenticate:
    nua_stack_authenticate(nua, nh, event, tags);
    break;
  case nua_r_authorize:
    nua_stack_authorize(nua, nh, event, tags);
    break;
  case nua_r_ack:
    error = nua_stack_ack(nua, nh, event, tags);
    break;
  case nua_r_respond:
    nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags);
    break;
  case nua_r_destroy:
    nua_stack_destroy_handle(nua, nh, tags);
    su_msg_destroy(nua->nua_signal);
    return;
  default:
    break;
  }

  if (error < 0) {
    nua_stack_event(nh->nh_nua, nh, NULL, event,
		    NUA_ERROR_AT(__FILE__, __LINE__), NULL);
  }

  su_msg_destroy(nua->nua_signal);
}
Beispiel #6
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;
}
Beispiel #7
0
int nua_stack_init(su_root_t *root, nua_t *nua)
{
  su_home_t *home;
  nua_handle_t *dnh;

  static int initialized_logs = 0;

  enter;

  if (!initialized_logs) {
    extern su_log_t tport_log[];
    extern su_log_t nta_log[];
    extern su_log_t nea_log[];
    extern su_log_t iptsec_log[];

    su_log_init(tport_log);
    su_log_init(nta_log);
    su_log_init(nea_log);
    su_log_init(iptsec_log);

    initialized_logs = 1;
  }

  nua->nua_root = root;

  home = nua->nua_home;
  nua->nua_handles_tail = &nua->nua_handles;
  sip_from_init(nua->nua_from);

  dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
  if (!dnh)
    return -1;

  dnh->nh_prefs = (void *)(dnh + 1);
  dnh->nh_valid = nua_valid_handle_cookie;
  dnh->nh_nua = nua;
  nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1;
  nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
  nh_append(nua, dnh);
  dnh->nh_identity = dnh;
  dnh->nh_ds->ds_local = nua->nua_from;
  dnh->nh_ds->ds_remote = nua->nua_from;

  if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
    return -1;

  if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
    return -1;

  /* XXX - soa should know what it supports */
  nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);

  nua->nua_accept_multipart = sip_accept_format(home, "%s, %s",
						SDP_MIME_TYPE,
						"multipart/*");

  nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
				  NTATAG_MERGE_482(1),
				  NTATAG_CLIENT_RPORT(1),
				  NTATAG_UA(1),
#if HAVE_SOFIA_SMIME
				  NTATAG_SMIME(nua->sm),
#endif
				  TPTAG_STUN_SERVER(1),
				  TAG_NEXT(nua->nua_args));

  dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
				       nua_stack_process_request, dnh,
				       NTATAG_NO_DIALOG(1),
				       TAG_END());

  if (nua->nua_nta == NULL ||
      dnh->nh_ds->ds_leg == NULL ||
      nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
      nua_stack_init_transport(nua, nua->nua_args) < 0) {
    SU_DEBUG_1(("nua: initializing SIP stack failed\n"));
    return -1;
  }

  if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
    return -1;

  if (nua->nua_prefs->ngp_detect_network_updates)
    nua_stack_launch_network_change_detector(nua);

  return 0;
}
Beispiel #8
0
/**Create a client request.
 *
 * @retval 0 if request is pending
 * @retval > 0 if error event has been sent
 * @retval < 0 upon an error
 */
int nua_client_create(nua_handle_t *nh,
		      int event,
		      nua_client_methods_t const *methods,
		      tagi_t const * const tags)
{
  su_home_t *home = nh->nh_home;
  nua_client_request_t *cr;
  sip_method_t method;
  char const *name;

  method = methods->crm_method, name = methods->crm_method_name;
  if (!name) {
    tagi_t const *t = tl_find_last(tags, nutag_method);
    if (t)
      name = (char const *)t->t_value;
  }

  cr = su_zalloc(home, sizeof *cr + methods->crm_extra);
  if (!cr) {
    return nua_stack_event(nh->nh_nua, nh,
			   NULL,
			   (enum nua_event_e)event,
			   NUA_ERROR_AT(__FILE__, __LINE__),
			   NULL);
  }

  cr->cr_methods = methods;
  cr->cr_event = event;
  cr->cr_method = method;
  cr->cr_method_name = name;
  cr->cr_contactize = methods->crm_flags.target_refresh;
  cr->cr_dialog = methods->crm_flags.create_dialog;
  cr->cr_auto = 1;

  if (su_msg_is_non_null(nh->nh_nua->nua_signal)) {
    nua_event_data_t *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data;

    if (tags == e->e_tags && event == e->e_event) {
      cr->cr_auto = 0;

      if (tags) {
	nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal);
	if (cr->cr_signal) {
	  /* Steal reference from signal */
	  cr->cr_owner = e->e_nh, e->e_nh = NULL;
	  cr->cr_tags = tags;
	}
      }
    }
  }

  if (cr->cr_owner == NULL)
    cr->cr_owner = nua_handle_ref(nh);

  if (tags && cr->cr_tags == NULL)
    cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags));

#if HAVE_MEMLEAK_LOG
  SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name));
#endif

  if (nua_client_request_queue(cr))
    return 0;

  return nua_client_init_request(cr);
}