summaryrefslogtreecommitdiffstats
path: root/tinyDEMO/common.c
diff options
context:
space:
mode:
authorbossiel <bossiel@yahoo.fr>2011-08-10 22:59:15 +0000
committerbossiel <bossiel@yahoo.fr>2011-08-10 22:59:15 +0000
commit1ebf5a5fcda0c9154e22ed02404fd46525a7fd9f (patch)
tree4b6214a7142ab1035cb0e47444e88af38e712421 /tinyDEMO/common.c
downloaddoubango-1ebf5a5fcda0c9154e22ed02404fd46525a7fd9f.zip
doubango-1ebf5a5fcda0c9154e22ed02404fd46525a7fd9f.tar.gz
Move deprecated v1.0 from trunk to branches1.0
Diffstat (limited to 'tinyDEMO/common.c')
-rw-r--r--tinyDEMO/common.c880
1 files changed, 880 insertions, 0 deletions
diff --git a/tinyDEMO/common.c b/tinyDEMO/common.c
new file mode 100644
index 0000000..4a2fbab
--- /dev/null
+++ b/tinyDEMO/common.c
@@ -0,0 +1,880 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#include "common.h"
+
+#include "invite.h"
+#include "message.h"
+#include "options.h"
+#include "publish.h"
+#include "register.h"
+#include "subscribe.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* === default values === */
+#define DEFAULT_REALM "open-ims.test"
+#define DEFAULT_IMPI "bob@"DEFAULT_REALM
+#define DEFAULT_IMPU "sip:bob@"DEFAULT_REALM
+
+#ifndef DEFAULT_LOCAL_IP
+//# ifdef ANDROID /* On the emulator */
+//# define DEFAULT_LOCAL_IP "10.0.2.15"
+//# define DEFAULT_LOCAL_IP "192.168.0.14"
+//# else
+# define DEFAULT_LOCAL_IP TNET_SOCKET_HOST_ANY
+//# endif
+#endif
+
+
+extern ctx_t* ctx;
+
+int stack_callback(const tsip_event_t *sipevent);
+int session_handle_event(const tsip_event_t *sipevent);
+int session_tostring(const session_t* session);
+
+/* our SIP callback function */
+int stack_callback(const tsip_event_t *_event)
+{
+ int ret = 0;
+
+ if(!_event){ /* should never happen ...but who know? */
+ TSK_DEBUG_WARN("Null SIP event.");
+ return -1;
+ }
+
+#if 0
+ tsk_safeobj_lock(ctx);
+#endif
+
+ switch(_event->type){
+ case tsip_event_register:
+ { /* REGISTER */
+ ret = register_handle_event(_event);
+ break;
+ }
+ case tsip_event_invite:
+ { /* INVITE */
+ ret = invite_handle_event(_event);
+ break;
+ }
+ case tsip_event_message:
+ { /* MESSAGE */
+ ret = message_handle_event(_event);
+ break;
+ }
+ case tsip_event_options:
+ { /* OPTIONS */
+ ret = options_handle_event(_event);
+ break;
+ }
+ case tsip_event_publish:
+ { /* PUBLISH */
+ ret = publish_handle_event(_event);
+ break;
+ }
+ case tsip_event_subscribe:
+ { /* SUBSCRIBE */
+ ret = subscribe_handle_event(_event);
+ break;
+ }
+
+ case tsip_event_dialog:
+ { /* Common to all dialogs */
+ ret = session_handle_event(_event);
+ break;
+ }
+
+ case tsip_event_stack:
+ {
+ switch(_event->code){
+ case tsip_event_code_stack_started:
+ TSK_DEBUG_INFO("Stack started");
+ break;
+ case tsip_event_code_stack_stopped:
+ TSK_DEBUG_INFO("Stack stopped");
+ break;
+ case tsip_event_code_stack_failed_to_start:
+ TSK_DEBUG_INFO("Stack failed to start");
+ break;
+ case tsip_event_code_stack_failed_to_stop:
+ TSK_DEBUG_INFO("Stack failed to stop");
+ break;
+ }
+ break;
+ }
+
+ default:
+ { /* Unsupported */
+ TSK_DEBUG_WARN("%d not supported as SIP event.", _event->type);
+ ret = -3;
+ break;
+ }
+ }
+#if 0
+ tsk_safeobj_unlock(ctx);
+#endif
+
+ return ret;
+}
+
+/* ==================================================================
+ ========================== Context =================================
+*/
+
+ctx_t* ctx_create()
+{
+ return tsk_object_new(ctx_def_t);
+}
+
+static tsk_object_t* ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ ctx_t *ctx = self;
+ if(ctx){
+ /* stack */
+ ctx->stack = tsip_stack_create(stack_callback, DEFAULT_REALM, DEFAULT_IMPI, DEFAULT_IMPU, /* Mandatory parameters */
+ TSIP_STACK_SET_LOCAL_IP(DEFAULT_LOCAL_IP), /* local IP */
+ TSIP_STACK_SET_NULL() /* Mandatory */);
+
+ /* SIP Sessions */
+ ctx->sessions = tsk_list_create();
+
+ /* user's parameters */
+ ctx->params = tsk_list_create();
+
+ /* init internal mutex */
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* ctx_dtor(tsk_object_t * self)
+{
+ ctx_t *ctx = self;
+ if(ctx){
+ /* Stop the stack (as sessions are alive, you will continue to receive callbacks)*/
+ tsip_stack_stop(ctx->stack);
+
+ /* sessions : should be freed before the stack as explained on the Programmer's Guide
+ * As all dialogs have been hanged up, the list should be empty ...but who know?*/
+ TSK_OBJECT_SAFE_FREE(ctx->sessions);
+
+ /* Destroy the stack */
+ TSK_OBJECT_SAFE_FREE(ctx->stack);
+
+ /* Identity */
+ TSK_FREE(ctx->identity.display_name);
+ TSK_FREE(ctx->identity.impu);
+ TSK_FREE(ctx->identity.preferred);
+ TSK_FREE(ctx->identity.impi);
+ TSK_FREE(ctx->identity.password);
+
+ /* Network */
+ TSK_FREE(ctx->network.local_ip);
+ TSK_FREE(ctx->network.proxy_cscf);
+ TSK_FREE(ctx->network.proxy_cscf_trans);
+ TSK_FREE(ctx->network.realm);
+
+ /* Security */
+ TSK_FREE(ctx->security.operator_id);
+
+ /* Params */
+ TSK_OBJECT_SAFE_FREE(ctx->params);
+
+ /* deinit internal mutex */
+ tsk_safeobj_deinit(ctx);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t ctx_def_s =
+{
+ sizeof(ctx_t),
+ ctx_ctor,
+ ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *ctx_def_t = &ctx_def_s;
+
+
+/* ==================================================================
+ ========================== Stack =================================
+*/
+
+int stack_dump()
+{
+ const tsk_list_item_t* item;
+
+ tsk_list_foreach(item, ctx->sessions){
+ session_tostring(item->data);
+ }
+ return 0;
+}
+
+int stack_config(const opts_L_t* opts)
+{
+ const tsk_list_item_t* item;
+ const opt_t* opt;
+ int ret = 0;
+ tsk_param_t* param;
+ tsk_bool_t pcscf_changed = tsk_false;
+ tsk_bool_t stun_done = tsk_false;
+
+ if(!opts){
+ return -1;
+ }
+
+ tsk_list_foreach(item, opts){
+ opt = item->data;
+
+ /* Stack-level option */
+ if(opt->lv != lv_none && opt->lv != lv_stack){
+ continue;
+ }
+
+ switch(opt->type){
+ case opt_amf:
+ {
+ break;
+ }
+ case opt_dhcpv4:
+ case opt_dhcpv6:
+ {
+ tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_DISCOVERY_DHCP(tsk_true),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_dname:
+ {
+ break;
+ }
+ case opt_dns_naptr:
+ {
+ tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_DISCOVERY_NAPTR(tsk_true),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_header:
+ {
+ if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))){
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_HEADER(param->name, param->value),
+ TSIP_STACK_SET_NULL());
+ TSK_OBJECT_SAFE_FREE(param);
+ }
+ break;
+ }
+ case opt_impi:
+ {
+ tsk_strupdate(&ctx->identity.impi, opt->value);
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_IMPI(ctx->identity.impi),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_impu:
+ {
+ tsk_strupdate(&ctx->identity.impu, opt->value);
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_IMPU(ctx->identity.impu),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_ipv6:
+ {
+ pcscf_changed = tsk_true;
+ ctx->network.ipv6 = tsk_true;
+ break;
+ }
+ case opt_local_ip:
+ {
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_LOCAL_IP(opt->value),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_local_port:
+ {
+ unsigned port = (unsigned)atoi(opt->value);
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_LOCAL_PORT(port),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_opid:
+ {
+ break;
+ }
+ case opt_password:
+ {
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_PASSWORD(opt->value),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+ case opt_pcscf_ip:
+ {
+ pcscf_changed = tsk_true;
+ tsk_strupdate(&ctx->network.proxy_cscf, opt->value);
+ break;
+ }
+ case opt_pcscf_port:
+ {
+ pcscf_changed = tsk_true;
+ ctx->network.proxy_cscf_port = atoi(opt->value);
+ break;
+ }
+ case opt_pcscf_trans:
+ {
+ pcscf_changed = tsk_true;
+ tsk_strupdate(&ctx->network.proxy_cscf_trans, opt->value);
+ break;
+ }
+ case opt_realm:
+ {
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_REALM(opt->value),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+
+ case opt_sigcomp_id:
+ { /* add compartment */
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_SIGCOMP_NEW_COMPARTMENT(opt->value),
+ TSIP_STACK_SET_NULL());
+ break;
+ }
+
+ case opt_stun_ip:
+ case opt_stun_pwd:
+ case opt_stun_port:
+ case opt_stun_usr:
+ {
+ if(!stun_done){
+ const opt_t* _opt;
+ const char* ip = tsk_null, *usr = tsk_null, *pwd = tsk_null;
+ unsigned port = 0;
+
+ if((_opt = opt_get_by_type(opts, opt_stun_ip))){
+ ip = _opt->value;
+ }
+ if((_opt = opt_get_by_type(opts, opt_stun_port))){
+ port = atoi(_opt->value);
+ }
+ if((_opt = opt_get_by_type(opts, opt_stun_usr))){
+ usr = _opt->value;
+ }
+ if((_opt = opt_get_by_type(opts, opt_stun_pwd))){
+ pwd = _opt->value;
+ }
+
+ if(ip && port){
+ tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_STUN_SERVER(ip, port),
+ TSIP_STACK_SET_NULL());
+ }
+ if(usr){
+ tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_STUN_CRED(usr, pwd),
+ TSIP_STACK_SET_NULL());
+ }
+
+ stun_done = tsk_true;
+ }
+ break;
+ }
+
+ }/* switch */
+
+ } /* foreach */
+
+ /* whether Proxy-CSCF config has changed */
+ if(pcscf_changed){
+ ret = tsip_stack_set(ctx->stack,
+ TSIP_STACK_SET_PROXY_CSCF(ctx->network.proxy_cscf, ctx->network.proxy_cscf_port, ctx->network.proxy_cscf_trans, ctx->network.ipv6 ? "ipv6" : "ipv4"),
+ TSIP_STACK_SET_NULL());
+ }
+
+ return ret;
+}
+
+int stack_run(const opts_L_t* opts)
+{
+ if(!ctx->stack){
+ TSK_DEBUG_ERROR("Stack is Null.");
+ return -1;
+ }
+ else{
+ return tsip_stack_start(ctx->stack);
+ }
+}
+
+/* ==================================================================
+ ========================== Session =================================
+*/
+
+/* Find SIP session by id */
+int pred_find_session_by_id(const tsk_list_item_t *item, const void* id)
+{
+ const session_t* session;
+ if(item && item->data){
+ session = item->data;
+ return (int)(tsip_ssession_get_id(session->handle)
+ - *((tsip_ssession_id_t*)id));
+ }
+ return -1;
+}
+
+session_t* session_create(session_type_t type, tsip_ssession_handle_t* handle)
+{
+ session_t* session = tsk_object_new(session_def_t, type, handle);
+ if(!session){
+ TSK_DEBUG_ERROR("Failed to create new SIP session");
+ return tsk_null;
+ }
+
+ switch(type){
+ case st_invite:
+ { /* Enable all features (QoS, Session timers, SigComp, ...) */
+ tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_USERDATA(session),
+ /*=== MEDIA */
+ TSIP_SSESSION_SET_MEDIA(
+ // 100rel
+ TSIP_MSESSION_SET_100rel(),
+ // Session timers
+ TSIP_MSESSION_SET_TIMERS(3600, "uac"),
+ // QoS
+ TSIP_MSESSION_SET_QOS(tmedia_qos_stype_segmented, tmedia_qos_strength_optional),
+ // close media params
+ TSIP_MSESSION_SET_NULL()
+ ),
+
+ TSIP_SSESSION_SET_NULL());
+ break;
+ }
+ default:
+ break;
+ }
+ return session;
+}
+
+const session_t* session_get_by_sid(const sessions_L_t* sessions, tsip_ssession_id_t sid)
+{
+ const tsk_list_item_t* item;
+ if((item = tsk_list_find_item_by_pred(sessions, pred_find_session_by_id, &sid))){
+ return item->data;
+ }
+ else{
+ return tsk_null;
+ }
+}
+
+
+int session_tostring(const session_t* session)
+{
+ //char* temp = tsk_null;
+ printf("== Session: ");
+ if(session){
+ /* Session Id */
+ printf("sid=%llu", tsip_ssession_get_id(session->handle));
+ /* Type */
+ printf(" type=");
+ switch(session->type){
+ case st_invite:
+ printf("INVITE");
+ break;
+ case st_message:
+ printf("MESSAGE");
+ break;
+ case st_publish:
+ printf("PUBLISH");
+ break;
+ case st_register:
+ printf("REGISTER");
+ break;
+ case st_subscribe:
+ printf("SUBSCRIBE");
+ break;
+ default:
+ printf("(null)");
+ break;
+ }
+ /* From */
+ printf(" from=%s", session->from ? session->from : ctx->identity.impu);
+ /* From */
+ printf(" to=%s", session->to ? session->to : ctx->identity.impu);
+ }
+ else{
+ printf("(invalid)");
+ }
+ printf("\n");
+ return -1;
+}
+
+
+/* handle events -common to all sessions */
+int session_handle_event(const tsip_event_t *_event)
+{
+ const session_t* session;
+
+ /* Find associated session */
+ if(!(session = session_get_by_sid(ctx->sessions, tsip_ssession_get_id(_event->ss)))){
+ /* Silentky ignore */
+ return 0;
+ }
+ switch(_event->code)
+ {
+ /* === 7xx ==> errors === */
+ case tsip_event_code_dialog_transport_error:
+ case tsip_event_code_dialog_global_error:
+ case tsip_event_code_dialog_message_error:
+ /* do not guess that the dialog is terminated, wait for "tsip_event_code_dialog_terminated" event */
+ break;
+
+ /* === 8xx ==> success === */
+ case tsip_event_code_dialog_request_incoming:
+ case tsip_event_code_dialog_request_cancelled:
+ case tsip_event_code_dialog_request_sent:
+ break;
+
+ /* === 9xx ==> Informational === */
+ case tsip_event_code_dialog_terminated:
+ { /* we no longer need the session
+ * -> remove and destroy the session */
+ TSK_DEBUG_INFO("Dialog Terminated --> %s", _event->phrase);
+ tsk_list_remove_item_by_data(ctx->sessions, session);
+ break;
+ }
+
+ case tsip_event_code_dialog_connected:
+ ((session_t*)session)->connected = tsk_true;
+ break;
+ case tsip_event_code_dialog_terminating:
+ break;
+ }
+ return 0;
+}
+
+/* handle commands -common to all sessions */
+const session_t* session_handle_cmd(cmd_type_t cmd, const opts_L_t* opts)
+{
+ const session_t* session = tsk_null;
+ const opt_t* opt;
+ const tsk_list_item_t* item;
+ tsk_param_t* param;
+ int ret = 0;
+
+ /* Check if there is a session with is Id */
+ if((opt = opt_get_by_type(opts, opt_sid))){
+ tsip_ssession_id_t sid = atoi(opt->value);
+ session = session_get_by_sid(ctx->sessions, sid);
+ }
+
+#define TYPE_FROM_CMD(_CMD) \
+ ((_CMD==cmd_audio || _CMD==cmd_video || _CMD==cmd_audiovideo || _CMD==cmd_file || _CMD==cmd_large_message) ? st_invite : \
+ ((_CMD==cmd_message || _CMD==cmd_sms) ? st_message : \
+ (_CMD==cmd_options ? st_options : \
+ (_CMD==cmd_publish ? st_publish : \
+ (_CMD==cmd_register ? st_register : \
+ (_CMD==cmd_subscribe ? st_subscribe : st_none))))))
+
+ /* === Command === */
+ switch(cmd){
+ case cmd_audio: case cmd_video: case cmd_audiovideo: case cmd_file: case cmd_large_message:
+ case cmd_message:
+ case cmd_sms:
+ case cmd_options:
+ case cmd_publish:
+ case cmd_register:
+ case cmd_subscribe:
+ {
+ if(!session){ /* Create "client-side-session" */
+ session_t* _session;
+ if((_session = session_client_create(TYPE_FROM_CMD(cmd))) && (session = _session)){
+ tsk_list_push_back_data(ctx->sessions, (void**)&_session);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if(session){
+ /* hold, resume, refer, update, ...all in-dialog commands */
+ break;
+ }
+ else{
+ TSK_DEBUG_WARN("Session handling: Cannot handle this command [%d]", cmd);
+ goto bail;
+ }
+ }
+ } /* switch */
+
+ if(!session){
+ TSK_DEBUG_ERROR("SIP Session is Null");
+ goto bail;
+ }
+
+ /* === User Options === */
+ tsk_list_foreach(item, opts){
+ opt = item->data;
+
+ /* Session-level option? */
+ if(opt->lv != lv_none && opt->lv != lv_session){
+ continue;
+ }
+
+ switch(opt->type){
+ case opt_caps:
+ {
+ if(!tsk_strnullORempty(opt->value)){
+ if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))){
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_CAPS(param->name, param->value),
+ TSIP_SSESSION_SET_NULL());
+ TSK_OBJECT_SAFE_FREE(param);
+ }
+ }
+ break;
+ }
+ case opt_expires:
+ {
+ if(!tsk_strnullORempty(opt->value)){
+ unsigned expires = atoi(opt->value);
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_EXPIRES(expires),
+ TSIP_SSESSION_SET_NULL());
+ }
+ break;
+ }
+ case opt_from:
+ { /* You should use TSIP_SSESSION_SET_OPTION(TSIP_SSESSION_OPTION_FROM, value)
+ instead of TSIP_SSESSION_SET_HEADER() to set the destination URI. */
+ break;
+ }
+ case opt_header:
+ {
+ if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))){
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_HEADER(param->name, param->value),
+ TSIP_SSESSION_SET_NULL());
+ TSK_OBJECT_SAFE_FREE(param);
+ }
+ break;
+ }
+ case opt_payload:
+ { /* Will be handled by the caller */
+ break;
+ }
+ case opt_silent:
+ { /* valueless option */
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_SILENT_HANGUP(tsk_true),
+ TSIP_SSESSION_SET_NULL());
+ break;
+ }
+ case opt_sigcomp_id:
+ { /* sigcomp-id */
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_SIGCOMP_COMPARTMENT(opt->value),
+ TSIP_SSESSION_SET_NULL());
+ break;
+ }
+ case opt_to:
+ { /* You should use TSIP_SSESSION_SET_OPTION(TSIP_SSESSION_OPTION_TO, value)
+ instead of TSIP_SSESSION_SET_HEADER() to set the destination URI. */
+ if((cmd != cmd_sms) && (cmd != cmd_ect) && !tsk_strnullORempty(opt->value)){ /* SMS will use SMSC Address as Request URI */
+ ret = tsip_ssession_set(session->handle,
+ TSIP_SSESSION_SET_TO(opt->value),
+ TSIP_SSESSION_SET_NULL());
+ }
+ break;
+ }
+ default:
+ {
+ /* will be handled by the caller */
+ break;
+ }
+ }
+
+ } /* foreach */
+
+bail:
+ return session;
+}
+
+int session_hangup(tsip_ssession_id_t sid)
+{
+ const session_t* session;
+ if((session = session_get_by_sid(ctx->sessions, sid))){
+ switch(session->type){
+ case st_invite:
+ tsip_action_BYE(session->handle,
+ /* You can add your parameters */
+ TSIP_ACTION_SET_NULL());
+ break;
+ case st_message:
+ break;
+ case st_publish:
+ tsip_action_UNPUBLISH(session->handle,
+ /* You can add your parameters */
+ TSIP_ACTION_SET_NULL());
+ break;
+ case st_register:
+ tsip_action_UNREGISTER(session->handle,
+ /* You can add your parameters */
+ TSIP_ACTION_SET_NULL());
+ break;
+ case st_subscribe:
+ tsip_action_UNSUBSCRIBE(session->handle,
+ /* You can add your parameters */
+ TSIP_ACTION_SET_NULL());
+ break;
+ default:
+ TSK_DEBUG_WARN("Cannot hangup session with this type [%d]", session->type);
+ return -2;
+ }
+ return 0;
+ }
+ else{
+ TSK_DEBUG_WARN("Failed to find session with sid=%llu", sid);
+ return -1;
+ }
+}
+
+static tsk_object_t* session_ctor(tsk_object_t * self, va_list * app)
+{
+ session_t *session = self;
+ if(session){
+ session->type = va_arg(*app, session_type_t);
+ if((session->handle = va_arg(*app, tsip_ssession_handle_t*))){
+ int ret;
+ /* "server-side-session" */
+ if((ret = tsip_ssession_take_ownership(session->handle))){
+ TSK_DEBUG_ERROR("Failed to take ownership [%d]", ret);
+ }
+ }
+ else{
+ /* "client-side-session" */
+ session->handle = tsip_ssession_create(ctx->stack,
+ TSIP_SSESSION_SET_NULL());
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* session_dtor(tsk_object_t * self)
+{
+ session_t *session = self;
+ if(session){
+ TSK_OBJECT_SAFE_FREE(session->handle);
+
+ TSK_FREE(session->to);
+ TSK_FREE(session->from);
+ }
+
+ return self;
+}
+
+static int session_cmp(const tsk_object_t *_ss1, const tsk_object_t *_ss2)
+{
+ const session_t *ss1 = _ss1;
+ const session_t *ss2 = _ss2;
+
+ if(ss1 && ss1){
+ if(ss1->handle && ss2->handle){
+ return tsk_object_cmp(ss1->handle, ss2->handle);
+ }
+ else{
+ return (ss2 - ss1);
+ }
+ }
+ else if(!ss1 && !ss2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t session_def_s =
+{
+ sizeof(session_t),
+ session_ctor,
+ session_dtor,
+ session_cmp,
+};
+const tsk_object_def_t *session_def_t = &session_def_s;
+
+
+
+tsip_action_handle_t* action_get_config(const opts_L_t* opts)
+{
+ const opt_t* opt;
+ const tsk_list_item_t* item;
+ tsip_action_handle_t* action_config = tsk_null;
+ tsk_param_t* param;
+
+ if(TSK_LIST_IS_EMPTY(opts)){
+ return tsk_null;
+ }
+
+ tsk_list_foreach(item, opts){
+ opt = item->data;
+
+ /* action level? */
+ if(opt->lv != lv_action){
+ continue;
+ }
+
+ /* create new action */
+ if(!action_config && !(action_config = tsip_action_create(tsip_atype_config,
+ TSIP_ACTION_SET_NULL()))) break;
+
+ switch(opt->type){
+ case opt_header:
+ {
+ if((param = tsk_params_parse_param(opt->value, tsk_strlen(opt->value)))){
+ tsip_action_set(action_config,
+ TSIP_ACTION_SET_HEADER(param->name, param->value),
+ TSIP_ACTION_SET_NULL());
+ TSK_OBJECT_SAFE_FREE(param);
+ }
+ break;
+ }
+ case opt_payload:
+ {
+ tsip_action_set(action_config,
+ TSIP_ACTION_SET_PAYLOAD(opt->value, tsk_strlen(opt->value)),
+ TSIP_ACTION_SET_NULL());
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ return action_config;
+}
OpenPOWER on IntegriCloud