Commit 92ba5325 authored by Pekka Pessi's avatar Pekka Pessi

nua: refactored server side requests.

There is now nua_server_methods_t table for handling requests on server side.

darcs-hash:20070124171140-65a35-d5dd2c7ee3940307bf8bbc308321c46234639a77.gz
parent 5fd365c3
......@@ -438,12 +438,11 @@ void nua_dialog_deinit(nua_owner_t *own,
/** @internal Dialog has been terminated. Remove all usages. */
void nua_dialog_terminated(nua_owner_t *own,
struct nua_dialog_state *ds,
int status,
char const *phrase)
void nua_dialog_remove_usages(nua_owner_t *own,
struct nua_dialog_state *ds,
int status,
char const *phrase)
{
ds->ds_terminated = 1;
while (ds->ds_usage) {
......@@ -457,6 +456,8 @@ void nua_dialog_terminated(nua_owner_t *own,
#endif
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
}
nua_dialog_remove(own, ds, NULL);
}
/**@internal
......@@ -557,8 +558,25 @@ void nua_dialog_usage_refresh(nua_owner_t *owner,
}
}
/** Terminate all dialog usages gracefully. */
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds)
{
nua_dialog_usage_t *du;
do {
for (du = ds->ds_usage; du; du = du->du_next) {
if (!du->du_shutdown) {
nua_dialog_usage_shutdown(owner, ds, du);
break;
}
}
} while (du);
return 1;
}
/** (Gracefully) terminate usage */
void nua_dialog_usage_terminate(nua_owner_t *owner,
void nua_dialog_usage_shutdown(nua_owner_t *owner,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
......
......@@ -48,48 +48,72 @@ typedef NUA_OWNER_T nua_owner_t;
#include <sofia-sip/nta.h>
#endif
typedef su_msg_r nua_saved_signal_t;
typedef struct nua_server_request nua_server_request_t;
typedef struct nua_client_request nua_client_request_t;
typedef su_msg_r nua_saved_signal_t;
/** Respond to an incoming request. */
typedef int nua_server_respond_f(nua_server_request_t *, tagi_t const *);
typedef struct {
sip_method_t sm_method;
char const *sm_method_name;
/** Restart an outgoing request. */
typedef void nua_creq_restart_f(nua_owner_t *, tagi_t *tags);
int sm_event;
/** Initialize an outgoing request */
typedef int nua_client_init_f(nua_client_request_t *,
nua_dialog_usage_t *,
tagi_t const *tags);
struct {
unsigned create_dialog:1, in_dialog:1, target_refresh:1, add_contact:1;
unsigned :0;
} sm_flags;
/** Initialize server-side request. */
int (*sm_init)(nua_server_request_t *sr);
/** Preprocess server-side request (after handle has been created). */
int (*sm_preprocess)(nua_server_request_t *sr);
/** Update server-side request parameters */
int (*sm_params)(nua_server_request_t *sr, tagi_t const *tags);
/** Respond to server-side request. */
int (*sm_respond)(nua_server_request_t *sr, tagi_t const *tags);
/** Send an outgoing request. */
typedef int nua_client_request_f(nua_client_request_t *,
msg_t *msg, sip_t *);
/** Report server-side request to application. */
int (*sm_report)(nua_server_request_t *sr, tagi_t const *tags);
} nua_server_methods_t;
/** Server side transaction */
struct nua_server_request {
struct nua_server_request *sr_next, **sr_prev;
nua_server_methods_t const *sr_methods;
nua_owner_t *sr_owner; /**< Backpointer to handle */
nua_dialog_usage_t *sr_usage; /**< Backpointer to usage */
/** When the application responds to a request with
* nua_respond(), the sr_respond() is called
*/
nua_server_respond_f *sr_respond;
nta_incoming_t *sr_irq; /**< Server transaction object */
msg_t *sr_request; /**< Request message */
msg_t *sr_response; /**< Response message */
struct {
msg_t *msg; /**< Request message */
sip_t const *sip; /**< Headers in request message */
} sr_request;
struct {
msg_t *msg; /**< Response message */
sip_t *sip; /**< Headers in response message */
} sr_response;
sip_method_t sr_method; /**< Request method */
int sr_application; /**< Status by application */
int sr_status; /**< Status code */
char const *sr_phrase; /**< Status phrase */
unsigned sr_event:1; /**< Sent to application */
unsigned sr_application:1; /**< Response by application */
unsigned sr_event:1; /**< Reported to application */
unsigned sr_initial:1; /**< Handle was created by this request */
unsigned sr_add_contact:1; /**< Add Contact header to the response */
unsigned sr_terminating:1; /**< Terminate usage after final response */
unsigned sr_gracefully:1; /**< Terminate usage gracefully */
/* Flags used with offer-answer */
unsigned sr_offer_recv:1; /**< We have received an offer */
......@@ -97,12 +121,11 @@ struct nua_server_request {
unsigned sr_offer_sent:1; /**< We have offered SDP */
unsigned sr_answer_recv:1; /**< We have received SDP answer */
};
unsigned :0;
#define SR_INIT(sr) \
((void)memset((sr), 0, sizeof (sr)[0]), \
(void)(SR_STATUS1((sr), SIP_100_TRYING)), \
sr)
char const *sr_sdp; /**< SDP received from client */
size_t sr_sdp_len; /**< ... and its length */
};
#define SR_STATUS(sr, status, phrase) \
((sr)->sr_phrase = (phrase), (sr)->sr_status = (status))
......@@ -394,10 +417,12 @@ void nua_dialog_usage_remove(nua_owner_t *,
void nua_dialog_deinit(nua_owner_t *own,
nua_dialog_state_t *ds);
void nua_dialog_terminated(nua_owner_t *,
struct nua_dialog_state *ds,
int status,
char const *phrase);
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds);
void nua_dialog_remove_usages(nua_owner_t *,
struct nua_dialog_state *ds,
int status,
char const *phrase);
void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
......@@ -413,7 +438,7 @@ void nua_dialog_usage_refresh(nua_owner_t *owner,
nua_dialog_usage_t *du,
sip_time_t now);
void nua_dialog_usage_terminate(nua_owner_t *owner,
void nua_dialog_usage_shutdown(nua_owner_t *owner,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
......@@ -550,19 +575,57 @@ nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
/* ---------------------------------------------------------------------- */
extern nua_server_methods_t const
nua_extension_server_methods,
nua_invite_server_methods, /**< INVITE */
nua_bye_server_methods, /**< BYE */
nua_options_server_methods, /**< OPTIONS */
nua_register_server_methods, /**< REGISTER */
nua_info_server_methods, /**< INFO */
nua_prack_server_methods, /**< PRACK */
nua_update_server_methods, /**< UPDATE */
nua_message_server_methods, /**< MESSAGE */
nua_subscribe_server_methods, /**< SUBSCRIBE */
nua_notify_server_methods, /**< NOTIFY */
nua_refer_server_methods, /**< REFER */
nua_publish_server_methods; /**< PUBLISH */
static inline
int nua_server_request_is_pending(nua_server_request_t const *sr)
{
return sr && sr->sr_response.msg;
}
void nua_server_request_destroy(nua_server_request_t *sr);
int nua_server_respond(nua_server_request_t *sr,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
int nua_base_server_init(nua_server_request_t *sr);
msg_t *nua_server_response(nua_server_request_t *sr,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
#define nua_base_server_init NULL
int nua_base_server_preprocess(nua_server_request_t *sr);
#define nua_base_server_preprocess NULL
int nua_server_params(nua_server_request_t *sr, tagi_t const *tags);
int nua_base_server_params(nua_server_request_t *sr, tagi_t const *tags);
#define nua_base_server_params NULL
int nua_server_trespond(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags);
int nua_base_server_trespond(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_base_server_respond(nua_server_request_t *sr,
tagi_t const *tags);
int nua_default_respond(nua_server_request_t *sr,
tagi_t const *tags);
int nua_server_report(nua_server_request_t *sr);
int nua_base_server_treport(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags);
/* ---------------------------------------------------------------------- */
......
......@@ -135,34 +135,19 @@ nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags
* @END_NUA_EVENT
*/
static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
int nua_stack_process_method(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
{
nua_server_request_t *sr, sr0[1];
sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof sr0,
respond_to_method, 0);
return nua_stack_server_event(nua, sr, nua_i_method, TAG_END());
}
static
int respond_to_method(nua_server_request_t *sr, tagi_t const *tags)
{
nua_handle_t *nh = sr->sr_owner;
nua_t *nua = nh->nh_nua;
int status = sr->sr_status;
int final = nua_default_respond(sr, tags);
if (status != sr->sr_status)
nua_stack_event(nua, nh, NULL,
nua_i_error, 900, "Response to Extension Method Fails",
NULL);
return final;
}
nua_server_methods_t const nua_extension_server_methods =
{
SIP_METHOD_UNKNOWN,
nua_i_method, /* Event */
{
0, /* Do not create dialog */
0, /* Can be an initial request */
1, /* Perhaps a target refresh request? */
1, /* Add a contact? */
},
nua_base_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
......@@ -149,19 +149,39 @@ static int nua_message_client_init(nua_client_request_t *cr,
* @END_NUA_EVENT
*/
int nua_stack_process_message(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
int nua_message_server_init(nua_server_request_t *sr);
int nua_message_server_params(nua_server_request_t *, tagi_t const *);
nua_server_methods_t const nua_message_server_methods =
{
SIP_METHOD_MESSAGE,
nua_i_message, /* Event */
{
0, /* Do not create dialog */
0, /* Can be initial request */
0, /* Perhaps a target refresh request? */
0, /* Do not add contact by default */
},
nua_message_server_init,
nua_base_server_preprocess,
nua_message_server_params,
nua_base_server_respond,
nua_base_server_report,
};
int nua_message_server_init(nua_server_request_t *sr)
{
nua_server_request_t *sr, sr0[1];
if (!NH_PGET(sr->sr_owner, message_enable))
return SR_STATUS1(sr, SIP_403_FORBIDDEN);
sr = SR_INIT(sr0);
if (!NUA_PGET(nua, nh, message_enable))
SR_STATUS1(sr, SIP_403_FORBIDDEN);
return 0;
}
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr, NULL, 0);
int nua_message_server_params(nua_server_request_t *sr,
tagi_t const *tags)
{
if (NH_PGET(sr->sr_owner, win_messenger_enable))
sr->sr_add_contact = 1;
return nua_stack_server_event(nua, sr, nua_i_message, TAG_END());
return 0;
}
This diff is collapsed.
......@@ -475,24 +475,35 @@ static int nua_publish_usage_shutdown(nua_handle_t *nh,
* @END_NUA_EVENT
*/
int nua_stack_process_publish(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
int nua_publish_server_init(nua_server_request_t *sr);
nua_server_methods_t const nua_publish_server_methods =
{
SIP_METHOD_PUBLISH,
nua_i_publish, /* Event */
{
0, /* Do not create dialog */
0, /* Initial request */
0, /* Not a target refresh request */
1, /* Add Contact */
},
nua_publish_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
int nua_publish_server_init(nua_server_request_t *sr)
{
nua_server_request_t *sr, sr0[1];
sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
sip_event_t *o = sip->sip_event;
sip_allow_events_t *allow_events = NH_PGET(sr->sr_owner, allow_events);
sip_event_t *o = sr->sr_request.sip->sip_event;
char const *event = o ? o->o_type : NULL;
sr = SR_INIT(sr0);
if (!allow_events)
SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
return SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
else if (!event || !msg_header_find_param(allow_events->k_common, event))
SR_STATUS1(sr, SIP_489_BAD_EVENT);
return SR_STATUS1(sr, SIP_489_BAD_EVENT);
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr, NULL, 0);
return nua_stack_server_event(nua, sr, nua_i_publish, TAG_END());
return 0;
}
......@@ -87,15 +87,19 @@
* @END_NUA_EVENT
*/
int nua_stack_process_register(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
{
nua_server_request_t *sr, sr0[1];
sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
NULL, 0);
return nua_stack_server_event(nua, sr, nua_i_register, TAG_END());
}
nua_server_methods_t const nua_register_server_methods =
{
SIP_METHOD_REGISTER,
nua_i_register, /* Event */
{
0, /* Do not create dialog */
0, /* Initial request */
0, /* Not a target refresh request */
0, /* Do not add Contact */
},
nua_base_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
This diff is collapsed.
This diff is collapsed.
......@@ -388,47 +388,6 @@ int nua_registration_add_contact_to_response(nua_handle_t *nh,
sip_record_route_t const *,
sip_contact_t const *remote);
msg_t *nh_make_response(nua_t *nua, nua_handle_t *nh,
nta_incoming_t *irq,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
typedef int nua_stack_process_request_t(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip);
nua_stack_process_request_t nua_stack_process_invite;
nua_stack_process_request_t nua_stack_process_info;
nua_stack_process_request_t nua_stack_process_update;
nua_stack_process_request_t nua_stack_process_bye;
nua_stack_process_request_t nua_stack_process_message;
nua_stack_process_request_t nua_stack_process_options;
nua_stack_process_request_t nua_stack_process_publish;
nua_stack_process_request_t nua_stack_process_subscribe;
nua_stack_process_request_t nua_stack_process_notify;
nua_stack_process_request_t nua_stack_process_refer;
nua_stack_process_request_t nua_stack_process_unknown;
nua_stack_process_request_t nua_stack_process_register;
nua_stack_process_request_t nua_stack_process_method;
/* ---------------------------------------------------------------------- */
nua_server_request_t *nua_server_request(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip,
nua_server_request_t *sr,
size_t size,
nua_server_respond_f *respond,
int create_dialog);
int nua_stack_server_event(nua_t *nua,
nua_server_request_t *sr,
nua_event_t event,
tag_type_t tag, tag_value_t value, ...);
/* ---------------------------------------------------------------------- */
#ifndef SDP_MIME_TYPE
......
......@@ -499,170 +499,178 @@ static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
* @END_NUA_EVENT
*/
/** @internal Process incoming NOTIFY. */
int nua_stack_process_notify(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
int nua_notify_server_init(nua_server_request_t *sr);
int nua_notify_server_preprocess(nua_server_request_t *sr);
int nua_notify_server_report(nua_server_request_t *, tagi_t const *);
nua_server_methods_t const nua_notify_server_methods =
{
SIP_METHOD_NOTIFY,
nua_i_notify, /* Event */
{
0, /* Do not create dialog */
1, /* In-dialog request */
1, /* Target refresh request */
1, /* Add Contact */
},
nua_notify_server_init,
nua_notify_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_notify_server_report,
};
int nua_notify_server_init(nua_server_request_t *sr)
{
nua_dialog_state_t *ds = nh->nh_ds;
nua_dialog_usage_t *du;
struct event_usage *eu;
sip_subscription_state_t *subs = sip ? sip->sip_subscription_state : NULL;
sip_subscription_state_t ss0[1];
msg_t *response;
char expires[32];
int retry = -1;
char const *what = NULL, *why = NULL;
if (!sr->sr_initial) {
nua_dialog_state_t *ds = sr->sr_owner->nh_ds;
/* Check for forked subscription. */
if (ds->ds_remote_tag && ds->ds_remote_tag[0] &&
str0cmp(ds->ds_remote_tag, sr->sr_request.sip->sip_from->a_tag)) {
sip_contact_t const *m = NULL;
m = nua_stack_get_contact(sr->sr_owner->nh_nua->nua_registrations);
if (m) {
sip_warning_t w[1];
sip_warning_init(w)->w_code = 399;
w->w_host = m->m_url->url_host;
w->w_port = m->m_url->url_port;
w->w_text = "Forking SUBSCRIBEs are not supported";
enter;
sip_add_dup(sr->sr_response.msg, NULL, (sip_header_t*)w);
}
if (nh == NULL) {
nta_incoming_treply(irq, 481, "Subscription Does Not Exist",
TAG_END());
return 481;
}
assert(nh);
if (/* XXX - support forking of subscriptions?... */
ds->ds_remote_tag && ds->ds_remote_tag[0] &&
sip && sip->sip_from->a_tag &&
strcmp(ds->ds_remote_tag, sip->sip_from->a_tag)) {
sip_contact_t const *m = NULL;
sip_warning_t *w = NULL, w0[1];
m = nua_stack_get_contact(nua->nua_registrations);
if (m) {
w = sip_warning_init(w0);
w->w_code = 399;
w->w_host = m->m_url->url_host;
w->w_port = m->m_url->url_port;
w->w_text = "Forking SUBSCRIBEs are not supported";
return SR_STATUS(sr, 481, "Subscription Does Not Exist");
}
nta_incoming_treply(irq, 481, "Subscription Does Not Exist",
SIPTAG_WARNING(w),
TAG_END());
return 481;
}
du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, sip->sip_event);
return 0;
}
if (du == NULL) {
nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END());
return 481;
}
int nua_notify_server_preprocess(nua_server_request_t *sr)
{
nua_dialog_state_t *ds = sr->sr_owner->nh_ds;
nua_dialog_usage_t *du;
struct event_usage *eu;
sip_t const *sip = sr->sr_request.sip;
sip_event_t *o = sip->sip_event;
enum nua_substate substate = nua_substate_terminated;
sip_subscription_state_t *subs = sip->sip_subscription_state;
char const *what = "", *reason = NULL;
du = nua_dialog_usage_get(ds, nua_subscribe_usage, o);
if (du == NULL)
return SR_STATUS(sr, 481, "Subscription Does Not Exist");
sr->sr_usage = du;
eu = nua_dialog_usage_private(du); assert(eu);
eu->eu_notified++;
if (!sip->sip_event->o_id) {
if (!o->o_id)
eu->eu_no_id = 1;
}
if (subs == NULL) {
/* Do some compatibility stuff here */
unsigned long delta;
sip_subscription_state_init(subs = ss0);
delta = sip->sip_expires ? sip->sip_expires->ex_delta : eu->eu_expires;
/* Compatibility */
unsigned long delta = eu->eu_expires;
if (sip->sip_expires)
delta = sip->sip_expires->ex_delta;
if (delta == 0)
subs->ss_substate = "terminated";
substate = nua_substate_terminated, what = "terminated";
else
subs->ss_substate = "active";
if (delta > 0 && sip->sip_expires) {
snprintf(expires, sizeof expires, "%lu", delta);
subs->ss_expires = expires;
}
substate = nua_substate_active, what = "active";
}
else if (strcasecmp(subs->ss_substate, what = "terminated") == 0) {
substate = nua_substate_terminated;
reason = subs->ss_reason;
nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
if (strcasecmp(subs->ss_substate, what = "terminated") == 0) {
eu->eu_substate = nua_substate_terminated;
if (str0casecmp(subs->ss_reason, why = "deactivated") == 0) {
eu->eu_substate = nua_substate_embryonic;
retry = 0; /* retry immediately */
}
else if (str0casecmp(subs->ss_reason, why = "probation") == 0) {
eu->eu_substate = nua_substate_embryonic;
retry = 30;
if (subs->ss_retry_after)
retry = strtoul(subs->ss_retry_after, NULL, 10);
if (retry > 3600)
retry = 3600;
}
else
why = subs->ss_reason;
if (str0casecmp(reason, "deactivated") == 0 ||
str0casecmp(reason, "probation") == 0)
substate = nua_substate_embryonic;
}
else if (strcasecmp(subs->ss_substate, what = "pending") == 0)
eu->eu_substate = nua_substate_pending;
else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ {
else if (strcasecmp(subs->ss_substate, what = "pending") == 0) {
substate = nua_substate_pending;
}
else /* if (strcasecmp(subs->ss_substate, what = "active") == 0) */ {
/* Any extended state is considered as active */
what = subs->ss_substate ? subs->ss_substate : "active";
eu->eu_substate = nua_substate_active;
what = subs->ss_substate;
substate = nua_substate_active;
}
if (du->du_shutdown || (du->du_cr && du->du_cr->cr_terminating))
retry = -1;
response = nh_make_response(nua, nh, irq, SIP_200_OK,
SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
TAG_END());
eu->eu_substate = substate;
if (response)
nta_incoming_mreply(irq, response);
else
nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
SU_DEBUG_5(("nua(%p): %s: %s (%s)\n",
sr->sr_owner, "nua_notify_server_preprocess",
what, reason ? reason : ""));
if (eu->eu_substate == nua_substate_terminated && retry > 0)
eu->eu_substate = nua_substate_embryonic;
return SR_STATUS1(sr, SIP_200_OK);
}
nua_stack_tevent(nh->nh_nua, nh, nta_incoming_getrequest(irq),
nua_i_notify, SIP_200_OK,
NUTAG_SUBSTATE(eu->eu_substate),
TAG_END());
nta_incoming_destroy(irq), irq = NULL;
int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
{
nua_handle_t *nh = sr->sr_owner;
nua_dialog_usage_t *du = sr->sr_usage;
struct event_usage *eu = nua_dialog_usage_private(du);
sip_t const *sip = sr->sr_request.sip;
enum nua_substate substate = nua_substate_terminated;