Commit f8e318c7 authored by jpbl's avatar jpbl
Browse files

sfl uses Sockets now

parent 89fecf6f
/**
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author: Jean-Philippe Barrette-LaPierre
* <jean-philippe.barrette-lapierre@savoirfairelinux.com>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __FACTORY_HPP__
#define __FACTORY_HPP__
template< typename T >
struct Creator
{
virtual ~Creator(){}
virtual T *create() = 0;
};
template< typename T >
class Factory
{
public:
Factory();
~Factory();
/**
* This function will set the creator. The
* Factory owns the creator instance.
*/
void setCreator(Creator< T > *creator);
/**
* It ask the creator to create a SessionIO.
* If there's no creator set, it will throw
* a std::logic_error.
*/
T *create();
private:
Creator< T > *mCreator;
};
#include "Factory.inl"
#endif
......@@ -18,33 +18,35 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SFLPHONEGUI_ANSWERRECIVER_H
#define SFLPHONEGUI_ANSWERRECIVER_H
#include <stdexcept>
#include <qthread.h>
template< typename T >
Factory< T >::Factory()
: mCreator(0)
{}
class RequesterImpl;
class SessionIO;
/**
* This class is the thread that will read
* from the SessionIO.
*/
class AnswerReceiver : public QThread
template< typename T >
Factory< T >::~Factory()
{
public:
AnswerReceiver(RequesterImpl *requester,
SessionIO *session);
/**
* This is the main processing function.
*/
virtual void run();
delete mCreator;
}
template< typename T >
void
Factory< T >::setCreator(Creator< T > *creator)
{
mCreator = creator;
}
private:
RequesterImpl *mRequester;
SessionIO *mSession;
};
template< typename T >
T *
Factory< T >::create()
{
if(!mCreator) {
throw std::logic_error("Trying to create without a creator.");
}
else {
return mCreator->create();
}
}
#endif
......@@ -16,9 +16,15 @@ PhoneLineManagerImpl::PhoneLineManagerImpl()
{
EventFactory::instance().registerEvent< HangupEvent >("002");
EventFactory::instance().registerEvent< IncommingEvent >("001");
}
void
PhoneLineManagerImpl::connect()
{
mSession.getEvents();
}
PhoneLine *
PhoneLineManagerImpl::getCurrentLine()
{
......
......@@ -46,6 +46,8 @@ signals:
void selected(unsigned int);
public slots:
void connect();
void sendKey(Qt::Key c);
/**
......
......@@ -18,13 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include <stdexcept>
#include <sstream>
#include "globals.h"
#include "RequesterImpl.hpp"
#include "SessionIO.hpp"
#include "AnswerReceiver.hpp"
RequesterImpl::RequesterImpl()
: mCallIdCount(0)
......@@ -83,11 +83,7 @@ RequesterImpl::registerSession(const std::string &id,
throw std::logic_error("Registering an already know Session ID");
}
AnswerReceiver *a = new AnswerReceiver(this, s);
mAnswerReceivers.insert(std::make_pair(id, a));
mSessions.insert(std::make_pair(id, s));
s->start();
a->start();
}
int
......@@ -181,10 +177,4 @@ RequesterImpl::inputIsDown(const std::string &sessionId)
_debug("SessionIO input for session %s is down, but we don't have that session.\n",
sessionId.c_str());
}
else {
// If we no longer can receive, it means it's
// not possible to receive answer for new requests,
// so we close the session.
pos->second->stop();
}
}
......@@ -116,7 +116,6 @@ class RequesterImpl
private:
ObjectFactory< Request > mRequestFactory;
std::map< std::string, SessionIO * > mSessions;
std::map< std::string, AnswerReceiver * > mAnswerReceivers;
std::map< std::string, Request * > mRequests;
std::map< std::string, std::string > mSequenceToSession;
......
#include "globals.h"
#include "SFLPhoneApp.hpp"
#include "SFLPhoneWindow.hpp"
#include "SFLRequest.hpp"
#include "PhoneLine.hpp"
#include "PhoneLineButton.hpp"
#include "Requester.hpp"
#include "SessionIOFactory.hpp"
#include "SFLPhoneApp.hpp"
#include "SFLPhoneWindow.hpp"
#include "SFLRequest.hpp"
#include "TCPSessionIOCreator.hpp"
SFLPhoneApp::SFLPhoneApp(int argc, char **argv)
: QApplication(argc, argv)
, mSession()
, mAccount(mSession.getDefaultAccount())
{
SessionIOFactory::instance().setCreator(new TCPSessionIOCreator(QString("localhost"), 3999));
PhoneLineManager::instance().setNbLines(NB_PHONELINES);
Requester::instance().registerObject< Request >(std::string("playtone"));
Requester::instance().registerObject< Request >(std::string("playdtmf"));
Requester::instance().registerObject< EventRequest >(std::string("getevents"));
......@@ -26,7 +28,6 @@ SFLPhoneApp::SFLPhoneApp(int argc, char **argv)
Requester::instance().registerObject< CallRelatedRequest >(std::string("hold"));
Requester::instance().registerObject< CallRelatedRequest >(std::string("unhold"));
Requester::instance().registerObject< CallRelatedRequest >(std::string("hangup"));
PhoneLineManager::instance().setNbLines(NB_PHONELINES);
}
void
......
......@@ -20,9 +20,6 @@ public:
*/
void initConnections(SFLPhoneWindow *w);
private:
Session mSession;
Account mAccount;
};
#endif
......@@ -23,7 +23,7 @@
#include "Session.hpp"
#include "Requester.hpp"
#include "SessionIO.hpp"
#include "SessionIOFactory.hpp"
Session::Session(const std::string &id)
......@@ -33,7 +33,7 @@ Session::Session(const std::string &id)
Session::Session()
{
mId = Requester::instance().generateSessionId();
SessionIO *s = new SessionIO(mId, &std::cin, &std::cout);
SessionIO *s = SessionIOFactory::instance().create();
Requester::instance().registerSession(mId, s);
}
......
......@@ -18,93 +18,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef SFLPHONEGUI_SESSIONIO_H
#define SFLPHONEGUI_SESSIONIO_H
#ifndef __SESSIONIO_HPP__
#define __SESSIONIO_HPP__
#include <QObject>
#include <string>
#include <iostream>
#include <qthread.h>
#include "ObjectPool.hpp"
class SessionIO;
/**
* This class is the thread that will read
* from the SessionIO.
*/
class InputStreamer : public QThread
{
public:
InputStreamer(SessionIO *sessionIO);
/**
* This is the main processing function.
*/
virtual void run();
private:
SessionIO *mSessionIO;
};
/**
* This class is the thread that will write
* to the SessionIO.
*/
class OutputStreamer : public QThread
{
public:
OutputStreamer(SessionIO *sessionIO);
/**
* This is the main processing function
*/
virtual void run();
private:
SessionIO *mSessionIO;
};
/**
* This is the main class that will handle
* the IO.
*/
class SessionIO
class SessionIO : public QObject
{
public:
friend class OutputStreamer;
friend class InputStreamer;
/**
* Those streams will be the streams read or write to.
*/
SessionIO(const std::string &id,
std::istream *input,
std::ostream *output);
~SessionIO();
/**
* This is the function that will start the threads
* that will handle the streams.
*/
void start();
/**
* This function will stop the streaming
* processing. On return, the service
* might not be completly down. You need
* to use waitStop if you want to be sure.
*/
void stop();
Q_OBJECT
/**
* This function will wait until the
* service is really down.
*/
void waitStop();
public:
virtual ~SessionIO(){}
/**
* You can use this function for sending request.
......@@ -112,45 +41,15 @@ class SessionIO
* send the data as it is; it will NOT add an EOL.
* the stream will be "sync"ed.
*/
void send(const std::string &request);
virtual void send(const std::string &request) = 0;
/**
* You can use this function to receive answers.
* This function will wait until there's an
* answer to be processed.
*/
void receive(std::string &answer);
bool isUp();
private:
/**
* This function will send to the stream
* the given data. EOL will be added at the
* end of the data.
*/
void send();
/**
* This function will read a line of data from
* the stream.
*/
void receive();
public:
const std::string id;
private:
QMutex mMutex;
bool mIsUp;
ObjectPool< std::string > mInputPool;
ObjectPool< std::string > mOutputPool;
virtual void receive(std::string &answer) = 0;
std::istream *mInput;
std::ostream *mOutput;
InputStreamer mInputStreamer;
OutputStreamer mOutputStreamer;
};
......
......@@ -18,139 +18,119 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <QMessageBox>
#include "globals.h"
#include "Requester.hpp"
#include "SessionIO.hpp"
InputStreamer::InputStreamer(SessionIO *sessionIO)
: mSessionIO(sessionIO)
{}
#include "TCPSessionIO.hpp"
void
InputStreamer::run()
TCPSessionIO::TCPSessionIO(const QString &hostname, quint16 port)
: mSocket(new QTcpSocket(this))
, mHostname(hostname)
, mPort(port)
{
while(mSessionIO->isUp()) {
mSessionIO->receive();
}
_debug("The Session input is down.\n");
Requester::instance().inputIsDown(mSessionIO->id);
QObject::connect(mSocket, SIGNAL(readyRead()),
this, SLOT(receive()));
QObject::connect(mSocket, SIGNAL(connected()),
this, SLOT(sendWaitingRequests()));
QObject::connect(mSocket, SIGNAL(disconnected()),
this, SLOT(askReconnect()));
QObject::connect(mSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(askReconnect()));
}
OutputStreamer::OutputStreamer(SessionIO *sessionIO)
: mSessionIO(sessionIO)
TCPSessionIO::~TCPSessionIO()
{}
void
OutputStreamer::run()
void
TCPSessionIO::askReconnect()
{
while(mSessionIO->isUp()) {
mSessionIO->send();
int ret = QMessageBox::critical(NULL,
tr("SFLPhone disconnected"),
tr("The link between SFLPhone and SFLPhoned is broken.\n"
"Do you want to try to reconnect?"),
QMessageBox::Retry | QMessageBox::Default,
QMessageBox::Cancel | QMessageBox::Escape);
if (ret == QMessageBox::Yes) {
connect();
}
_debug("The Session output is down.\n");
}
SessionIO::SessionIO(const std::string &sessionId,
std::istream *input,
std::ostream *output)
: id(sessionId)
, mIsUp(false)
, mInput(input)
, mOutput(output)
, mInputStreamer(this)
, mOutputStreamer(this)
{}
SessionIO::~SessionIO()
void
TCPSessionIO::receive()
{
stop();
waitStop();
QString s;
receive(s);
Requester::instance().receiveAnswer(s.toStdString());
}
bool
SessionIO::isUp()
void
TCPSessionIO::connect()
{
{
QMutexLocker guard(&mMutex);
return mIsUp;
}
_debug("TCPSessionIO: Tring to connect to %s:%d.\n",
mHostname.toStdString().c_str(),
mPort);
mSocket->connectToHost(mHostname, mPort);
}
void
SessionIO::start()
TCPSessionIO::send(const std::string &request)
{
stop();
waitStop();
//just protecting the mutex
{
QMutexLocker guard(&mMutex);
mInputStreamer.start();
mOutputStreamer.start();
mIsUp = true;
}
send(QString::fromStdString(request));
}
void
SessionIO::stop()
TCPSessionIO::sendWaitingRequests()
{
mMutex.lock();
mIsUp = false;
mMutex.unlock();
_debug("TCPSessionIO: Connected.\n");
_debug("TCPSessionIO: Sending waiting data.\n");
QTextStream stream(mSocket);
QMutexLocker guard(&mStackMutex);
while(mSocket->state() == QAbstractSocket::ConnectedState &&
mStack.size() > 0) {
stream << *mStack.begin();
mStack.pop_front();
}
emit connected();
}
void
SessionIO::waitStop()
TCPSessionIO::send(const QString &request)
{
mInputStreamer.wait();
mOutputStreamer.wait();
QTextStream stream(mSocket);
if(mSocket->state() == QAbstractSocket::ConnectedState) {
_debug("Sending request to sflphone: %s",
request.toStdString().c_str());
stream << request;
}
else {
mStackMutex.lock();
mStack.push_back(request);
mStackMutex.unlock();
}
}
void
SessionIO::send(const std::string &request)
void
TCPSessionIO::receive(std::string &answer)
{
mOutputPool.push(request);
QString a;
receive(a);
answer = a.toStdString();
}
void
SessionIO::receive(std::string &answer)
{
mInputPool.pop(answer);
}
void
SessionIO::send()
TCPSessionIO::receive(QString &answer)
{
if(!mOutput->good()) {
mMutex.lock();
mIsUp = false;
mMutex.unlock();
}
else {
std::string output;
if(mOutputPool.pop(output, 100)) {
(*mOutput) << output;
mOutput->flush();
}
if(mSocket->isReadable()) {
QTextStream stream(mSocket);
answer = stream.readLine();
}
}
void
SessionIO::receive()
{
if(!mInput->good()) {
mMutex.lock();
mIsUp = false;
mMutex.unlock();
}
else {
std::string s;
std::getline(*mInput, s);
if(s.size() > 0) {
mInputPool.push(s);
}
}
}
......
#include "TCPSessionIOCreator.hpp"
#include "PhoneLineManager.hpp"