mirror of https://github.com/sipwise/sems.git
git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@165 8eb893ce-cfd4-0310-b710-fb5ebe64c474sayer/1.4-spce2.6
parent
f55194e479
commit
b36cacb45a
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* $Id: AmUtils.h,v 1.18.2.1 2005/08/31 13:54:29 rco Exp $
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
*
|
||||
* 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 "ContactInfo.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool ContactInfo::isEqual(const ContactInfo& c) const {
|
||||
return (uri_user == c.uri_user) &&
|
||||
(!strcasecmp(uri_host.c_str(),
|
||||
c.uri_host.c_str())) &&
|
||||
(uri_port == c.uri_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip display name part
|
||||
*/
|
||||
static inline int skip_name(string& s, unsigned int pos)
|
||||
{
|
||||
size_t i;
|
||||
int last_wsp, quoted = 0;
|
||||
|
||||
for(i = pos; i < s.length(); i++) {
|
||||
char c = s[i];
|
||||
if (!quoted) {
|
||||
if ((c == ' ') || (c == '\t')) {
|
||||
last_wsp = i;
|
||||
} else {
|
||||
if (c == '<') {
|
||||
return i;
|
||||
}
|
||||
|
||||
if (c == '\"') {
|
||||
quoted = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((c == '\"') && (s[i-1] != '\\')) quoted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (quoted) {
|
||||
cout << "ERROR" << "skip_name(): Closing quote missing in name part of Contact\n";
|
||||
} else {
|
||||
cout << "ERROR" << "skip_name(): Error in contact, scheme separator not found\n";
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define ST1 1 /* Basic state */
|
||||
#define ST2 2 /* Quoted */
|
||||
#define ST3 3 /* Angle quoted */
|
||||
#define ST4 4 /* Angle quoted and quoted */
|
||||
#define ST5 5 /* Escape in quoted */
|
||||
#define ST6 6 /* Escape in angle quoted and quoted */
|
||||
|
||||
/*
|
||||
* Skip URI, stops when , (next contact)
|
||||
* or ; (parameter) is found
|
||||
*/
|
||||
static inline int skip_uri(string& s, unsigned int pos)
|
||||
{
|
||||
unsigned int len = s.length() - pos;
|
||||
unsigned int p = pos;
|
||||
|
||||
register int st = ST1;
|
||||
|
||||
while(len) {
|
||||
switch(s[p]) {
|
||||
case ',':
|
||||
case ';':
|
||||
if (st == ST1) return p;
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
switch(st) {
|
||||
case ST1: st = ST2; break;
|
||||
case ST2: st = ST1; break;
|
||||
case ST3: st = ST4; break;
|
||||
case ST4: st = ST3; break;
|
||||
case ST5: st = ST2; break;
|
||||
case ST6: st = ST4; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
switch(st) {
|
||||
case ST1: st = ST3; break;
|
||||
case ST3:
|
||||
cout << "ERROR" << "skip_uri(): Second < found\n";
|
||||
return -1;
|
||||
case ST5: st = ST2; break;
|
||||
case ST6: st = ST4; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
switch(st) {
|
||||
case ST1:
|
||||
cout << "ERROR" << "skip_uri(): > is first\n";
|
||||
return -2;
|
||||
|
||||
case ST3: st = ST1; break;
|
||||
case ST5: st = ST2; break;
|
||||
case ST6: st = ST4; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
switch(st) {
|
||||
case ST2: st = ST5; break;
|
||||
case ST4: st = ST6; break;
|
||||
case ST5: st = ST2; break;
|
||||
case ST6: st = ST4; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
|
||||
}
|
||||
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (st != ST1) {
|
||||
cout << "ERROR" << "skip_uri(): < or \" not closed\n";
|
||||
return -3;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#define uS0 0 // start
|
||||
#define uS1 1 // protocol
|
||||
#define uS2 2 // user / host
|
||||
#define uS3 3 // host
|
||||
#define uS4 4 // port
|
||||
#define uS5 5 // params
|
||||
#define uS6 6 // end
|
||||
/**
|
||||
* parse uri into user, host, port, param
|
||||
*
|
||||
*/
|
||||
bool ContactInfo::parse_uri() {
|
||||
// assuming user@host
|
||||
size_t pos = 0; int st = uS0;
|
||||
size_t p1 = 0;
|
||||
int eq = 0; const char* sip_prot = "SIP:";
|
||||
uri_user = ""; uri_host = ""; uri_port = ""; uri_param = "";
|
||||
|
||||
while (pos<uri.length()) {
|
||||
char c = uri[pos];
|
||||
switch(st) {
|
||||
case uS0: {
|
||||
switch (c) {
|
||||
case '<': { st = uS1; } break;
|
||||
default: {
|
||||
if ((eq<=4)&&(toupper(c) ==sip_prot[eq]))
|
||||
eq++;
|
||||
if (eq==5) { // found sip:
|
||||
st = uS2; p1 = pos;
|
||||
};
|
||||
} break;
|
||||
};
|
||||
} break;
|
||||
case uS1: {
|
||||
if (c == ':') { st = uS2; p1 = pos;}
|
||||
} break;
|
||||
case uS2: {
|
||||
switch(c) {
|
||||
case '@': {
|
||||
uri_user = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS3; p1 = pos;
|
||||
} ; break;
|
||||
case ':': {
|
||||
uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS4; p1 = pos;
|
||||
}; break;
|
||||
case ';': {
|
||||
uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS5; p1 = pos;
|
||||
}; break;
|
||||
case '>': {
|
||||
uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS6; p1 = pos;
|
||||
}; break;
|
||||
}
|
||||
} break;
|
||||
case uS3: {
|
||||
switch (c) {
|
||||
case ':': { uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS4; p1 = pos; }
|
||||
break;
|
||||
case ';': { uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS5; p1 = pos; }
|
||||
break;
|
||||
case '>': { uri_host = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS6; p1 = pos; }
|
||||
break;
|
||||
};
|
||||
} break;
|
||||
case uS4: {
|
||||
switch (c) {
|
||||
case ';': { uri_port = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS5; p1 = pos; }
|
||||
break;
|
||||
case '>': { uri_port = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS6; p1 = pos; }
|
||||
break;
|
||||
};
|
||||
} break;
|
||||
case uS5: {
|
||||
switch (c) {
|
||||
case '>': { uri_param = uri.substr(p1+1, pos-p1-1);
|
||||
st = uS6; p1 = pos; }
|
||||
break;
|
||||
};
|
||||
} break;
|
||||
};
|
||||
pos++;
|
||||
}
|
||||
switch(st) {
|
||||
case uS2:
|
||||
case uS3: uri_host = uri.substr(p1+1, pos-p1-1); break;
|
||||
case uS4: uri_port = uri.substr(p1+1, pos-p1-1); break;
|
||||
case uS5: uri_param = uri.substr(p1+1, pos-p1-1); break;
|
||||
case uS0:
|
||||
case uS1: { cout << "ERROR while parsing uri"; return false; } break;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
#define pS0 0 // start
|
||||
#define pS1 1 // name
|
||||
#define pS2 2 // val
|
||||
/**
|
||||
* parse params int param map
|
||||
*
|
||||
*/
|
||||
bool ContactInfo::parse_params(string& line, int& pos) {
|
||||
size_t p1=pos, p2=pos;
|
||||
int st = 0; int quoted = false;
|
||||
char last_c = ' ';
|
||||
params.clear();
|
||||
while((size_t)pos < line.length()) {
|
||||
char c = line[pos];
|
||||
if (!quoted) {
|
||||
if (c == ',')
|
||||
break;
|
||||
if (c == '\"') {
|
||||
quoted = 1;
|
||||
} else if (c == '=') {
|
||||
p2 = pos; st = pS2;
|
||||
} else if (c == ';') {
|
||||
if ((st == pS2) ||(st == pS1)) {
|
||||
params[line.substr(p1, p2-p1)]
|
||||
= line.substr(p2+1, pos-p2-1);
|
||||
st = pS0;
|
||||
}
|
||||
} else {
|
||||
if (st == pS0) {
|
||||
st = pS1;
|
||||
p1 = pos;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if ((c == '\"') && (last_c != '\\')) quoted = 0;
|
||||
}
|
||||
last_c = c;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (st == pS2)
|
||||
params[line.substr(p1, p2-p1)] = line.substr(p2+1, pos-p2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ContactInfo::parse_contact(string& line, size_t pos, size_t& end) {
|
||||
int p0 = skip_name(line, pos);
|
||||
if (p0 < 0) return false;
|
||||
int p1 = skip_uri(line, p0);
|
||||
if (p1 < 0) return false;
|
||||
uri = line.substr(p0, p1-p0);
|
||||
if (!parse_uri()) return false;
|
||||
parse_params(line, p1);
|
||||
end = p1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContactInfo::dump() {
|
||||
DBG("--- Contact Info --- \n");
|
||||
DBG(" uri '%s'\n", uri.c_str());
|
||||
DBG(" uri_user '%s'\n", uri_user.c_str());
|
||||
DBG(" uri_host '%s'\n", uri_host.c_str());
|
||||
DBG(" uri_port '%s'\n", uri_port.c_str());
|
||||
DBG(" uri_param '%s'\n", uri_param.c_str());
|
||||
for (map<string, string>::iterator it = params.begin();
|
||||
it != params.end(); it++)
|
||||
DBG(" param '%s'='%s'\n", it->first.c_str(), it->second.c_str()) ;
|
||||
DBG("-------------------- \n");
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* $Id: AmUtils.h,v 1.18.2.1 2005/08/31 13:54:29 rco Exp $
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
*
|
||||
* 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 <string>
|
||||
#include <map>
|
||||
using std::map;
|
||||
using std::string;
|
||||
|
||||
struct ContactInfo {
|
||||
string display_name;
|
||||
string uri;
|
||||
|
||||
string uri_user;
|
||||
string uri_host;
|
||||
string uri_port;
|
||||
string uri_param;
|
||||
|
||||
map<string, string> params;
|
||||
|
||||
bool isEqual(const ContactInfo& c) const;
|
||||
bool parse_contact(string& line, size_t pos, size_t& end);
|
||||
bool parse_uri();
|
||||
bool parse_params(string& line, int& pos);
|
||||
void dump();
|
||||
ContactInfo() { }
|
||||
};
|
||||
@ -0,0 +1,7 @@
|
||||
plug_in_name = registrar_client
|
||||
|
||||
module_ldflags =
|
||||
module_cflags =
|
||||
|
||||
COREPATH ?=../../core
|
||||
include $(COREPATH)/plug-in/Makefile.app_module
|
||||
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* $Id: AmApi.h,v 1.9.2.1 2005/06/01 12:00:24 rco Exp $
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
*
|
||||
* 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 "SIPRegistrarClient.h"
|
||||
#include "AmUtils.h"
|
||||
#include "AmPlugIn.h"
|
||||
#include "AmSessionContainer.h"
|
||||
|
||||
#define MOD_NAME "registrar_client"
|
||||
|
||||
#define REGISTER_SEND_TIMEOUT 60
|
||||
|
||||
EXPORT_SIP_EVENT_HANDLER_FACTORY(SIPRegistrarClient, MOD_NAME);
|
||||
EXPORT_PLUGIN_CLASS_FACTORY(SIPRegistrarClient, MOD_NAME);
|
||||
|
||||
|
||||
SIPRegistration::SIPRegistration(const string& handle,
|
||||
const SIPRegistrationInfo& info,
|
||||
const string& sess_link)
|
||||
: info(info),
|
||||
dlg(this),
|
||||
cred(info.domain, info.auth_user, info.pwd),
|
||||
active(false),
|
||||
reg_begin(0),
|
||||
reg_expires(0),
|
||||
remove(false),
|
||||
sess_link(sess_link),
|
||||
reg_send_begin(0)
|
||||
{
|
||||
req.cmd = "sems";
|
||||
req.user = info.user;
|
||||
req.method = "REGISTER";
|
||||
req.dstip = AmConfig::LocalIP;
|
||||
req.r_uri = "sip:"+info.domain;
|
||||
req.from = info.name+" <sip:"+info.user+"@"+info.domain+">";
|
||||
req.from_uri = "sip:"+info.user+"@"+info.domain;
|
||||
req.from_tag = handle;
|
||||
req.to = req.from;
|
||||
req.to_tag = "";
|
||||
req.callid = AmSession::getNewId() + "@" + AmConfig::LocalIP;
|
||||
//
|
||||
|
||||
// clear dlg.callid? ->reregister?
|
||||
dlg.updateStatusFromLocalRequest(req);
|
||||
|
||||
dlg.sip_ip = AmConfig::LocalSIPIP;
|
||||
if (AmConfig::LocalSIPPort)
|
||||
dlg.sip_port = int2str(AmConfig::LocalSIPPort);
|
||||
dlg.cseq = 50;
|
||||
}
|
||||
|
||||
void SIPRegistration::setSessionEventHandler(AmSessionEventHandler* new_seh) {
|
||||
seh = new_seh;
|
||||
}
|
||||
|
||||
void SIPRegistration::doRegistration() {
|
||||
req.to_tag = "";
|
||||
dlg.remote_tag = "";
|
||||
req.r_uri = "sip:"+info.domain;
|
||||
dlg.remote_uri = req.r_uri;
|
||||
dlg.next_hop = "";
|
||||
dlg.sendRequest(req.method, "", "", "Expires: 1000\n");
|
||||
|
||||
// save TS
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
reg_send_begin = now.tv_sec;
|
||||
}
|
||||
|
||||
void SIPRegistration::doUnregister() {
|
||||
req.to_tag = "";
|
||||
dlg.remote_tag = "";
|
||||
req.r_uri = "sip:"+info.domain;
|
||||
dlg.remote_uri = req.r_uri;
|
||||
dlg.next_hop = "";
|
||||
dlg.sendRequest(req.method, "", "", "Expires: 0\n");
|
||||
|
||||
// save TS
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
reg_send_begin = now.tv_sec;
|
||||
}
|
||||
|
||||
void SIPRegistration::onSendRequest(const string& method,
|
||||
const string& content_type,
|
||||
const string& body,
|
||||
string& hdrs,
|
||||
unsigned int cseq) {
|
||||
if (seh)
|
||||
seh->onSendRequest(method, content_type, body,
|
||||
hdrs,cseq);
|
||||
}
|
||||
|
||||
void SIPRegistration::onSendReply(const AmSipRequest& req,
|
||||
unsigned int code,
|
||||
const string& reason,
|
||||
const string& content_type,
|
||||
const string& body,
|
||||
string& hdrs) {
|
||||
if (seh)
|
||||
seh->onSendReply(req,code,reason,
|
||||
content_type,body,hdrs);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
SIPRegistrarClient* SIPRegistrarClient::_instance=0;
|
||||
|
||||
SIPRegistrarClient* SIPRegistrarClient::instance()
|
||||
{
|
||||
if(_instance == NULL){
|
||||
_instance = new SIPRegistrarClient(MOD_NAME);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
SIPRegistrarClient::SIPRegistrarClient(const string& name)
|
||||
: AmSIPEventHandler(name),
|
||||
AmEventQueue(this) ,
|
||||
uac_auth_i(NULL),
|
||||
AmDynInvokeFactory(MOD_NAME)
|
||||
{
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::run() {
|
||||
DBG("SIPRegistrarClient starting...\n");
|
||||
AmDynInvokeFactory* uac_auth_f = AmPlugIn::instance()->getFactory4Di("uac_auth");
|
||||
if (uac_auth_f == NULL) {
|
||||
DBG("unable to get a uac_auth factory. registrations will not be authenticated.\n");
|
||||
DBG("(do you want to load uac_auth module?)\n");
|
||||
} else {
|
||||
uac_auth_i = uac_auth_f->getInstance();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (registrations.size()) {
|
||||
unsigned int cnt = 250;
|
||||
while (cnt > 0) {
|
||||
usleep(2000); // every 2 ms
|
||||
processEvents();
|
||||
cnt--;
|
||||
}
|
||||
checkTimeouts();
|
||||
} else {
|
||||
waitForEvent();
|
||||
processEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SIPRegistration::onRegisterExpired() {
|
||||
if (sess_link.length()) {
|
||||
AmSessionContainer::instance()->postEvent(sess_link,
|
||||
new SIPRegistrationEvent(SIPRegistrationEvent::RegisterTimeout,
|
||||
req.from_tag));
|
||||
}
|
||||
DBG("Registration '%s' expired.\n", (info.user+"@"+info.domain).c_str());
|
||||
remove = true;
|
||||
}
|
||||
|
||||
void SIPRegistration::onRegisterSendTimeout() {
|
||||
if (sess_link.length()) {
|
||||
AmSessionContainer::instance()->postEvent(sess_link,
|
||||
new SIPRegistrationEvent(SIPRegistrationEvent::RegisterSendTimeout,
|
||||
req.from_tag));
|
||||
}
|
||||
DBG("Registration '%s' REGISTER request timeout.\n",
|
||||
(info.user+"@"+info.domain).c_str());
|
||||
remove = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SIPRegistrarClient::checkTimeouts() {
|
||||
// DBG("checking timeouts...\n");
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
reg_mut.lock();
|
||||
for (map<string, SIPRegistration*>::iterator it = registrations.begin();
|
||||
it != registrations.end(); it++) {
|
||||
if (it->second->active) {
|
||||
if (it->second->registerExpired(now.tv_sec)) {
|
||||
SIPRegistration* reg = it->second;
|
||||
reg->onRegisterExpired();
|
||||
} else if (it->second->timeToReregister(now.tv_sec)) {
|
||||
it->second->doRegistration();
|
||||
}
|
||||
} else if (it->second->remove) {
|
||||
DBG("removing registration\n");
|
||||
SIPRegistration* reg = it->second;
|
||||
registrations.erase(it);
|
||||
delete reg;
|
||||
} else if (it->second->registerSendTimeout(now.tv_sec)) {
|
||||
SIPRegistration* reg = it->second;
|
||||
reg->onRegisterSendTimeout();
|
||||
}
|
||||
}
|
||||
reg_mut.unlock();
|
||||
}
|
||||
|
||||
int SIPRegistrarClient::onLoad() {
|
||||
instance()->start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::process(AmEvent* ev) {
|
||||
AmSipReplyEvent* sip_rep = dynamic_cast<AmSipReplyEvent*>(ev);
|
||||
if (sip_rep) {
|
||||
onSipReplyEvent(sip_rep);
|
||||
return;
|
||||
}
|
||||
|
||||
SIPNewRegistrationEvent* new_reg = dynamic_cast<SIPNewRegistrationEvent*>(ev);
|
||||
if (new_reg) {
|
||||
onNewRegistration(new_reg);
|
||||
return;
|
||||
}
|
||||
|
||||
SIPRemoveRegistrationEvent* rem_reg = dynamic_cast<SIPRemoveRegistrationEvent*>(ev);
|
||||
if (rem_reg) {
|
||||
onRemoveRegistration(rem_reg);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::onSipReplyEvent(AmSipReplyEvent* ev) {
|
||||
SIPRegistration* reg = get_reg(ev->reply.local_tag);
|
||||
if (reg != NULL) {
|
||||
reg->onSipReply(ev->reply);
|
||||
}
|
||||
}
|
||||
|
||||
bool SIPRegistration::registerSendTimeout(time_t now_sec) {
|
||||
return now_sec > reg_send_begin + REGISTER_SEND_TIMEOUT;
|
||||
}
|
||||
|
||||
bool SIPRegistration::timeToReregister(time_t now_sec) {
|
||||
// if (active)
|
||||
// DBG("compare %lu with %lu\n",(reg_begin+reg_expires), (unsigned long)now_sec);
|
||||
return ((reg_begin+reg_expires/2) < (unsigned long)now_sec);
|
||||
}
|
||||
|
||||
bool SIPRegistration::registerExpired(time_t now_sec) {
|
||||
return ((reg_begin+reg_expires) < (unsigned int)now_sec);
|
||||
}
|
||||
|
||||
void SIPRegistration::onSipReply(AmSipReply& reply) {
|
||||
if ((seh!=NULL) && seh->onSipReply(reply))
|
||||
return;
|
||||
|
||||
dlg.updateStatus(reply);
|
||||
|
||||
if ((reply.code>=200)&&(reply.code<300)) {
|
||||
DBG("positive reply to REGISTER!\n");
|
||||
size_t end = 0;
|
||||
string local_contact_hdr = dlg.getContactHdr();
|
||||
local_contact.parse_contact(local_contact_hdr, (size_t)0, end);
|
||||
local_contact.dump();
|
||||
|
||||
string contacts = getHeader(reply.hdrs, "Contact", "m");
|
||||
bool found = false;
|
||||
|
||||
if (!contacts.length()) {
|
||||
DBG("received positive reply to de-Register \n");
|
||||
remove = true;
|
||||
} else {
|
||||
end = 0;
|
||||
while (!found) {
|
||||
if (!server_contact.parse_contact(contacts, end, end)) {
|
||||
ERROR("while parsing contact\n");
|
||||
break;
|
||||
}
|
||||
server_contact.dump();
|
||||
|
||||
if (server_contact.isEqual(local_contact)) {
|
||||
DBG("contact found\n");
|
||||
found = active = true;
|
||||
bool str2i(const string& str, unsigned int& result);
|
||||
|
||||
if (str2i(server_contact.params["expires"], reg_expires)) {
|
||||
ERROR("could not extract expires value.\n");
|
||||
reg_expires = 500;
|
||||
}
|
||||
DBG("got an expires of %d\n", reg_expires);
|
||||
// save TS
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
reg_begin = now.tv_sec;
|
||||
|
||||
if (sess_link.length()) {
|
||||
DBG("posting SIPRegistrationEvent to '%s'\n", sess_link.c_str());
|
||||
AmSessionContainer::instance()->postEvent(sess_link,
|
||||
new SIPRegistrationEvent(SIPRegistrationEvent::RegisterSuccess,
|
||||
req.from_tag,
|
||||
reply.code, reply.reason));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (sess_link.length()) {
|
||||
AmSessionContainer::instance()->postEvent(sess_link,
|
||||
new SIPRegistrationEvent(SIPRegistrationEvent::RegisterNoContact,
|
||||
req.from_tag,
|
||||
reply.code, reply.reason));
|
||||
}
|
||||
active = false;
|
||||
}
|
||||
|
||||
} else if (reply.code >= 300) {
|
||||
DBG("Registration failed.\n");
|
||||
if (sess_link.length()) {
|
||||
AmSessionContainer::instance()->postEvent(sess_link,
|
||||
new SIPRegistrationEvent(SIPRegistrationEvent::RegisterFailed,
|
||||
req.from_tag,
|
||||
reply.code, reply.reason));
|
||||
}
|
||||
active = false;
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::onNewRegistration(SIPNewRegistrationEvent* new_reg) {
|
||||
|
||||
SIPRegistration* reg = new SIPRegistration(new_reg->handle, new_reg->info,
|
||||
new_reg->sess_link);
|
||||
|
||||
if (uac_auth_i != NULL) {
|
||||
DBG("enabling UAC Auth for new registration.\n");
|
||||
|
||||
// get a sessionEventHandler from uac_auth
|
||||
AmArgArray di_args,ret;
|
||||
di_args.push(reg);
|
||||
di_args.push(reg);
|
||||
uac_auth_i->invoke("getHandler", di_args, ret);
|
||||
ArgObject* p = ret.get(0).asObject();
|
||||
if (p != NULL) {
|
||||
AmSessionEventHandler* h = dynamic_cast<AmSessionEventHandler*>(p);
|
||||
if (h != NULL)
|
||||
reg->setSessionEventHandler(h);
|
||||
}
|
||||
}
|
||||
|
||||
add_reg(new_reg->handle, reg);
|
||||
reg->doRegistration();
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::onRemoveRegistration(SIPRemoveRegistrationEvent* new_reg) {
|
||||
SIPRegistration* reg = get_reg(new_reg->handle);
|
||||
if (reg)
|
||||
reg->doUnregister();
|
||||
}
|
||||
|
||||
|
||||
void SIPRegistrarClient::on_stop() { }
|
||||
|
||||
|
||||
bool SIPRegistrarClient::onSipReply(const AmSipReply& rep) {
|
||||
DBG("got reply with tag '%s'\n", rep.local_tag.c_str());
|
||||
|
||||
if (instance()->hasRegistration(rep.local_tag)) {
|
||||
instance()->postEvent(new AmSipReplyEvent(rep));
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SIPRegistrarClient::hasRegistration(const string& handle) {
|
||||
return get_reg(handle) != NULL;
|
||||
}
|
||||
|
||||
SIPRegistration* SIPRegistrarClient::
|
||||
get_reg(const string& reg_id)
|
||||
{
|
||||
DBG("get registration '%s'\n", reg_id.c_str());
|
||||
SIPRegistration* res = NULL;
|
||||
reg_mut.lock();
|
||||
map<string, SIPRegistration*>::iterator it =
|
||||
registrations.find(reg_id);
|
||||
if (it!=registrations.end())
|
||||
res = it->second;
|
||||
reg_mut.unlock();
|
||||
DBG("get registration : res = '%ld' (this = %ld)\n", (long)res, (long)this);
|
||||
return res;
|
||||
}
|
||||
|
||||
SIPRegistration* SIPRegistrarClient::
|
||||
remove_reg(const string& reg_id) {
|
||||
reg_mut.lock();
|
||||
SIPRegistration* reg = remove_reg_unsafe(reg_id);
|
||||
reg_mut.unlock();
|
||||
return reg;
|
||||
}
|
||||
|
||||
SIPRegistration* SIPRegistrarClient::
|
||||
remove_reg_unsafe(const string& reg_id) {
|
||||
DBG("removing registration '%s'\n", reg_id.c_str());
|
||||
SIPRegistration* reg = NULL;
|
||||
map<string, SIPRegistration*>::iterator it =
|
||||
registrations.find(reg_id);
|
||||
if (it!=registrations.end()) {
|
||||
reg = it->second;
|
||||
registrations.erase(it);
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::
|
||||
add_reg(const string& reg_id, SIPRegistration* new_reg)
|
||||
{
|
||||
DBG("adding registration '%s' (this = %ld)\n", reg_id.c_str(), (long)this);
|
||||
SIPRegistration* reg = NULL;
|
||||
reg_mut.lock();
|
||||
map<string, SIPRegistration*>::iterator it =
|
||||
registrations.find(reg_id);
|
||||
if (it!=registrations.end()) {
|
||||
reg = it->second;
|
||||
|
||||
}
|
||||
registrations[reg_id] = new_reg;
|
||||
reg_mut.unlock();
|
||||
|
||||
if (reg != NULL)
|
||||
delete reg; // old one with the same ltag
|
||||
|
||||
}
|
||||
|
||||
|
||||
// API
|
||||
string SIPRegistrarClient::createRegistration(const string& domain,
|
||||
const string& user,
|
||||
const string& name,
|
||||
const string& auth_user,
|
||||
const string& pwd,
|
||||
const string& sess_link) {
|
||||
|
||||
string handle = AmSession::getNewId();
|
||||
instance()->
|
||||
postEvent(new SIPNewRegistrationEvent(SIPRegistrationInfo(domain, user,
|
||||
name, auth_user, pwd),
|
||||
handle, sess_link));
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::removeRegistration(const string& handle) {
|
||||
instance()->
|
||||
postEvent(new SIPRemoveRegistrationEvent(handle));
|
||||
|
||||
}
|
||||
|
||||
void SIPRegistrarClient::invoke(const string& method, const AmArgArray& args,
|
||||
AmArgArray& ret)
|
||||
{
|
||||
if(method == "createRegistration"){
|
||||
ret.push(createRegistration(args.get(0).asCStr(),
|
||||
args.get(1).asCStr(),
|
||||
args.get(2).asCStr(),
|
||||
args.get(3).asCStr(),
|
||||
args.get(4).asCStr(),
|
||||
args.get(5).asCStr()
|
||||
).c_str());
|
||||
}
|
||||
else if(method == "removeRegistration"){
|
||||
removeRegistration(args.get(0).asCStr());
|
||||
}
|
||||
else
|
||||
throw AmDynInvoke::NotImplemented(method);
|
||||
}
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* $Id: AmApi.h,v 1.9.2.1 2005/06/01 12:00:24 rco Exp $
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RegisterClient_h
|
||||
#define RegisterClient_h
|
||||
|
||||
#include "AmApi.h"
|
||||
#include "AmSession.h"
|
||||
#include "ContactInfo.h"
|
||||
|
||||
#include "ampi/SIPRegistrarClientAPI.h"
|
||||
#include "ampi/UACAuthAPI.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
using std::map;
|
||||
using std::string;
|
||||
|
||||
struct SIPRegistrationInfo {
|
||||
string domain;
|
||||
string user;
|
||||
string name;
|
||||
string auth_user;
|
||||
string pwd;
|
||||
SIPRegistrationInfo(const string& domain,
|
||||
const string& user,
|
||||
const string& name,
|
||||
const string& auth_user,
|
||||
const string& pwd)
|
||||
: domain(domain),user(user),name(name),
|
||||
auth_user(auth_user),pwd(pwd)
|
||||
{ }
|
||||
};
|
||||
|
||||
class SIPRegistration : public AmSipDialogEventHandler,
|
||||
public DialogControl,
|
||||
public CredentialHolder
|
||||
|
||||
{
|
||||
|
||||
AmSipDialog dlg;
|
||||
UACAuthCred cred;
|
||||
|
||||
SIPRegistrationInfo info;
|
||||
|
||||
// session to post events to
|
||||
string sess_link;
|
||||
|
||||
AmSessionEventHandler* seh;
|
||||
|
||||
AmSipRequest req;
|
||||
|
||||
ContactInfo server_contact;
|
||||
ContactInfo local_contact;
|
||||
|
||||
time_t reg_begin;
|
||||
unsigned int reg_expires;
|
||||
time_t reg_send_begin;
|
||||
public:
|
||||
SIPRegistration(const string& handle,
|
||||
const SIPRegistrationInfo& info,
|
||||
const string& sess_link);
|
||||
|
||||
void setSessionEventHandler(AmSessionEventHandler* new_seh);
|
||||
|
||||
void doRegistration();
|
||||
void doUnregister();
|
||||
|
||||
inline bool timeToReregister(time_t now_sec);
|
||||
inline bool registerExpired(time_t now_sec);
|
||||
void onRegisterExpired();
|
||||
void onRegisterSendTimeout();
|
||||
|
||||
inline bool registerSendTimeout(time_t now_sec);
|
||||
|
||||
void onSendRequest(const string& method,
|
||||
const string& content_type,
|
||||
const string& body,
|
||||
string& hdrs,
|
||||
unsigned int cseq);
|
||||
|
||||
void onSendReply(const AmSipRequest& req,
|
||||
unsigned int code,
|
||||
const string& reason,
|
||||
const string& content_type,
|
||||
const string& body,
|
||||
string& hdrs);
|
||||
// DialogControl if
|
||||
AmSipDialog* getDlg() { return &dlg; }
|
||||
// CredentialHolder
|
||||
UACAuthCred* getCredentials() { return &cred; }
|
||||
void onSipReply(AmSipReply& reply);
|
||||
|
||||
/** is this registration registered? */
|
||||
bool active;
|
||||
/** should this registration be removed from container? */
|
||||
bool remove;
|
||||
|
||||
};
|
||||
|
||||
class SIPNewRegistrationEvent;
|
||||
class SIPRemoveRegistrationEvent;
|
||||
|
||||
class SIPRegistrarClient : public AmSIPEventHandler,
|
||||
public AmThread,
|
||||
public AmEventQueue,
|
||||
public AmEventHandler,
|
||||
public AmDynInvoke,
|
||||
public AmDynInvokeFactory
|
||||
{
|
||||
// registrations container
|
||||
AmMutex reg_mut;
|
||||
std::map<std::string, SIPRegistration*> registrations;
|
||||
|
||||
void add_reg(const string& reg_id,
|
||||
SIPRegistration* new_reg);
|
||||
SIPRegistration* remove_reg(const string& reg_id);
|
||||
SIPRegistration* remove_reg_unsafe(const string& reg_id);
|
||||
SIPRegistration* get_reg(const string& reg_id);
|
||||
|
||||
void onSipReplyEvent(AmSipReplyEvent* ev);
|
||||
void onNewRegistration(SIPNewRegistrationEvent* new_reg);
|
||||
void onRemoveRegistration(SIPRemoveRegistrationEvent* new_reg);
|
||||
|
||||
static SIPRegistrarClient* _instance;
|
||||
|
||||
AmDynInvoke* uac_auth_i;
|
||||
|
||||
|
||||
void checkTimeouts();
|
||||
public:
|
||||
SIPRegistrarClient(const string& name);
|
||||
// DI factory
|
||||
SIPRegistrarClient* getInstance() { return instance(); }
|
||||
// DI API
|
||||
static SIPRegistrarClient* instance();
|
||||
void invoke(const string& method,
|
||||
const AmArgArray& args, AmArgArray& ret);
|
||||
|
||||
bool onSipReply(const AmSipReply& rep);
|
||||
int onLoad();
|
||||
|
||||
void run();
|
||||
void on_stop();
|
||||
void process(AmEvent* ev);
|
||||
|
||||
|
||||
// API
|
||||
string createRegistration(const string& domain,
|
||||
const string& user,
|
||||
const string& name,
|
||||
const string& auth_user,
|
||||
const string& pwd,
|
||||
const string& sess_link);
|
||||
void removeRegistration(const string& handle);
|
||||
|
||||
bool hasRegistration(const string& handle);
|
||||
|
||||
enum {
|
||||
AddRegistration,
|
||||
RemoveRegistration
|
||||
} RegEvents;
|
||||
|
||||
};
|
||||
|
||||
struct SIPNewRegistrationEvent : public AmEvent {
|
||||
|
||||
SIPNewRegistrationEvent(const SIPRegistrationInfo& info,
|
||||
const string& handle,
|
||||
const string& sess_link)
|
||||
: info(info), handle(handle), sess_link(sess_link),
|
||||
AmEvent(SIPRegistrarClient::AddRegistration) { }
|
||||
|
||||
|
||||
string handle;
|
||||
string sess_link;
|
||||
SIPRegistrationInfo info;
|
||||
};
|
||||
|
||||
class SIPRemoveRegistrationEvent : public AmEvent {
|
||||
public:
|
||||
string handle;
|
||||
SIPRemoveRegistrationEvent(const string& handle)
|
||||
: handle(handle),
|
||||
AmEvent(SIPRegistrarClient::RemoveRegistration) { }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* $Id: Ivr.cpp,v 1.26.2.1 2005/09/02 13:47:46 rco Exp $
|
||||
*
|
||||
* Copyright (C) 2006 iptego GmbH
|
||||
*
|
||||
* This file is part of sems, a free SIP media server.
|
||||
*
|
||||
* This program 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 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
|
||||
*/
|
||||
|
||||
#ifndef _SIPREGISTRARCLIENTAPI_H
|
||||
#define _SIPREGISTRARCLIENTAPI_H
|
||||
|
||||
#include <string>
|
||||
#include "AmEvent.h"
|
||||
|
||||
using std::string;
|
||||
struct SIPRegistrationEvent : public AmEvent {
|
||||
string handle;
|
||||
unsigned int code;
|
||||
string reason;
|
||||
|
||||
SIPRegistrationEvent(int t, const string& handle,
|
||||
unsigned int code=0, const string& reason="")
|
||||
: AmEvent(t), handle(handle), code(code), reason(reason) {}
|
||||
|
||||
enum {
|
||||
RegisterSuccess=0,
|
||||
RegisterFailed,
|
||||
RegisterNoContact,
|
||||
RegisterTimeout,
|
||||
RegisterSendTimeout
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue