#include "AmInterfaceHandler.h" #include "AmCtrlInterface.h" #include "AmSessionContainer.h" #include "AmServer.h" // FIFO_VERSION #include "AmUtils.h" #include "AmSipRequest.h" #include "AmConfig.h" #include "AmUtils.h" #include "log.h" #include #define SAFECTRLCALL0(fct)\ {\ if(ctrl->fct() == -1){\ ERROR("%s returned -1\n",#fct);\ return -1;\ }\ } #define SAFECTRLCALL1(fct,arg1)\ {\ if(ctrl->fct(arg1) == -1){\ ERROR("%s returned -1\n",#fct);\ return -1;\ }\ } AmInterfaceHandler::~AmInterfaceHandler() {} // // AmRequestHandler methods // static AmRequestHandler _request_handler; AmRequestHandler* AmRequestHandler::get() { return &_request_handler; } int AmRequestHandler::handleRequest(AmCtrlInterface* ctrl) { string version; string fct_name; string cmd; string::size_type pos; SAFECTRLCALL1(getParam,version); if (version == "") { // some odd trailer from previous request -- ignore ERROR("odd trailer\n"); return -1; } if(version != FIFO_VERSION){ ERROR("wrong FIFO Interface version: %s\n",version.c_str()); return -1; } SAFECTRLCALL1(getParam,fct_name); if((pos = fct_name.find('.')) != string::npos){ cmd = fct_name.substr(pos+1,string::npos); fct_name = fct_name.substr(0,pos); } if(fct_name == "sip_request") return execute(ctrl,cmd); AmRequestHandlerFct* fct = getFct(fct_name); if(!fct){ ERROR("unknown request function: '%s'\n",fct_name.c_str()); return -1; } return fct->execute(ctrl,cmd); } int AmRequestHandler::execute(AmCtrlInterface* ctrl, const string& cmd) { AmSipRequest req; if(cmd.empty()){ ERROR("AmRequestHandler::execute: parameter plug-in name missing.\n"); return -1; } //req.cmd = cmd; #define READ_PARAMETER(p)\ {\ SAFECTRLCALL1(getParam,p);\ DBG("%s = <%s>\n",#p,p.c_str());\ } READ_PARAMETER(req.method); READ_PARAMETER(req.user); READ_PARAMETER(req.domain); READ_PARAMETER(req.dstip); // will be taken for UDP's local peer IP & Contact READ_PARAMETER(req.port); // will be taken for Contact READ_PARAMETER(req.r_uri); // ??? will be taken for the answer's Contact header field ??? READ_PARAMETER(req.from_uri); // will be taken for subsequent request uri READ_PARAMETER(req.from); READ_PARAMETER(req.to); READ_PARAMETER(req.callid); READ_PARAMETER(req.from_tag); READ_PARAMETER(req.to_tag); string cseq_str; READ_PARAMETER(cseq_str); if(sscanf(cseq_str.c_str(),"%u", &req.cseq) != 1){ ERROR("invalid cseq number '%s'\n",cseq_str.c_str()); return -1; } DBG("cseq = <%s>(%i)\n",cseq_str.c_str(),req.cseq); READ_PARAMETER(req.key); READ_PARAMETER(req.route); READ_PARAMETER(req.next_hop); #undef READ_PARAMETER SAFECTRLCALL1(getLines,req.hdrs); DBG("hdrs = <%s>\n",req.hdrs.c_str()); req.cmd = cmd; SAFECTRLCALL1(getLines,req.body); DBG("body = <%s>\n",req.body.c_str()); if(req.from.empty() || req.to.empty() || req.callid.empty() || req.from_tag.empty()) { throw string("AmRequestHandler::execute: mandatory parameter " "is empty (from|to|callid|from_tag)\n"); } DBG("Request OK: dispatch it!\n"); dispatch(req); return 0; } // // AmReplyHandler methods // AmReplyHandler* AmReplyHandler::_instance=0; AmReplyHandler::AmReplyHandler(AmCtrlInterface* ctrl) : m_ctrl(ctrl) { } AmReplyHandler* AmReplyHandler::get() { if(!_instance){ AmCtrlInterface* ctrl = AmCtrlInterface::getNewCtrl(); if(ctrl->init(AmConfig::ReplySocketName)){ ERROR("could not initialize the reply socket '%s'\n", AmConfig::ReplySocketName.c_str()); delete ctrl; return NULL; } _instance = new AmReplyHandler(ctrl); } return _instance; } int AmReplyHandler::handleRequest(AmCtrlInterface* ctrl) { AmSipReply reply; string tmp_str; SAFECTRLCALL1(getParam,tmp_str); DBG("response from Ser: %s\n",tmp_str.c_str()); if( parse_return_code(tmp_str.c_str(),// res_code_str, reply.code,reply.reason) == -1 ){ ERROR("while parsing return code from Ser.\n"); //cleanup(ctrl); return -1; } /* Parse complete response: * * [next_request_uri->cmd.from_uri]CRLF * [next_hop->cmd.next_hop]CRLF * [route->cmd.route]CRLF * ([headers->n_cmd.hdrs]CRLF)* * CRLF * ([body->body]CRLF)* */ SAFECTRLCALL1(getParam,reply.next_request_uri); SAFECTRLCALL1(getParam,reply.next_hop); SAFECTRLCALL1(getParam,reply.route); SAFECTRLCALL1(getLines,reply.hdrs); SAFECTRLCALL1(getLines,reply.body); if(reply.hdrs.empty()){ ERROR("reply is missing headers: <%i %s>\n", reply.code,reply.reason.c_str()); return -1; } reply.local_tag = getHeader(reply.hdrs,"From"); reply.local_tag = extract_tag(reply.local_tag); reply.remote_tag = getHeader(reply.hdrs,"To"); reply.remote_tag = extract_tag(reply.remote_tag); string cseq_str; cseq_str = getHeader(reply.hdrs,"CSeq"); if(str2i(cseq_str,reply.cseq)){ ERROR("could not parse CSeq header\n"); return -1; } AmSessionContainer::instance()->postEvent( reply.local_tag, new AmSipReplyEvent(reply)); // if(reply.code >= 200) // cleanup(ctrl); return 0; } AmRequestHandlerFct* AmRequestHandler::getFct(const string& name) { AmRequestHandlerFct* fct=NULL; fct_map_mut.lock(); if(fct_map.find(name) != fct_map.end()) fct = fct_map[name]; fct_map_mut.unlock(); return fct; } void AmRequestHandler::registerFct(const string& name, AmRequestHandlerFct* fct) { fct_map_mut.lock(); fct_map.insert(make_pair(name,fct)); fct_map_mut.unlock(); } void AmRequestHandler::dispatch(AmSipRequest& req) { string callid = req.callid; string remote_tag = req.from_tag; string local_tag = req.to_tag; bool sess_exists; AmSipRequestEvent* ev = new AmSipRequestEvent(req); AmSessionContainer* sess_cont = AmSessionContainer::instance(); if(local_tag.empty()) sess_exists = sess_cont->postEvent(callid,remote_tag,ev); else sess_exists = sess_cont->postEvent(local_tag,ev); if(!sess_exists){ if(req.method == "INVITE"){ sess_cont->startSessionUAS(req); } else { if(!local_tag.empty() || req.method == "CANCEL"){ AmSipDialog::reply_error(req,481,"Call leg/Transaction does not exist"); } else { //TODO: reply some 4xx. ERROR("sorry, we don't support beginning a new session with a '%s' message\n", req.method.c_str()); AmSipDialog::reply_error(req,500,"Not supported here"); return; } } } }