Commit dae79bdd authored by Kai Vehmanen's avatar Kai Vehmanen
Browse files

Big update to to nua_glib. Separated nua_glib operator code to...

Big update to to nua_glib. Separated nua_glib operator code to nua_glib_oper.c, improved documentation, and error handling.

darcs-hash:20060913111631-7659e-cdad8f8db0060e4114faa2833984b00c42568e4f.gz
parent 21cbeee7
......@@ -56,11 +56,14 @@ nobase_include_sofia_HEADERS += \
sofia-sip/nua_glib.h
endif
noinst_HEADERS = nua_glib_priv.h
noinst_HEADERS = nua_glib_priv.h \
nua_glib_op.h
check_PROGRAMS = test_nua_glib
libnua_glib_la_SOURCES = nua_glib.c
libnua_glib_la_SOURCES = \
nua_glib.c \
nua_glib_op.c
libnua_glib_la_LIBADD = nua_glib_marshal.lo
......
......@@ -42,6 +42,7 @@
#include "sofia-sip/nua_glib.h"
#include "nua_glib_priv.h"
#include "nua_glib_op.h"
#include "nua_glib_marshal.h"
/*=============== Class and Object init ===============*/
......@@ -85,6 +86,8 @@ enum
NGSIG_LAST_SIGNAL
};
/*=============== Static variables ===============*/
static guint signals[NGSIG_LAST_SIGNAL] = {0};
enum
......@@ -98,17 +101,150 @@ enum
LAST_PROPERTY
};
void final_shutdown(NuaGlib *self)
{
g_object_unref(self);
}
static GObjectClass *parent_class=NULL;
/*=============== Private function declarations ===============*/
static int sof_init(NuaGlibPrivate *priv, const char *contact);
static void priv_submit_authlist(NuaGlibOp *op);
static void priv_oper_handle_auth (NuaGlib *self, NuaGlibOp *op, sip_t const *sip, tagi_t *tags);
static void priv_oper_check_response_for_auth(NuaGlib *self, NuaGlibOp *op, int status, sip_t const *sip, tagi_t *tags);
static void sof_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_register(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_unregister(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_publish(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_invite(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_fork(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_invite(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_state(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_active(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_terminated(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_prack(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_bye(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_bye(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_cancel(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_message(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_message(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_info(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_info(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_refer(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_refer(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_subscribe(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_unsubscribe(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_notify(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_notify(nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_options(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_shutdown(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_r_get_params(int status, char const *phrase,
nua_t *nua, NuaGlib *self,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[]);
static void sof_i_error(nua_t *nua, NuaGlib *self, nua_handle_t *nh, NuaGlibOp *op,
int status, char const *phrase,
tagi_t tags[]);
/*=============== Function definitions ===============*/
void final_shutdown(NuaGlib *self)
{
g_object_unref(self);
}
static GObject *
nua_glib_constructor (GType type,
......@@ -201,7 +337,8 @@ nua_glib_dispose(GObject *obj)
self->priv->init = FALSE;
/*now hold a ref to ourselves that we drop when distruction is complete*/
g_object_ref (obj);
/* TODO:some start/stop nua funtions to do su_init/de_init? su_deinit();*/
/* XXX: some start/stop nua funtions to do su_init/de_init? su_deinit();*/
}
/* Chain up to the parent class */
......@@ -788,6 +925,8 @@ nua_glib_class_init (NuaGlibClass *nua_glib_class)
* @status: SIP status of REFER answer (see SIP RFC)
* @phrase: Reason for REFER answer
*
* XXX: should we pass the even header as param (see nua_refer()
* documentation and SIPTAG_EVENT())
*/
signals[NGSIG_REFER_ANSWERED] =
g_signal_new("refer-answered",
......@@ -1042,173 +1181,6 @@ sof_callback(nua_event_t event,
}
/* ====================================================================== */
static inline
void oper_assign(NuaGlibOp *op, sip_method_t method, char const *name);
static void nua_glib_op_destroy(NuaGlib *self, NuaGlibOp *op);
static NuaGlibOp *
nua_glib_op_create(NuaGlib *self,
sip_method_t method,
char const *name,
const char *address,
tag_type_t tag, tag_value_t value, ...)
{
NuaGlibOp *op, *old;
ta_list ta;
enter;
for (old = self->priv->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(self->priv->home, address);
if (to == NULL) {
/*TODO, error returns*/
g_warning("%s: %s: invalid address: %s\n", self->priv->name, name, address);
return NULL;
}
/* Try to make sense out of the URL */
if (url_sanitize(to->a_url) < 0) {
/*TODO, error returns*/
g_warning("%s: %s: invalid address\n", self->priv->name, name);
return NULL;
}
if (!(op = su_zalloc(self->priv->home, sizeof(*op)))) {
/*TODO, error returns*/
g_warning("%s: %s: cannot create handle\n", self->priv->name, name);
return NULL;
}
op->op_parent = self;
op->op_next = self->priv->operations;
op->op_prev_state = -1;
self->priv->operations = op;
if (method == sip_method_register)
have_url = 0;
ta_start(ta, tag, value);
op->op_handle = nua_handle(self->priv->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(self->priv->home, (sip_header_t *)to);
oper_assign(op, method, name);
if (!op->op_persistent) {
NuaGlibOp *old_next;
for (; old; old = old_next) { /* Clean old handles */
old_next = old->op_next;
if (!old->op_persistent && !old->op_callstate)
nua_glib_op_destroy(self, old);
}
}
su_free(self->priv->home, to);
}
else if (method || name)
oper_assign(op = old, method, name);
else
return old;
if (!op) {
if (address)
/*TODO, error returns*/
g_warning("%s: %s: invalid destination\n", self->priv->name, name);
else
/*TODO, error returns*/
g_warning("%s: %s: no destination\n", self->priv->name, name);
return NULL;
}
return op;
}
static NuaGlibOp *
nua_glib_op_create2(NuaGlib *self,
sip_method_t method,
char const *name,
nua_handle_t *nh,
sip_from_t const *from)
{
NuaGlibOp *op;
enter;
if ((op = su_zalloc(self->priv->home, sizeof(*op)))) {
op->op_parent = self;
op->op_next = self->priv->operations;
self->priv->operations = op;
oper_assign(op, method, name);
nua_handle_bind(op->op_handle = nh, op);
op->op_ident = sip_header_as_string(self->priv->home, (sip_header_t*)from);
}
else {
SU_DEBUG_1(("%s: cannot create operation object for %s\n",
self->priv->name, name));
}
return op;
}
/** Delete operation and attached handles and identities */
static void
nua_glib_op_destroy(NuaGlib *self, NuaGlibOp *op)
{
NuaGlibOp **prev;
if (!op)
return;
g_assert(op->data == NULL);
/* Remove from queue */
for (prev = &self->priv->operations;
*prev && *prev != op;
prev = &(*prev)->op_next)
;
if (*prev)
*prev = op->op_next, op->op_next = NULL;
if (op->op_authlist)
nua_glib_auth_clear(self, op);
if (op->op_handle)
nua_handle_destroy(op->op_handle), op->op_handle = NULL;
su_free(self->priv->home, op);
}
/* ====================================================================== */
static void
oper_assign(NuaGlibOp *op, sip_method_t method, char const *name)
{
if (!op)
return;
op->op_method = method, op->op_method_name = name;
op->op_persistent =
method == sip_method_subscribe ||
method == sip_method_register ||
method == sip_method_publish;
}
/**
* Helper function called from all response callback handler.
......@@ -1225,7 +1197,7 @@ static void priv_oper_check_response_for_auth(NuaGlib *self, NuaGlibOp *op, int
op->op_authstate != opa_auth_ok) {
op->op_authstate = opa_auth_ok;
SU_DEBUG_3(("%s: authorization of %s (%p) was succesful\n",
self->priv->name, op->op_method_name, op));
self->priv->name, sip_method_name(op->op_method, "<NONE>"), op));
}
}
}
......@@ -1247,7 +1219,7 @@ static void priv_oper_handle_auth (NuaGlib *self, NuaGlibOp *op, sip_t const *si
SIPTAG_PROXY_AUTHENTICATE_REF(pa),
TAG_NULL());
SU_DEBUG_3(("%s: %s (%p) was unauthorized\n", self->priv->name, op->op_method_name, op));
SU_DEBUG_3(("%s: %s (%p) was unauthorized\n", self->priv->name, sip_method_name(op->op_method, "<NONE>"), op));
/* step: the initial challenge */
if (op->op_authstate == opa_none) {
......@@ -1272,14 +1244,14 @@ static void priv_oper_handle_auth (NuaGlib *self, NuaGlibOp *op, sip_t const *si
/* step: a new challenge, ask for matching credentials */
else if (op->op_authstate == opa_try_derived) {
g_message("Requesting for additional authentication credentials %s(%s)",
self->priv->name, op->op_method_name);
self->priv->name, sip_method_name(op->op_method, "<NONE>"));
op->op_authstate = opa_auth_req;
g_signal_emit(self, signals[NGSIG_AUTH_REQUIRED], 0, op, op->op_method_name, realm);
g_signal_emit(self, signals[NGSIG_AUTH_REQUIRED], 0, op, sip_method_name(op->op_method, "<NONE>"), realm);
}
/* step: a new challenge, ask for matching credentials */
else if (op->op_authstate == opa_auth_req) {
g_message("Failed auth for %s by %s",
op->op_method_name, self->priv->name);
sip_method_name(op->op_method, "<NONE>"), self->priv->name);
op->op_authstate = opa_failed;
}
}
......@@ -1359,17 +1331,20 @@ sof_i_error(nua_t *nua, NuaGlib *self, nua_handle_t *nh, NuaGlibOp *op,
* @destination sip address to invite
* @local_sdp an SDP blob describing local capabilites
*
* Issue an INVITE
* Return value: operation descriptor for this operation, NULL if failure
* Invites 'destination_uri' to a new call.
*
* Incomplete sessions can be hung-up with nua_glib_cancel(). Complete or
* incomplete calls can be hung-up with nua_glib_bye()
*
* @see nua_invite() (libsofia-sip-ua/nua)
*
* Return value: operation descriptor for this operation, NULL if failure
*/
NuaGlibOp *
nua_glib_invite(NuaGlib *self, const char *destination, const char *local_sdp)
NuaGlibOp *nua_glib_invite(NuaGlib *self, const char *destination_uri, const char *local_sdp)
{
NuaGlibOp *op;
op = nua_glib_op_create(self, SIP_METHOD_INVITE, destination, TAG_END());
op = nua_glib_op_create(self, sip_method_invite, destination_uri, TAG_END());
/* SDP O/A note:
* - pass media information to nua_invite() in the
......@@ -1385,10 +1360,10 @@ nua_glib_invite(NuaGlib *self, const char *destination, const char *local_sdp)
op->op_callstate |= opc_sent;
return op;
}
return NULL;
}
/*
* invite response handler
*/
......@@ -1406,7 +1381,7 @@ sof_r_invite(int status, char const *phrase,
}
/*
* incoming call-forked handler
* Stack callback: incoming call-forked
*
* Releases forked calls
*/
......@@ -1431,7 +1406,7 @@ sof_i_fork(int status, char const *phrase,
}
/*
* incoming invite handler
* Stack callback: incoming invite handler
*/
static void
sof_i_invite(nua_t *nua, NuaGlib *self,
......@@ -1455,7 +1430,7 @@ sof_i_invite(nua_t *nua, NuaGlib *self,
if (op) {
op->op_callstate |= opc_recv;
}
else if ((op = nua_glib_op_create2(self, SIP_METHOD_INVITE, nh, from))) {
else if ((op = nua_glib_op_create_with_handle(self, sip_method_invite, nh, from))) {
op->op_callstate = opc_recv;
}
else {
......@@ -1500,14 +1475,15 @@ nua_glib_redirect(NuaGlib *self,
* @phrase: Reponse text (default response phrase used if NULL)
* @sdp: SDP description of local media capabilites
*
* Answer a call.
* Answer a incoming call.
*
* @see nua_respond() (libsofia-sip-ua/nua)
*/
void
nua_glib_answer(NuaGlib *self,
NuaGlibOp *op,
int status,
const char *phrase,
const char *sdp)
void nua_glib_answer(NuaGlib *self,
NuaGlibOp *op,
int status,
const char *phrase,
const char *sdp)
{
/* SDP O/A note:
* - pass SDP information to nua_respond() in
......@@ -1515,6 +1491,10 @@ nua_glib_answer(NuaGlib *self,
* - see also: sof_i_state() and nua_glib_invite()
*/
g_assert(self);
g_assert(op);
g_assert(op->op_method == sip_method_invite);
if (status >= 200 && status < 300)
op->op_callstate |= opc_sent;
else
......@@ -1621,24 +1601,27 @@ sof_i_terminated(int status, char const *phrase,
nua_handle_t *nh, NuaGlibOp *op, sip_t const *sip,
tagi_t tags[])
{
g_debug("%s: KVDEBUG\n", G_STRFUNC);
if (op) {
g_signal_emit(self, signals[NGSIG_CALL_TERMINATED], 0, op, status);
op->op_callstate = 0;
g_idle_add(idle_kill_op, op);
}
}
/**
* nua_glib_bye:
* @op the call to bye
*
* Initiate a BYE
* a bye-received signal will be emitted with the response to the bye
* Terminates the call 'op' with SIP BYE method. A 'bye-answered'
* signal will emitted with the response to the bye.
*
* @see nua_bye() (libsofia-sip-ua/nua)
*/
void nua_glib_bye(NuaGlib *self, NuaGlibOp *op)
{
g_assert(nua_glib_op_check(self, op));
nua_bye(op->op_handle, TAG_END());
op->op_callstate = 0;
}
......@@ -1692,10 +1675,9 @@ void sof_i_cancel(nua_t *nua, NuaGlib *self,
* Return value: operation created for request
*/
NuaGlibOp *
nua_glib_options(NuaGlib *self, const char *destination)
nua_glib_options(NuaGlib *self, const char *destination_uri)
{
NuaGlibOp *op = nua_glib_op_create(self, SIP_METHOD_OPTIONS, destination,
TAG_END());
NuaGlibOp *op = nua_glib_op_create(self, sip_method_options, destination_uri, TAG_END());
if (op) {
nua_options(op->op_handle, TAG_END());
......@@ -1725,10 +1707,9 @@ sof_r_options(int status, char const *phrase,
* Return value: operation created for the message, NULL cif failure
*/
NuaGlibOp *
nua_glib_message(NuaGlib *self, const char *destination, const char *message)
nua_glib_message(NuaGlib *self, const char *destination_uri, const char *message)
{
NuaGlibOp *op = nua_glib_op_create(self, SIP_METHOD_MESSAGE, destination,
TAG_END());
NuaGlibOp *op = nua_glib_op_create(self, sip_method_message, destination_uri, TAG_END());
if (op) {
nua_message(op->op_handle,
......@@ -1791,7 +1772,7 @@ sof_i_message(nua_t *nua, NuaGlib *self,
g_string_free(message, TRUE);
if (op == NULL)
op = nua_glib_op_create2(self, SIP_METHOD_MESSAGE, nh, from);
op = nua_glib_op_create_with_handle(self, sip_method_message, nh, from);
if (op == NULL)
nua_handle_destroy(nh);
......@@ -1802,7 +1783,9 @@ sof_i_message(nua_t *nua, NuaGlib *self,
* @op operation representing existing call to send INFO in
* @message INFO message to send
*
* Send an INFO request to a destination on an existing call
* Sends on INFO request to recipient associated with call 'op'.
* INFO is used to send call related information like DTMF digit input
* events. See RFC 2976.
*/
void
nua_glib_info (NuaGlib *self, NuaGlibOp *op, const char *content_type,
......@@ -1859,30 +1842,33 @@ sof_i_info(nua_t *nua, NuaGlib *self,
g_string_free(message, TRUE);
if (op == NULL)
op = nua_glib_op_create2(self, SIP_METHOD_INFO, nh, from);
op = nua_glib_op_create_with_handle(self, sip_method_info, nh, from);
if (op == NULL)
nua_handle_destroy(nh);
}
/*=======================================*/
/**
* nua_glib_refer:
* @op: operation representing existing call
* @destination: destination to REFER them to