Commit b460e53c authored by Pekka Pessi's avatar Pekka Pessi
Browse files

stab 2 at soa

Added more functionality to soa. Stab at asynchronous API, too.

darcs-hash:20050908002300-65a35-d3cf6bfd21d7cb5ab7603d530056581164a4ece9.gz
parent aff03339
......@@ -26,7 +26,8 @@ BUILT_SOURCES = soa_tag_ref.c
include_HEADERS = soa.h soa_session.h soa_add.h
libsoa_a_SOURCES = soa.c soa_static.c soa_tag.c soa_tag_ref.c
libsoa_a_SOURCES = soa.c soa_static.c soa_asynch.c \
soa_tag.c soa_tag_ref.c
soa_objs_o_SOURCES = $(libsoa_a_SOURCES)
soa_objs_o_LDADD =
......
......@@ -43,6 +43,7 @@ const char soa_c_id[] =
#include <assert.h>
#include <su_tag_class.h>
#include <su_wait.h>
#include "soa.h"
const char soa_h_id[] = SOA_H;
......@@ -53,6 +54,7 @@ const char soa_session_h_id[] = SOA_SESSION_H;
const char soa_add_h_id[] = SOA_ADD_H;
#include <su_tagarg.h>
#include <su_localinfo.h>
#define NONE ((void *)-1)
#define XXX assert(!"implemented")
......@@ -61,12 +63,14 @@ typedef long long unsigned llu;
/* ======================================================================== */
/* Internal prototypes */
static inline
int soa_set_status(soa_session_t *ss, int status, char const *phrase);
static int soa_remote_sdp(soa_session_t *ss, sdp_parser_t *,
char const *sdp, int len);
static int soa_config_sdp(soa_session_t *ss, sdp_parser_t *,
char const *sdp, int len);
static void soa_set_activity(soa_session_t *ss,
sdp_media_t const *,
int remote);
void soa_set_activity(soa_session_t *ss,
sdp_media_t const *,
int remote);
static inline int soa_media_is_ready(soa_session_t const *ss);
......@@ -92,23 +96,32 @@ char const *soa_sent_offer_answer(soa_session_t *soa,
(a)->soa_activate_session != NULL && \
(a)->soa_terminate_session != NULL)
struct soa_session_actions const soa_default_actions =
/*
* The default soa objct stores the offer from parameters,
* sends it when requested.
*
* Likewise it stores the remote offer and sends the SDP from parameters as
* an answer.
*/
struct soa_session_actions const soa_default_actions =
{
(sizeof soa_default_actions),
sizeof (struct soa_session),
soa_default_init,
soa_default_deinit,
soa_default_set_params,
soa_default_get_params,
soa_default_get_paramlist,
soa_default_media_features,
soa_default_sip_required,
soa_default_sip_support,
soa_default_remote_sip_features,
soa_base_init,
soa_base_deinit,
soa_base_set_params,
soa_base_get_params,
soa_base_get_paramlist,
soa_base_media_features,
soa_base_sip_required,
soa_base_sip_support,
soa_base_remote_sip_features,
soa_base_config_sdp,
soa_default_generate_offer,
soa_default_generate_answer,
soa_default_activate_session,
soa_default_terminate_session
soa_base_activate,
soa_base_terminate
};
/* ======================================================================== */
......@@ -119,7 +132,7 @@ struct soa_session_actions const soa_default_actions =
*
* The SOA_DEBUG environment variable is used to determine the default
* debug logging level. The normal level is 3.
*
*
* @sa <su_debug.h>, su_log_global, SOFIA_DEBUG
*/
extern char const SOA_DEBUG[];
......@@ -128,8 +141,8 @@ extern char const SOA_DEBUG[];
#define SU_DEBUG 3
#endif
/**Debug log for @b soa module.
*
/**Debug log for @b soa module.
*
* The soa_log is the log object used by @b soa module. The level of
* #soa_log is set using #SOA_DEBUG environment variable.
*/
......@@ -139,7 +152,7 @@ su_log_t soa_log[] = { SU_LOG_INIT("soa", "SOA_DEBUG", SU_DEBUG) };
/* API Functions */
struct soa_namenode
struct soa_namenode
{
struct soa_namenode const *next;
char const *basename;
......@@ -148,7 +161,7 @@ struct soa_namenode
#define SOA_NAMELISTLEN (16)
static struct soa_namenode const soa_default_node =
static struct soa_namenode const soa_default_node =
{
NULL, "default", &soa_default_actions
};
......@@ -156,8 +169,8 @@ static struct soa_namenode const soa_default_node =
static struct soa_namenode const *soa_namelist = &soa_default_node;
/** Add a named soa backend */
int soa_add_backend(char const *name,
struct soa_session_actions const *actions)
int soa_add(char const *name,
struct soa_session_actions const *actions)
{
struct soa_namenode const *n;
struct soa_namenode *e;
......@@ -167,7 +180,7 @@ int soa_add_backend(char const *name,
if (!SOA_VALID_ACTIONS(actions))
return (errno = EINVAL), -1;
for (n = soa_namelist; n; n = n->next) {
if (strcasecmp(name, n->basename) == 0)
return 0;
......@@ -184,14 +197,37 @@ int soa_add_backend(char const *name,
return 0;
}
/** Search for a named backend */
struct soa_session_actions const *soa_find(char const *name)
{
if (name) {
struct soa_namenode const *n;
size_t baselen = strcspn(name, ":/");
for (n = soa_namelist; n; n = n->next) {
if (strncasecmp(name, n->basename, baselen) == 0)
break;
}
if (n == NULL)
return (void)(errno = ENOENT), NULL;
return n->actions;
}
return NULL;
}
/* ======================================================================== */
soa_session_t *soa_create(su_root_t *root, char const *name)
soa_session_t *soa_create(char const *name,
su_root_t *root,
soa_magic_t *magic)
{
struct soa_session_actions const *actions = &soa_default_actions;
soa_session_t *ss;
if (name) {
struct soa_namenode const *n;
size_t baselen = strcspn(name, ":/");
......@@ -211,36 +247,56 @@ soa_session_t *soa_create(su_root_t *root, char const *name)
if (root == NULL)
return (void)(errno = EFAULT), NULL;
ss = su_home_clone(NULL, actions->sizeof_soa_session);
ss = su_home_new(actions->sizeof_soa_session);
if (ss) {
ss->ss_root = root;
ss->ss_magic = magic;
ss->ss_actions = actions;
ss->ss_actions->soa_init(name, ss, NULL);
if (ss->ss_actions->soa_init(name, ss, NULL) < 0)
ss->ss_actions->soa_deinit(ss), ss = NULL;
}
return ss;
}
soa_session_t *soa_clone(soa_session_t *ss, su_root_t *root)
soa_session_t *soa_clone(soa_session_t *parent_ss,
su_root_t *root,
soa_magic_t *magic)
{
soa_session_t *new_ss;
if (ss == NULL || root == NULL);
soa_session_t *ss;
if (parent_ss == NULL || root == NULL);
return (void)(errno = EFAULT), NULL;
new_ss = su_home_clone(NULL, ss->ss_actions->sizeof_soa_session);
if (new_ss) {
new_ss->ss_root = root;
new_ss->ss_actions = ss->ss_actions;
new_ss->ss_actions->soa_init(NULL, new_ss, ss);
ss = su_home_new(parent_ss->ss_actions->sizeof_soa_session);
if (ss) {
ss->ss_root = root;
ss->ss_magic = magic;
ss->ss_actions = parent_ss->ss_actions;
if (ss->ss_actions->soa_init(NULL, ss, parent_ss) < 0)
ss->ss_actions->soa_deinit(ss), ss = NULL;
}
return new_ss;
return ss;
}
/** Increase reference count */
soa_session_t *soa_session_ref(soa_session_t *ss)
{
return su_home_ref(ss->ss_home);
}
/** Decrease reference count */
void soa_session_unref(soa_session_t *ss)
{
su_home_unref(ss->ss_home);
}
/* Initialize session */
int soa_default_init(char const *name,
soa_session_t *ss,
int soa_base_init(char const *name,
soa_session_t *ss,
soa_session_t *parent)
{
if (parent) {
......@@ -248,12 +304,13 @@ int soa_default_init(char const *name,
static char const *null = NULL;
DUP(ss->ss_caps, sdp_session_dup, parent->ss_caps);
DUP(ss->ss_path, su_strdup, parent->ss_path);
DUP(ss->ss_address, su_strdup, parent->ss_address);
ss->ss_af = parent->ss_af;
DUP(ss->ss_cname, su_strdup, parent->ss_cname);
DUP(ss->ss_path, su_strdup, parent->ss_path);
DUP(ss->ss_mss_sdp, su_strdup, parent->ss_mss_sdp);
DUP(ss->ss_mss_cfg, su_strdup, parent->ss_mss_cfg);
......@@ -263,7 +320,7 @@ int soa_default_init(char const *name,
DUP(ss->ss_image_local, su_strdup, parent->ss_image_local);
DUP(ss->ss_image_remote, su_strdup, parent->ss_image_remote);
DUP(ss->ss_image_name, su_strdup, parent->ss_image_name);
DUP(ss->ss_events, su_strlst_dup, parent->ss_events);
ss->ss_srtp_enable = parent->ss_srtp_enable;
......@@ -278,12 +335,14 @@ int soa_default_init(char const *name,
void soa_destroy(soa_session_t *ss)
{
if (ss) {
ss->ss_active = 0;
ss->ss_terminated++;
ss->ss_actions->soa_deinit(ss);
su_home_zap(ss->ss_home);
su_home_unref(ss->ss_home);
}
}
void soa_default_deinit(soa_session_t *ss)
void soa_base_deinit(soa_session_t *ss)
{
(void)ss;
}
......@@ -293,7 +352,7 @@ int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...)
{
ta_list ta;
int n;
if (ss == NULL)
return (errno = EFAULT), -1;
......@@ -306,12 +365,14 @@ int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...)
return n;
}
int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
int soa_base_set_params(soa_session_t *ss, tagi_t const *tags)
{
int n;
int af;
char const *caps_sdp_str;
char const *media_address, *media_profile, *mss_sdp, *mss_cfg;
char const *media_event_path;
char const *image_local, *image_remote, *image_name;
......@@ -319,6 +380,8 @@ int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
int srtp_enable, srtp_confidentiality, srtp_integrity;
caps_sdp_str = NONE;
af = ss->ss_af;
media_address = ss->ss_address;
......@@ -338,6 +401,8 @@ int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
srtp_integrity = ss->ss_srtp_integrity;
n = tl_gets(tags,
SOATAG_CAPS_SDP_STR_REF(caps_sdp_str),
SOATAG_AF_REF(af),
SOATAG_ADDRESS_REF(media_address),
SOATAG_MEDIA_PROFILE_REF(media_profile),
......@@ -355,12 +420,36 @@ int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
SOATAG_SRTP_ENABLE_REF(srtp_enable),
SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality),
SOATAG_SRTP_INTEGRITY_REF(srtp_integrity),
TAG_END());
if (n <= 0)
return n;
if (caps_sdp_str != NONE) {
if (str0cmp(caps_sdp_str, ss->ss_caps_str0) &&
str0cmp(caps_sdp_str, ss->ss_caps_str)) {
if (caps_sdp_str) {
if (soa_parse_sdp(ss, 0, caps_sdp_str, strlen(caps_sdp_str)) < 0) {
return -1;
}
}
else {
void *p0 = (void *)ss->ss_caps;
void *p1 = (void *)ss->ss_caps_str0;
void *p2 = (void *)ss->ss_caps_str;
ss->ss_caps = NULL;
ss->ss_caps_str = NULL;
ss->ss_caps_str0 = NULL;
su_free(ss->ss_home, p0);
su_free(ss->ss_home, p1);
su_free(ss->ss_home, p2);
}
}
}
if (af != ss->ss_af &&
af >= SOA_AF_ANY && af <= SOA_AF_IP6_IP4)
ss->ss_af = af;
......@@ -389,13 +478,13 @@ int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
if (media_event_path != NONE) {
su_strlst_t *events = ss->ss_events;
tagi_t const *tl;
for (tl = tags; tl; tl = tl_next(tl)) {
if ((tl = tl_find(tl, soatag_media_event_path))) {
char const *path = (char const *)tl->t_value;
size_t i, len = su_strlst_len(events);
for (i = 0; i < len; i++)
for (i = 0; i < len; i++)
if (str0cmp(path, su_strlst_item(events, i)) == 0)
break;
......@@ -409,12 +498,12 @@ int soa_default_set_params(soa_session_t *ss, tagi_t const *tags)
}
/** Get tagged parameters */
int soa_get_params(soa_session_t const *ss,
int soa_get_params(soa_session_t const *ss,
tag_type_t tag, tag_value_t value, ...)
{
ta_list ta;
int n;
if (ss == NULL)
return (errno = EFAULT), -1;
......@@ -427,7 +516,7 @@ int soa_get_params(soa_session_t const *ss,
return n;
}
int soa_default_get_params(soa_session_t const *ss, tagi_t *tags)
int soa_base_get_params(soa_session_t const *ss, tagi_t *tags)
{
int n;
......@@ -437,20 +526,22 @@ int soa_default_get_params(soa_session_t const *ss, tagi_t *tags)
media_event_path = su_strlst_item(ss->ss_events, 0);
n = tl_tgets(tags,
SOATAG_CAPS_SDP_STR(ss->ss_caps_str),
SOATAG_AF(ss->ss_af),
SOATAG_ADDRESS(ss->ss_address),
SOATAG_MEDIA_PROFILE(ss->ss_path),
SOATAG_MSS_SDP(ss->ss_mss_sdp),
SOATAG_MSS_CFG(ss->ss_mss_cfg),
SOATAG_MEDIA_EVENT_PATH(media_event_path),
SOATAG_IMAGE_LOCAL(ss->ss_image_local),
SOATAG_IMAGE_REMOTE(ss->ss_image_remote),
SOATAG_TARGET_IMAGE_NAME(ss->ss_image_name),
SOATAG_VIDEO_LOCAL(ss->ss_video_local),
SOATAG_VIDEO_REMOTE(ss->ss_video_remote),
SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
......@@ -470,7 +561,7 @@ tagi_t *soa_get_paramlist(soa_session_t const *ss)
}
tagi_t *soa_default_get_paramlist(soa_session_t const *ss)
tagi_t *soa_base_get_paramlist(soa_session_t const *ss)
{
tagi_t *params, *media_events = NULL;
......@@ -492,24 +583,26 @@ tagi_t *soa_default_get_paramlist(soa_session_t const *ss)
media_events[len].t_value = 0;
}
}
params = tl_list(SOATAG_AF(ss->ss_af),
params = tl_list(SOATAG_CAPS_SDP_STR(ss->ss_caps_str),
SOATAG_AF(ss->ss_af),
SOATAG_ADDRESS(ss->ss_address),
SOATAG_MEDIA_PROFILE(ss->ss_path),
SOATAG_MSS_SDP(ss->ss_mss_sdp),
SOATAG_MSS_CFG(ss->ss_mss_cfg),
SOATAG_IMAGE_LOCAL(ss->ss_image_local),
SOATAG_IMAGE_REMOTE(ss->ss_image_remote),
SOATAG_TARGET_IMAGE_NAME(ss->ss_image_name),
SOATAG_VIDEO_LOCAL(ss->ss_video_local),
SOATAG_VIDEO_REMOTE(ss->ss_video_remote),
SOATAG_SRTP_ENABLE(ss->ss_srtp_enable),
SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality),
SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity),
TAG_NEXT(media_events));
free(media_events);
......@@ -519,7 +612,7 @@ tagi_t *soa_default_get_paramlist(soa_session_t const *ss)
#include <sip_status.h>
int soa_error_as_sip_response(soa_session_t *ss,
int soa_error_as_sip_response(soa_session_t *ss,
char const **return_phrase)
{
if (ss == NULL) {
......@@ -542,67 +635,44 @@ char const *soa_error_as_sip_reason(soa_session_t *ss)
/**Parse and store session description received from remote end.
*
* @param ss session handle
* @param live
* @param sdp pointer to session description
* @param len length of session description
*
*
* @retval 1 when description is new
* @retval 0 when description is old
* @retval -1 upon an error
*/
int soa_parse_sdp(soa_session_t *ss,
int soa_parse_sdp(soa_session_t *ss,
int live,
char const *sdp,
int len)
{
sdp_parser_t *parser;
sdp_session_t *parsed;
sdp_origin_t const *o;
char const *verdict;
int new_version = 0;
if (ss == NULL || sdp == NULL || len == 0)
return -1;
parser = sdp_parse(ss->ss_home, sdp, len, sdp_f_mode_0000);
if (len == -1)
len = strlen(sdp);
parser = sdp_parse(ss->ss_home, sdp, len,
live ? sdp_f_mode_0000 : sdp_f_config);
if (sdp_parsing_error(parser)) {
sdp_parser_free(parser);
return soa_set_status(ss, 400, "Bad Session Description");
}
soa_clear_sdp(ss);
parsed = sdp_session(parser); assert(parsed);
soa_set_activity(ss, parsed->sdp_media, 1);
o = parsed->sdp_origin;
if (sdp_origin_cmp(o, ss->ss_o_remote)) {
new_version = 1;
if (ss->ss_o_remote)
su_free(ss->ss_home, ss->ss_o_remote);
ss->ss_o_remote = sdp_origin_dup(ss->ss_home, o);
}
if (ss->ss_offer_sent && !ss->ss_answer_recv) {
verdict = "answer";
ss->ss_answer_recv = 1 + new_version;
}
else {
verdict = "offer";
ss->ss_complete = 0;
ss->ss_offer_recv = 1 + new_version;
ss->ss_answer_sent = 0;
}
SU_DEBUG_5(("%s(%p): %s%s (o=%s %llu %llu)\n",
"soa_parse_sdp", ss, new_version ? "new " : "", verdict,
o->o_username, (llu)o->o_id, (llu)o->o_version));
return 0;
if (live > 0)
return soa_remote_sdp(ss, parser, sdp, len);
else if (live == 0)
return soa_config_sdp(ss, parser, sdp, len);
else
return -1;
}
void
void
soa_clear_sdp(soa_session_t *ss)
{
if (ss && ss->ss_parser)
......@@ -611,26 +681,46 @@ soa_clear_sdp(soa_session_t *ss)
/** Return SDP description of the session.
*
* If @a live is 0, return media capabilities (as per RFC 3264 section 9).
* If @a live is 0, return media capabilities (as per RFC 3264 section 9).
*
* @retval 0 if there is no description to return
* @retval 1 if description is returned
* @retval -1 upon an error
*/
int soa_print_sdp(soa_session_t *ss,
int soa_print_sdp(soa_session_t *ss,
int live,
su_home_t *home,
char **return_sdp,
int *return_len)
{
sdp_session_t *session;
sdp_printer_t *printer;
char *sdp;
int len;
if (ss == NULL || return_sdp == NULL || return_len == NULL)
return (errno = EFAULT), -1;
XXX;
session = live ? ss->ss_local : ss->ss_caps;
if (live) {
return -1;
}
else {
return -1;
if (session == NULL)
return (void)(*return_sdp = NULL), (void)(*return_len = 0), 0;
printer = sdp_print(ss->ss_home, session, NULL, 0, 0);
sdp = (void *)sdp_message(printer);
if (sdp) {
len = sdp_message_size(printer);
sdp = su_strndup(home, sdp_message(printer), len);
}
sdp_printer_free(printer);
if (!sdp)
return (void)(*return_sdp = NULL), (void)(*return_len = 0), -1;
return (void)(*return_sdp = sdp), (void)(*return_len = len), 1;
}
......@@ -655,13 +745,13 @@ int soa_init_offer_answer(soa_session_t *ss)
char **soa_media_features(soa_session_t *ss, int live, su_home_t *home)
{