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.
sems/apps/dsm/mods/mod_dlg/ModDlg.cpp

295 lines
9.2 KiB

/*
* Copyright (C) 2008 iptego GmbH
*
* 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. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS 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 "ModDlg.h"
#include "log.h"
#include "AmUtils.h"
#include "DSMSession.h"
#include "AmSession.h"
#include "AmB2BSession.h"
#include <string.h>
#include "AmSipHeaders.h"
#include "AmUAC.h"
#include "ampi/UACAuthAPI.h"
SC_EXPORT(MOD_CLS_NAME);
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
DEF_CMD("dlg.reply", DLGReplyAction);
DEF_CMD("dlg.replyRequest", DLGReplyRequestAction);
DEF_CMD("dlg.acceptInvite", DLGAcceptInviteAction);
DEF_CMD("dlg.bye", DLGByeAction);
DEF_CMD("dlg.connectCalleeRelayed", DLGConnectCalleeRelayedAction);
DEF_CMD("dlg.dialout", DLGDialoutAction);
} MOD_ACTIONEXPORT_END;
MOD_CONDITIONEXPORT_NONE(MOD_CLS_NAME);
bool DLGModule::onInvite(const AmSipRequest& req, DSMSession* sess) {
// save inivital invite to last_req
// todo: save this in avar
sess->last_req.reset(new AmSipRequest(req));
return true;
}
// todo: convert errors to exceptions
void replyRequest(DSMSession* sc_sess, AmSession* sess,
EventParamT* event_params,
const string& par1, const string& par2,
const AmSipRequest& req) {
string code = resolveVars(par1, sess, sc_sess, event_params);
string reason = resolveVars(par2, sess, sc_sess, event_params);
unsigned int code_i;
if (str2i(code, code_i)) {
ERROR("decoding reply code '%s'\n", code.c_str());
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
return;
}
if (!sc_sess->last_req.get()) {
ERROR("no last request to reply\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("no last request to reply");
return;
}
if (sess->dlg.reply(req, code_i, reason)) {
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("error sending reply");
} else
sc_sess->CLR_ERRNO;
}
CONST_ACTION_2P(DLGReplyAction, ',', true);
EXEC_ACTION_START(DLGReplyAction) {
replyRequest(sc_sess, sess, event_params, par1, par2, *sc_sess->last_req.get());
} EXEC_ACTION_END;
// todo (?) move replyRequest to core module (?)
CONST_ACTION_2P(DLGReplyRequestAction, ',', true);
EXEC_ACTION_START(DLGReplyRequestAction) {
DSMSipRequest* sip_req;
AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
if (it == sc_sess->avar.end() ||
!isArgAObject(it->second) ||
!(sip_req = dynamic_cast<DSMSipRequest*>(it->second.asObject()))) {
throw DSMException("dlg", "cause", "no request");
}
replyRequest(sc_sess, sess, event_params, par1, par2, *sip_req->req);
} EXEC_ACTION_END;
CONST_ACTION_2P(DLGAcceptInviteAction, ',', true);
EXEC_ACTION_START(DLGAcceptInviteAction) {
// defaults to 200 OK
unsigned int code_i=200;
string reason = "OK";
string code = resolveVars(par1, sess, sc_sess, event_params);
DBG("replying with code %s\n", code.c_str());
if (code.length()) {
reason = resolveVars(par2, sess, sc_sess, event_params);
if (str2i(code, code_i)) {
ERROR("decoding reply code '%s'\n", code.c_str());
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("decoding reply code '"+
code+"%s'\n");
return false;
}
}
if (!sc_sess->last_req.get()) {
ERROR("no last request to reply\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("no last request to reply");
return false;
}
try {
string sdp_reply;
sess->acceptAudio(sc_sess->last_req.get()->body,
sc_sess->last_req.get()->hdrs,&sdp_reply);
if(sess->dlg.reply(*sc_sess->last_req.get(),code_i, reason,
"application/sdp",sdp_reply) != 0)
throw AmSession::Exception(500,"could not send response");
}catch(const AmSession::Exception& e){
ERROR("%i %s\n",e.code,e.reason.c_str());
sess->setStopped();
sess->dlg.reply(*sc_sess->last_req.get(),e.code,e.reason);
}
} EXEC_ACTION_END;
EXEC_ACTION_START(DLGByeAction) {
string hdrs = resolveVars(arg, sess, sc_sess, event_params);
if (sess->dlg.bye(hdrs)) {
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("Error sending bye");
} else {
sc_sess->SET_ERRNO(DSM_ERRNO_OK);
}
} EXEC_ACTION_END;
CONST_ACTION_2P(DLGConnectCalleeRelayedAction,',', false);
EXEC_ACTION_START(DLGConnectCalleeRelayedAction) {
string remote_party = resolveVars(par1, sess, sc_sess, event_params);
string remote_uri = resolveVars(par2, sess, sc_sess, event_params);
// if (sc_sess->last_req.get()) {
// sc_sess->B2BaddReceivedRequest(*sc_sess->last_req.get());
// } else {
// WARN("internal error: initial INVITE request missing.\n");
// }
// AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
// if (b2b_sess)
// b2b_sess->set_sip_relay_only(true);
// else
// ERROR("getting B2B session.\n");
sc_sess->B2BconnectCallee(remote_party, remote_uri, true);
} EXEC_ACTION_END;
EXEC_ACTION_START(DLGDialoutAction) {
string arrayname = resolveVars(arg, sess, sc_sess, event_params);
#define GET_VARIABLE_MANDATORY(varname_suffix, outvar) \
it = sc_sess->var.find(arrayname+varname_suffix); \
if (it == sc_sess->var.end()) { \
WARN("%s", std::string("need " + arrayname + varname_suffix " set for dlg.dialoutSimple("+arrayname+")").c_str()); \
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); \
return false; \
} \
outvar = it->second;
#define GET_VARIABLE_OPTIONAL(varname_suffix, outvar) \
it = sc_sess->var.find(arrayname+varname_suffix); \
if (it != sc_sess->var.end()) \
outvar = it->second;
map<string, string>::iterator it;
string v_from;
GET_VARIABLE_MANDATORY("_caller", v_from);
string v_to;
GET_VARIABLE_MANDATORY("_callee", v_to);
string v_domain;
GET_VARIABLE_MANDATORY("_domain", v_domain);
string app_name;
GET_VARIABLE_MANDATORY("_app", app_name);
string user = v_from;
string r_uri = "sip:"+v_to+"@"+v_domain;
GET_VARIABLE_OPTIONAL("_r_uri", r_uri);
string from = "<sip:"+v_from+"@"+v_domain+">";
GET_VARIABLE_OPTIONAL("_from", from);
string from_uri = "sip:"+v_from+"@"+v_domain;
GET_VARIABLE_OPTIONAL("_from_uri", from_uri);
string to = "<sip:"+v_to+"@"+v_domain+">";
GET_VARIABLE_OPTIONAL("_to", to);
string auth_user;
GET_VARIABLE_OPTIONAL("_auth_user", auth_user);
string auth_pwd;
GET_VARIABLE_OPTIONAL("_auth_pwd", auth_pwd);
string ltag;
GET_VARIABLE_OPTIONAL("_ltag", ltag);
string hdrs;
GET_VARIABLE_OPTIONAL("_hdrs", hdrs);
if (hdrs.length()) {
size_t crpos;
while ((crpos=hdrs.find("\\r\\n")) != string::npos) {
hdrs.replace(crpos, 4, "\r\n");
}
}
#undef GET_VARIABLE_MANDATORY
#undef GET_VARIABLE_OPTIONAL
DBG("placing UAC call: user <%s>, app <%s>, ruri <%s>, from <%s> "
"from_uri <%s>, to <%s>, ltag <%s>, hdrs <%s>, auth_user <%s>, auth_pwd <not shown>\n",
user.c_str(), app_name.c_str(), r_uri.c_str(), from.c_str(),
from_uri.c_str(), to.c_str(), ltag.c_str(), hdrs.c_str(), auth_user.c_str());
AmArg* sess_params = new AmArg();
bool has_auth = false;
if (!auth_user.empty() && !auth_pwd.empty()) {
AmArg auth_param;
auth_param.setBorrowedPointer(new UACAuthCred("", auth_user,auth_pwd));
sess_params->push(auth_param);
has_auth = true;
}
AmArg var_struct;
string varprefix = arrayname+"_var.";
bool has_vars = false;
map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
while (lb != sc_sess->var.end()) {
if ((lb->first.length() < varprefix.length()) ||
strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
break;
string varname = lb->first.substr(varprefix.length());
if (!has_auth) // sess_params is variable struct
(*sess_params)[varname] = lb->second;
else // variable struct is in sess_params array
var_struct[varname] = lb->second;
lb++;
has_vars = true;
}
if (has_vars && has_auth)
sess_params->push(var_struct);
DBG("sess_params: '%s'\n", AmArg::print(*sess_params).c_str());
string new_sess_tag = AmUAC::dialout(user, app_name, r_uri, from, from_uri, to, ltag, hdrs, sess_params);
if (!new_sess_tag.empty()) {
sc_sess->var[arrayname + "_ltag"] = new_sess_tag;
} else {
sc_sess->var[arrayname + "_ltag"] = "";
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
}
} EXEC_ACTION_END;