BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
75c7e0f
Branches
Tags
master
Blinker
src
noarch
Phone_impl.h
implemented extension config for phone connector
Stefan Schuermans
commited
75c7e0f
at 2011-12-22 15:00:51
Phone_impl.h
Blame
History
Raw
/* Blinker Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #ifndef BLINKER_PHONE_IMPL_H #define BLINKER_PHONE_IMPL_H #include <string> #include "Directory.h" #include "File.h" #include "IoCallee.h" #include "ListTracker.h" #include "ListTracker_impl.h" #include "Mgrs.h" #include "Module.h" #include "Phone.h" #include "PhoneExtension.h" #include "PhoneExtension_impl.h" #include "SettingFile.h" #include "StringParser.h" #include "Time.h" #include "TimeCallee.h" namespace Blinker { /** * @brief constructor * @param[in] mgrs managers * @param[in] dirBase base directory */ template<typename ADDR, typename SOCK> Phone<ADDR, SOCK>::Phone(Mgrs &mgrs, const Directory &dirBase): Module(mgrs, dirBase), m_fileBind(dirBase.getFile("bind")), m_fileServer(dirBase.getFile("server")), m_extListTracker(*this, dirBase.getSubdir("extensions")), m_pSock(NULL) { // read server address readServer(); // create and bind socket createSock(); // load extensions m_extListTracker.init(); } /// virtual destructor template<typename ADDR, typename SOCK> Phone<ADDR, SOCK>::~Phone() { // unload extensions m_extListTracker.clear(); // destroy socket destroySock(); // cancel time callback m_mgrs.m_callMgr.cancelTimeCall(this); } /// check for update of configuration template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::updateConfig() { // bind address file was modified -> re-create socket if (m_fileBind.checkModified()) { destroySock(); createSock(); } // server address file was modified -> re-read server address if (m_fileServer.checkModified()) readServer(); // extensions update m_extListTracker.updateConfig(); } /// callback when requested time reached template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::timeCall() { Time now = Time::now(); // server timeout -> re-register if (m_timeRegister <= now) sendRegister(); // send heartbeat if (m_timeHeartbeat <= now) sendHeartbeat(); } /** * @brief callback when I/O object is readable * @param[in] io I/O object that is readable */ template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::ioReadCall(Io *io) { // reception on socket if (io == m_pSock) receiveFromSock(); } /** * @brief callback when I/O object is writable * @param[in] io I/O object that is writable */ template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::ioWriteCall(Io *io) { (void)io; // unused } /// (re-)read server address template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::readServer() { m_fileServer.update(); // register with new server sendRegister(); } /// create socket and bind it template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::createSock() { // create socket if (!m_pSock) { m_pSock = new SOCK(); if (!m_pSock) return; } // get bind address from bind address setting file m_fileBind.update(); if (!m_fileBind.m_valid) { delete m_pSock; m_pSock = NULL; return; } // bind socket if (!m_pSock->bind(m_fileBind.m_obj)) { delete m_pSock; m_pSock = NULL; return; } // request callback on recepetion m_mgrs.m_callMgr.requestIoReadCall(this, m_pSock); // register with server sendRegister(); } /// destroy socket template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::destroySock() { // cancel callback request m_mgrs.m_callMgr.cancelIoReadCall(this, m_pSock); // destroy socket if (m_pSock) { delete m_pSock; m_pSock = NULL; } } /// register with server template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::sendRegister() { send("0:register"); // set time for next register message and next heartbeat m_timeRegister = Time::now() + m_serverTimeout; m_timeHeartbeat = m_timeRegister + m_heartbeatInterval; updateTimeCallback(); } /// send heartbeat to server template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::sendHeartbeat() { send("0:heartbeat"); // set time for next heartbeat m_timeHeartbeat = Time::now() + m_heartbeatInterval; updateTimeCallback(); } /** * @brief send message to server * @param[in] msg message to send */ template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::send(const std::string &msg) { // check that there is a socket and a server address if (!m_pSock || !m_fileServer.m_valid) return; // send message m_pSock->send(msg, m_fileServer.m_obj); } /// receive data from socket template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::receiveFromSock() { std::string msg; ADDR addr; // make sure socket exists if (!m_pSock) return; // receive (leave if no reception) if (!m_pSock->recv(msg, addr)) return; // check that packet came from server address if (!m_fileServer.m_valid || addr != m_fileServer.m_obj) return; // mismatch // reset server timeout m_timeRegister = Time::now() + m_serverTimeout; updateTimeCallback(); // process message serverMsg(msg); } /** * @brief process message from server * @param[in] msg message from server */ template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::serverMsg(const std::string &msg) { StringParser parser(msg); // get line number and command unsigned int line; std::string cmd; if (!parser.uintNo(line) || !parser.fixChr(':') || !parser.untilDelim(":", false, cmd)) return; // incoming call if (cmd == "setup") { std::string caller, extension; if (!parser.fixChr(':') || !parser.untilDelim(":", true, caller) || !parser.fixChr(':') || !parser.untilDelim(":", false, extension)) return; // TODO incomingCall(line, extension); } // hangup else if (cmd == "onhook") { // TODO hangup(line); } // DTMF symbol (i.e. key pressed) else if (cmd == "dtmf") { char key; if (!parser.fixChr(':') || !parser.oneChrOf("0123456789*#", key)) return; // TODO keyPressed(line, key); } } /// update time callback template<typename ADDR, typename SOCK> void Phone<ADDR, SOCK>::updateTimeCallback() { m_mgrs.m_callMgr.requestTimeCall(this, m_timeRegister < m_timeHeartbeat ? m_timeRegister : m_timeHeartbeat); } template<typename ADDR, typename SOCK> const Time Phone<ADDR, SOCK>::m_serverTimeout(5); template<typename ADDR, typename SOCK> const Time Phone<ADDR, SOCK>::m_heartbeatInterval(20); } // namespace Blinker #endif // #ifndef BLINKER_PHONE_IMPL_H