mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
741 lines
18 KiB
741 lines
18 KiB
/*
|
|
* $Id: AmSession.cpp,v 1.42.2.10 2005/09/02 13:47:46 rco Exp $
|
|
*
|
|
* Copyright (C) 2002-2003 Fhg Fokus
|
|
*
|
|
* This file is part of sems, a free SIP media server.
|
|
*
|
|
* sems 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 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* For a license to use the ser software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* sems 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "AmServer.h"
|
|
#include "AmSession.h"
|
|
#include "AmRequest.h"
|
|
#include "AmSdp.h"
|
|
#include "AmMail.h"
|
|
#include "AmConfig.h"
|
|
#include "AmUtils.h"
|
|
#include "AmPlugIn.h"
|
|
#include "AmApi.h"
|
|
// #include "AmRtpScheduler.h"
|
|
#include "AmSessionScheduler.h"
|
|
#include "AmDtmfDetector.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
AmSessionEvent::AmSessionEvent(EventType event_type, const AmRequestUAS& request)
|
|
: AmEvent(int(event_type)), request(request)
|
|
{
|
|
}
|
|
|
|
AmNotifySessionEvent::AmNotifySessionEvent(AmRequestUAS& request)
|
|
: AmSessionEvent(AmSessionEvent::Notify, request),
|
|
body(request.getBody()),
|
|
eventPackage(request.cmd.getHeader("Event")),
|
|
subscriptionState(request.cmd.getHeader("Subscription-State")),
|
|
contentType(request.cmd.getHeader("Content-Type")),
|
|
contentLength(request.cmd.getHeader("Content-Length")),
|
|
cseq(request.cmd.cseq)
|
|
{
|
|
}
|
|
|
|
// AmSession methods
|
|
|
|
AmSession::AmSession(AmRequest* _req, AmDialogState* _d_st)
|
|
: req(_req),dialog_st(_d_st),detached(true),
|
|
sess_stopped(false),rtp_str(this),first_negotiation(true),
|
|
input(0), output(0),
|
|
m_dtmfEventQueue(new AmDtmfDetector(this)),
|
|
m_dtmfDetectionEnabled(true),
|
|
m_dtmfOutputQueue(new AmDtmfHandler(this))
|
|
{
|
|
}
|
|
|
|
AmSession::~AmSession()
|
|
{
|
|
}
|
|
|
|
void AmSession::setInput(AmAudio* in)
|
|
{
|
|
lockAudio();
|
|
input = in;
|
|
unlockAudio();
|
|
}
|
|
|
|
void AmSession::setOutput(AmAudio* out)
|
|
{
|
|
lockAudio();
|
|
output = out;
|
|
unlockAudio();
|
|
}
|
|
|
|
void AmSession::setInOut(AmAudio* in,AmAudio* out)
|
|
{
|
|
lockAudio();
|
|
input = in;
|
|
output = out;
|
|
unlockAudio();
|
|
}
|
|
|
|
void AmSession::lockAudio()
|
|
{
|
|
audio_mut.lock();
|
|
}
|
|
|
|
void AmSession::unlockAudio()
|
|
{
|
|
audio_mut.unlock();
|
|
}
|
|
|
|
// void AmSession::onIdle()
|
|
// {
|
|
// dialog_st->processEvents();
|
|
// }
|
|
|
|
const string& AmSession::getCallID()
|
|
{
|
|
return req->cmd.callid;
|
|
}
|
|
|
|
const string& AmSession::getFromTag()
|
|
{
|
|
return req->cmd.from_tag;
|
|
}
|
|
|
|
const string& AmSession::getToTag()
|
|
{
|
|
return req->cmd.to_tag;
|
|
}
|
|
|
|
AmDialogState* AmSession::getDialogState()
|
|
{
|
|
return dialog_st.get();
|
|
}
|
|
|
|
const SdpPayload* AmSession::getPayload()
|
|
{
|
|
return payload;
|
|
}
|
|
|
|
int AmSession::getRPort()
|
|
{
|
|
return rtp_str.getRPort();
|
|
}
|
|
|
|
void AmSession::negotiate(AmRequest* request)
|
|
{
|
|
string r_host = "";
|
|
int r_port = 0;
|
|
|
|
if(request->sdp.parse())
|
|
throw AmSession::Exception(400,"session description parsing failed");
|
|
|
|
if(request->sdp.media.empty())
|
|
throw AmSession::Exception(400,"no media line found in SDP message");
|
|
|
|
SdpPayload* tmp_pl = request->sdp.getCompatiblePayload(MT_AUDIO,r_host,r_port);
|
|
|
|
if(!tmp_pl)
|
|
throw AmSession::Exception(606,"could not find compatible payload");
|
|
|
|
if(first_negotiation){
|
|
payload = tmp_pl;
|
|
}
|
|
else if(payload->int_pt != tmp_pl->int_pt)
|
|
throw AmSession::Exception(400,"do not accept payload changes");
|
|
|
|
const SdpPayload *telephone_event_payload = request->sdp.telephoneEventPayload();
|
|
if(telephone_event_payload)
|
|
{
|
|
DBG("remote party supports telephone events (pt=%i)\n",
|
|
telephone_event_payload->payload_type);
|
|
rtp_str.setTelephoneEventPT(telephone_event_payload);
|
|
}
|
|
else {
|
|
DBG("remote party doesn't support telephone events\n");
|
|
}
|
|
|
|
string str_msg_flags = request->cmd.getHeader("P-MsgFlags");
|
|
unsigned int msg_flags;
|
|
if(reverse_hex2int(str_msg_flags,msg_flags)){
|
|
ERROR("while parsing 'P-MsgFlags' header\n");
|
|
msg_flags = 0;
|
|
}
|
|
DBG("msg_flags=%u\n",msg_flags);
|
|
|
|
bool passive_mode = false;
|
|
if( request->sdp.remote_active
|
|
|| (msg_flags & FL_FORCE_ACTIVE) ) {
|
|
DBG("The other UA is NATed: switched to passive mode.\n");
|
|
DBG("remote_active = %i; msg_flags = %i\n",
|
|
request->sdp.remote_active,msg_flags);
|
|
passive_mode = true;
|
|
}
|
|
|
|
if(!request->getReplied()){
|
|
|
|
//TODO: if dialog started
|
|
if(first_negotiation)
|
|
dialog_st->onBeforeCallAccept(request);
|
|
|
|
if (sess_stopped.get()) /* session still alive ? */
|
|
return;
|
|
|
|
rtp_str.setLocalIP(request->cmd.dstip);
|
|
request->accept(rtp_str.getLocalPort());
|
|
}
|
|
|
|
rtp_str.setPassiveMode(passive_mode);
|
|
rtp_str.setRAddr(r_host, r_port);
|
|
DBG("Sending Rtp data to %s/%i\n",r_host.c_str(),r_port);
|
|
|
|
first_negotiation = false;
|
|
}
|
|
|
|
void AmSession::run()
|
|
{
|
|
if(dialog_st.get()){
|
|
|
|
try {
|
|
try {
|
|
// handle INVITE negotiation
|
|
negotiate(req.get());
|
|
|
|
if(sess_stopped.get()){
|
|
destroy();
|
|
return;
|
|
}
|
|
|
|
// enable RTP stream
|
|
rtp_str.init(payload);
|
|
//rtp_str.trace(true,getCallID());
|
|
dialog_st->onSessionStart(req.get());
|
|
|
|
AmSessionScheduler::instance()->addSession(this);
|
|
|
|
while (!sess_stopped.get()){
|
|
DBG("dialog_st->waitForEvent()\n");
|
|
dialog_st->waitForEvent();
|
|
DBG("dialog_st->processEvents()\n");
|
|
dialog_st->processEvents();
|
|
}
|
|
}
|
|
catch(const AmSession::Exception& e){ throw e; }
|
|
catch(const string& str){
|
|
ERROR("%s\n",str.c_str());
|
|
throw AmSession::Exception(500,"unexpected exception.");
|
|
}
|
|
catch(...){
|
|
throw AmSession::Exception(500,"unexpected exception.");
|
|
}
|
|
}
|
|
catch(const AmSession::Exception& e){
|
|
ERROR("%i %s\n",e.code,e.reason.c_str());
|
|
dialog_st->onError(e.code,e.reason);
|
|
req->error(e.code,e.reason);
|
|
}
|
|
}
|
|
|
|
destroy();
|
|
|
|
// wait at least until session is out of RtpScheduler
|
|
DBG("session is stopped, waiting for detach from SessionScheduler.\n");
|
|
detached.wait_for();
|
|
}
|
|
|
|
void AmSession::on_stop()
|
|
{
|
|
//sess_stopped.set(true);
|
|
DBG("AmSession::on_stop()\n");
|
|
AmSessionScheduler::instance()->removeSession(this);
|
|
}
|
|
|
|
void AmSession::destroy()
|
|
{
|
|
DBG("AmSession::destroy()\n");
|
|
AmSessionContainer::instance()->destroySession(this);
|
|
}
|
|
|
|
string AmSession::getNewId()
|
|
{
|
|
return int2hex(getpid()) + int2hex(rand());
|
|
}
|
|
|
|
void AmSession::postDtmfEvent(AmDtmfEvent *evt)
|
|
{
|
|
if (m_dtmfDetectionEnabled)
|
|
{
|
|
if (dynamic_cast<AmSipDtmfEvent *>(evt) ||
|
|
// dynamic_cast<AmInbandDtmfEvent *>(evt) ||
|
|
dynamic_cast<AmRtpDtmfEvent *>(evt))
|
|
{
|
|
m_dtmfEventQueue.postEvent(evt);
|
|
}
|
|
else
|
|
{
|
|
m_dtmfOutputQueue.postEvent(evt);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AmSession::processDtmfEvents()
|
|
{
|
|
if (m_dtmfDetectionEnabled)
|
|
{
|
|
m_dtmfEventQueue.processEvents();
|
|
m_dtmfOutputQueue.processEvents();
|
|
}
|
|
}
|
|
|
|
void AmSession::putDtmfAudio(const unsigned char *buf, int size, int user_ts)
|
|
{
|
|
m_dtmfEventQueue.putDtmfAudio(buf, size, user_ts);
|
|
}
|
|
|
|
void AmSession::onDtmf(int event, int duration_msec)
|
|
{
|
|
if (dialog_st.get())
|
|
dialog_st->onDtmf(event, duration_msec);
|
|
}
|
|
|
|
void AmSession::clearAudio()
|
|
{
|
|
lockAudio();
|
|
if(input){
|
|
input->close();
|
|
input = 0;
|
|
}
|
|
if(output){
|
|
output->close();
|
|
output = 0;
|
|
}
|
|
unlockAudio();
|
|
DBG("Audio cleared !!!\n");
|
|
dialog_st->postEvent(new AmAudioEvent(AmAudioEvent::cleared));
|
|
}
|
|
|
|
// AmSessionContainer methods
|
|
|
|
AmSessionContainer* AmSessionContainer::_SessionContainer=0;
|
|
|
|
AmSessionContainer::AmSessionContainer()
|
|
: _run_cond(false)
|
|
{
|
|
}
|
|
|
|
AmSessionContainer* AmSessionContainer::instance()
|
|
{
|
|
if(!_SessionContainer)
|
|
_SessionContainer = new AmSessionContainer();
|
|
|
|
return _SessionContainer;
|
|
}
|
|
|
|
void AmSessionContainer::on_stop()
|
|
{
|
|
}
|
|
|
|
void AmSessionContainer::run()
|
|
{
|
|
int seed=0;
|
|
FILE* fp_rand = fopen("/dev/random","r");
|
|
if(fp_rand){
|
|
fread(&seed,sizeof(int),1,fp_rand);
|
|
fclose(fp_rand);
|
|
}
|
|
seed += getpid();
|
|
seed += time(0);
|
|
srand(seed);
|
|
|
|
while(1){
|
|
|
|
_run_cond.wait_for();
|
|
|
|
// Let some time for the Sessions
|
|
// to stop by themselves
|
|
sleep(5);
|
|
|
|
ds_mut.lock();
|
|
DBG("Session cleaner starting its work\n");
|
|
|
|
try {
|
|
SessionQueue n_sessions;
|
|
|
|
while(!d_sessions.empty()){
|
|
|
|
AmSession* cur_session = d_sessions.front();
|
|
d_sessions.pop();
|
|
|
|
ds_mut.unlock();
|
|
|
|
if(cur_session->getStopped()){
|
|
delete cur_session;
|
|
DBG("session %ld has been destroyed'\n",(unsigned long int)cur_session->_pid);
|
|
}
|
|
else {
|
|
DBG("session %ld still running\n",(unsigned long int)cur_session->_pid);
|
|
n_sessions.push(cur_session);
|
|
}
|
|
|
|
ds_mut.lock();
|
|
}
|
|
|
|
swap(d_sessions,n_sessions);
|
|
|
|
}catch(std::exception& e){
|
|
ERROR("exception caught in session cleaner: %s\n", e.what());
|
|
throw; /* throw again as this is fatal (because unlocking the mutex fails!! */
|
|
}catch(...){
|
|
ERROR("unknown exception caught in session cleaner!\n");
|
|
throw; /* throw again as this is fatal (because unlocking the mutex fails!! */
|
|
}
|
|
|
|
bool more = !d_sessions.empty();
|
|
ds_mut.unlock();
|
|
|
|
DBG("Session cleaner finished\n");
|
|
if(!more)
|
|
_run_cond.set(false);
|
|
}
|
|
}
|
|
|
|
void AmSessionContainer::stopAndQueue(AmSession* s)
|
|
{
|
|
ds_mut.lock();
|
|
|
|
DBG("session cleaner trying to stop %ld\n",(unsigned long int)s->_pid);
|
|
s->stop();
|
|
d_sessions.push(s);
|
|
_run_cond.set(true);
|
|
|
|
ds_mut.unlock();
|
|
}
|
|
|
|
void AmSessionContainer::destroySession(AmSession* s)
|
|
{
|
|
string hash_str = string(s->getCallID()) + string(s->getFromTag());
|
|
string to_tag = s->getToTag();
|
|
sadSession(hash_str,to_tag);
|
|
}
|
|
|
|
bool AmSessionContainer::sadSession(const string& hash_str, string& sess_key)
|
|
{
|
|
bool ret;
|
|
as_mut.lock();
|
|
try {
|
|
DBG("searching for session to destroy (hash=%s,sess_key=%s)\n",hash_str.c_str(),sess_key.c_str());
|
|
pair<SessionMapIter,SessionTableIter> sess_pair = findSession(hash_str,sess_key);
|
|
ret = (sess_pair.first != a_sessions.end())
|
|
&& (sess_pair.second != sess_pair.first->second.end());
|
|
destroySession(sess_pair,true);
|
|
}catch(...){
|
|
ERROR("unexpected exception\n");
|
|
}
|
|
as_mut.unlock();
|
|
return ret;
|
|
}
|
|
|
|
void AmSessionContainer::destroySession(pair<SessionMapIter,SessionTableIter>& sess_pair, bool sessionsAreLocked)
|
|
{
|
|
if (!sessionsAreLocked) as_mut.lock();
|
|
|
|
try {
|
|
SessionMapIter sess_it = sess_pair.first;
|
|
SessionTableIter it = sess_pair.second;
|
|
|
|
if(sess_it != a_sessions.end()){
|
|
|
|
DBG("sess_it != a_sessions.end()\n");
|
|
if(it != sess_it->second.end()){
|
|
|
|
DBG("it != sess_it->second.end()\n");
|
|
|
|
AmSession* am_sess = it->second;
|
|
sess_it->second.erase(it);
|
|
if(!sess_it->second.size())
|
|
a_sessions.erase(sess_it);
|
|
|
|
DBG("session found: stopping session\n");
|
|
stopAndQueue(am_sess);
|
|
DBG("session stopped and destroyed (#sessions=%li)\n",a_sessions.size());
|
|
}
|
|
else {
|
|
DBG("it == sess_it->second.end()\n");
|
|
}
|
|
}
|
|
else {
|
|
DBG("sess_it == sessions.end()\n");
|
|
}
|
|
}catch(...){
|
|
ERROR("unexpected exception\n");
|
|
}
|
|
|
|
if (!sessionsAreLocked) as_mut.unlock();
|
|
}
|
|
|
|
|
|
AmSessionContainer::SessionSearchRes
|
|
AmSessionContainer::findSession(const string& hash_str, string& sess_key)
|
|
{
|
|
SessionTableIter it;
|
|
SessionMapIter sess_it = a_sessions.find(hash_str);
|
|
|
|
if(sess_it != a_sessions.end()){
|
|
|
|
if(sess_key.length()){
|
|
|
|
for(it=sess_it->second.begin();it!=sess_it->second.end();++it){
|
|
|
|
if(it->first == sess_key){
|
|
DBG("session found with key\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(!sess_it->second.empty()){
|
|
DBG("sess_key is null: using the last session key\n");
|
|
it = sess_it->second.end()-1;
|
|
sess_key = it->first;
|
|
}
|
|
else
|
|
it = sess_it->second.end();
|
|
}
|
|
|
|
return make_pair(sess_it,it);
|
|
}
|
|
|
|
AmSession* AmSessionContainer::getSession(const string& hash_str, string& sess_key)
|
|
{
|
|
pair<SessionMapIter,SessionTableIter> sess_pair = findSession(hash_str,sess_key);
|
|
|
|
if( (sess_pair.first != a_sessions.end())
|
|
&& (sess_pair.second != sess_pair.first->second.end()) ){
|
|
|
|
return sess_pair.second->second;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
AmSession* AmSessionContainer::getSession(string& sess_key)
|
|
{
|
|
// search through every session
|
|
for (SessionMapIter map_it = a_sessions.begin();
|
|
map_it != a_sessions.end(); map_it++) {
|
|
SessionTableIter sess_it = map_it->second.begin();
|
|
// search session within vector of sess_key,amsession*
|
|
while (sess_it != map_it->second.end()) {
|
|
if (sess_it->first == sess_key)
|
|
break;
|
|
sess_it++;
|
|
}
|
|
|
|
if (sess_it != map_it->second.end()) {
|
|
DBG("session found with key '%s'\n", sess_key.c_str());
|
|
return sess_it->second;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void AmSessionContainer::startSession(const string& hash_str, string& sess_key,
|
|
AmRequestUAS* req)
|
|
{
|
|
as_mut.lock();
|
|
try {
|
|
|
|
AmSession* session = AmSessionContainer::getSession(hash_str,sess_key);
|
|
if( session ){
|
|
|
|
DBG("AmSessionContainer: session already exists.\n");
|
|
// Session already exists...
|
|
if(!req->cmd.to_tag.empty()){
|
|
// ...it's a RE-INVITE
|
|
AmDialogState* state = session->getDialogState();
|
|
assert(state);
|
|
state->postEvent(new AmSessionEvent(AmSessionEvent::ReInvite,
|
|
*req));
|
|
}
|
|
else {
|
|
req->cmd.to_tag = session->req->cmd.to_tag;
|
|
// it's a forked-and-merged INVITE
|
|
// reply 482 Loop detected
|
|
throw AmSession::Exception(482, "Loop detected");
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Call-ID and From-Tag are unknown: it's a new session
|
|
|
|
sess_key = AmSession::getNewId();
|
|
AmSession* session = createSession(req->cmd.cmd,req);
|
|
|
|
if(session && !addSession(hash_str,sess_key,session)){
|
|
DBG( "Starting session... (hash=%s,sess_key=%s)\n",
|
|
hash_str.c_str(),req->cmd.to_tag.c_str());
|
|
session->start();
|
|
}
|
|
else
|
|
throw AmSession::Exception(500,"internal error");
|
|
}
|
|
}
|
|
catch(const AmSession::Exception& e){
|
|
ERROR("%i %s\n",e.code,e.reason.c_str());
|
|
req->reply(e.code,e.reason);
|
|
}
|
|
catch(const string& err){
|
|
ERROR("startSession: %s\n",err.c_str());
|
|
req->reply(500,err);
|
|
}
|
|
catch(...){
|
|
ERROR("unexpected exception\n");
|
|
}
|
|
as_mut.unlock();
|
|
}
|
|
|
|
// just a wrapper
|
|
bool AmSessionContainer::postEvent(const string& hash_str,string& sess_key,
|
|
AmSessionEvent* event)
|
|
{
|
|
return postGenericEvent(hash_str, sess_key, event);
|
|
}
|
|
|
|
// bool AmSessionContainer::postEvent(const string& hash_str,string& sess_key,
|
|
// AmSessionEvent* event)
|
|
// {
|
|
// bool ret = false;
|
|
// as_mut.lock();
|
|
// try {
|
|
// AmSession* session = AmSessionContainer::getSession(hash_str,sess_key);
|
|
// if( session ){
|
|
// AmDialogState* state = session->getDialogState();
|
|
// assert(state);
|
|
// state->postEvent(event);
|
|
// ret = true;
|
|
// }
|
|
// } catch(...){
|
|
// ERROR("unexpected exception\n");
|
|
// }
|
|
// as_mut.unlock();
|
|
// return ret;
|
|
// }
|
|
|
|
bool AmSessionContainer::postGenericEvent(const string& hash_str,string& sess_key,
|
|
AmEvent* event) {
|
|
bool ret = false;
|
|
|
|
if (hash_str == DAEMON_TYPE_ID) {
|
|
daemon_map_mutex.lock();
|
|
DaemonMap::iterator it = daemon_map.find(sess_key);
|
|
if (it != daemon_map.end()) {
|
|
it->second->postEvent(event);
|
|
ret = true;
|
|
} else
|
|
ERROR("unable to find daemon with name '%s'\n", sess_key.c_str());
|
|
|
|
daemon_map_mutex.unlock();
|
|
return ret;
|
|
}
|
|
|
|
as_mut.lock();
|
|
try {
|
|
AmSession* session = AmSessionContainer::getSession(hash_str,sess_key);
|
|
if( session ){
|
|
AmDialogState* state = session->getDialogState();
|
|
assert(state);
|
|
state->postEvent(event);
|
|
ret = true;
|
|
}
|
|
} catch(...){
|
|
ERROR("unexpected exception\n");
|
|
}
|
|
as_mut.unlock();
|
|
return ret;
|
|
}
|
|
|
|
bool AmSessionContainer::postGenericEvent(string& sess_key, AmEvent* event) {
|
|
bool ret = false;
|
|
as_mut.lock();
|
|
try {
|
|
AmSession* session = AmSessionContainer::getSession(sess_key);
|
|
if( session ){
|
|
AmDialogState* state = session->getDialogState();
|
|
assert(state);
|
|
state->postEvent(event);
|
|
ret = true;
|
|
}
|
|
} catch(...){
|
|
ERROR("unexpected exception\n");
|
|
}
|
|
as_mut.unlock();
|
|
return ret;
|
|
}
|
|
|
|
void AmSessionContainer::registerDaemon(const string& daemon_name, AmEventQueue* event_queue) {
|
|
if (!event_queue) {
|
|
ERROR("trying to register non existing event queue with Session Container");
|
|
}
|
|
DBG("registering daemon with name '%s' as event receiver.\n", daemon_name.c_str());
|
|
daemon_map_mutex.lock();
|
|
daemon_map[daemon_name] = event_queue;
|
|
daemon_map_mutex.unlock();
|
|
}
|
|
|
|
AmSession* AmSessionContainer::createSession(const string& app_name, AmRequest* req)
|
|
{
|
|
AmStateFactory* state_factory = AmPlugIn::instance()->getFactory4App(app_name);
|
|
if(!state_factory) {
|
|
ERROR("application '%s' not found !", app_name.c_str());
|
|
throw string("application '" + app_name + "' not found !");
|
|
}
|
|
|
|
AmDialogState* st = state_factory->onInvite(req->cmd);
|
|
if(!st) {
|
|
// State creation failed:
|
|
// application denied session creation
|
|
// or there was an error.
|
|
//
|
|
// let's hope the createState function has replied...
|
|
// ... and do nothing !
|
|
|
|
DBG("onInvite returned NULL\n");
|
|
return 0;
|
|
}
|
|
|
|
// create a new session
|
|
st->state_factory = state_factory;
|
|
AmSession* session = new AmSession(req->duplicate(),st);
|
|
st->session = session;
|
|
return session;
|
|
}
|
|
|
|
bool AmSessionContainer::addSession(const string& hash_str,const string& sess_key,
|
|
AmSession* session)
|
|
{
|
|
SessionMapIter sess_it = a_sessions.find(hash_str);
|
|
bool ret = sess_it != a_sessions.end();
|
|
a_sessions[hash_str].push_back(make_pair(sess_key,session));
|
|
return ret;
|
|
}
|