diff --git a/apps/announce_auth/AnnounceAuth.cpp b/apps/announce_auth/AnnounceAuth.cpp index 7f271d92..2d3a77e0 100644 --- a/apps/announce_auth/AnnounceAuth.cpp +++ b/apps/announce_auth/AnnounceAuth.cpp @@ -189,7 +189,7 @@ void DialerThread::set_dial(const string& r, const string& f, } void DialerThread::run() { - sleep(5); // wait for sems to completely start up + sleep(15); // wait for sems to completely start up while (!is_stopped()) { DBG("dialing..."); AmUAC::dialout("blibla", "announce_auth", diff --git a/apps/registrar_client/ContactInfo.cpp b/apps/registrar_client/ContactInfo.cpp new file mode 100644 index 00000000..e771a061 --- /dev/null +++ b/apps/registrar_client/ContactInfo.cpp @@ -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 +#include +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_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::iterator it = params.begin(); + it != params.end(); it++) + DBG(" param '%s'='%s'\n", it->first.c_str(), it->second.c_str()) ; + DBG("-------------------- \n"); +} diff --git a/apps/registrar_client/ContactInfo.h b/apps/registrar_client/ContactInfo.h new file mode 100644 index 00000000..106e02b0 --- /dev/null +++ b/apps/registrar_client/ContactInfo.h @@ -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 +#include +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 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() { } +}; diff --git a/apps/registrar_client/Makefile b/apps/registrar_client/Makefile new file mode 100644 index 00000000..f1fdc90f --- /dev/null +++ b/apps/registrar_client/Makefile @@ -0,0 +1,7 @@ +plug_in_name = registrar_client + +module_ldflags = +module_cflags = + +COREPATH ?=../../core +include $(COREPATH)/plug-in/Makefile.app_module diff --git a/apps/registrar_client/SIPRegistrarClient.cpp b/apps/registrar_client/SIPRegistrarClient.cpp new file mode 100644 index 00000000..e2d3c62d --- /dev/null +++ b/apps/registrar_client/SIPRegistrarClient.cpp @@ -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+" "; + 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::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(ev); + if (sip_rep) { + onSipReplyEvent(sip_rep); + return; + } + + SIPNewRegistrationEvent* new_reg = dynamic_cast(ev); + if (new_reg) { + onNewRegistration(new_reg); + return; + } + + SIPRemoveRegistrationEvent* rem_reg = dynamic_cast(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(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::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::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::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); +} + diff --git a/apps/registrar_client/SIPRegistrarClient.h b/apps/registrar_client/SIPRegistrarClient.h new file mode 100644 index 00000000..905fcbb3 --- /dev/null +++ b/apps/registrar_client/SIPRegistrarClient.h @@ -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 + +#include +#include +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 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 diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp index bc24a238..4a88296c 100644 --- a/core/AmConfig.cpp +++ b/core/AmConfig.cpp @@ -51,9 +51,19 @@ string AmConfig::PrefixSep = PREFIX_SEPARATOR; int AmConfig::RtpLowPort = RTP_LOWPORT; int AmConfig::RtpHighPort = RTP_HIGHPORT; int AmConfig::MediaProcessorThreads = NUM_MEDIA_PROCESSORS; +int AmConfig::LocalSIPPort = 5060; +string AmConfig::LocalSIPIP = ""; AmSessionTimerConfig AmConfig::defaultSessionTimerConfig; +int AmConfig::setSIPPort(const string& port) +{ + if(sscanf(port.c_str(),"%u",&AmConfig::LocalSIPPort) != 1) { + return 0; + } + return 1; +} + int AmConfig::setSmtpPort(const string& port) { if(sscanf(port.c_str(),"%u",&AmConfig::SmtpServerPort) != 1) { @@ -145,7 +155,13 @@ int AmConfig::readConfiguration() // local_ip LocalIP = cfg.getParameter("listen"); -DBG("RvR :- Local IP set to %s\n", LocalIP.c_str()); + + if(cfg.hasParameter("sip_port")){ + if(!setSIPPort(cfg.getParameter("sip_port").c_str())){ + ERROR("invalid sip port specified\n"); + return -1; + } + } // socket_name SocketName = cfg.getParameter("socket_name"); diff --git a/core/AmConfig.h b/core/AmConfig.h index f50d65d9..17b53100 100644 --- a/core/AmConfig.h +++ b/core/AmConfig.h @@ -77,6 +77,10 @@ struct AmConfig static AmSessionTimerConfig defaultSessionTimerConfig; /** number of session scheduler threads */ static int MediaProcessorThreads; + /** the interface SIP requests are sent from - needed for registrar_client */ + static string LocalSIPIP; + /** the port SIP requests are sent from - optional (default 5060) */ + static int LocalSIPPort; /** Init function. Resolves SMTP server address. */ static int init(); @@ -85,7 +89,10 @@ struct AmConfig * command line arguments */ static int readConfiguration(); - /* following setters are used to fill config from config file */ + /* following setters are used to fill config from config file */ + + /** Setter for SIP Port, returns 0 on invalid value */ + static int setSIPPort(const string& port); /** Setter for SmtpServer Port, returns 0 on invalid value */ static int setSmtpPort(const string& port); /** Setter for RtpLowPort, returns 0 on invalid value */ diff --git a/core/AmInterfaceHandler.cpp b/core/AmInterfaceHandler.cpp index f3de5edf..6b8880c6 100644 --- a/core/AmInterfaceHandler.cpp +++ b/core/AmInterfaceHandler.cpp @@ -260,7 +260,7 @@ int AmReplyHandler::handleRequest(AmCtrlInterface* ctrl) reply.local_tag, new AmSipReplyEvent(reply))) { for (vector::iterator it = - reply_handlers.begin(); it != reply_handlers.end(); it++) + reply_handlers.begin(); it != reply_handlers.end(); it++) if ((*it)->onSipReply(reply)) break; } diff --git a/core/AmPlugIn.cpp b/core/AmPlugIn.cpp index 87ff1caf..4e71f5e0 100644 --- a/core/AmPlugIn.cpp +++ b/core/AmPlugIn.cpp @@ -192,6 +192,12 @@ int AmPlugIn::loadPlugIn(const string& file) has_sym=true; } + if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_SIP_EVENT_HANDLER_EXPORT_STR)) != NULL){ + if(loadSIPehPlugIn((AmPluginFactory*)fc())) + goto error; + has_sym=true; + } + if(!has_sym){ ERROR("Plugin type could not be detected (%s)(%s)\n",file.c_str(),dlerror()); goto error; diff --git a/core/ampi/SIPRegistrarClientAPI.h b/core/ampi/SIPRegistrarClientAPI.h new file mode 100644 index 00000000..c8d24864 --- /dev/null +++ b/core/ampi/SIPRegistrarClientAPI.h @@ -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 +#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 diff --git a/core/sems.cpp b/core/sems.cpp index f58c0bfa..7b4f69f5 100644 --- a/core/sems.cpp +++ b/core/sems.cpp @@ -275,8 +275,9 @@ int main(int argc, char* argv[]) return -1; } - //if(AmConfig::LocalIP.empty()) AmConfig::LocalIP = getLocalIP(AmConfig::LocalIP); + AmConfig::LocalSIPIP = AmConfig::LocalIP; + printf( "\n\nConfiguration:\n" " configuration file: %s\n"