introduced optional HTTP port

This commit is contained in:
john30
2015-05-01 08:34:27 +02:00
parent f1d76a64cc
commit 34efc9a5ae
2 changed files with 160 additions and 77 deletions
+62 -36
View File
@@ -71,8 +71,8 @@ void Connection::run()
#endif #endif
#endif #endif
time_t listenSince = 0;
bool closed = false; bool closed = false;
NetMessage message(m_isHttp);
while (!closed) { while (!closed) {
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
@@ -109,37 +109,39 @@ void Connection::run()
#endif #endif
} }
if (newData || m_listening) { if (newData || message.isListening()) {
char data[256]; char data[256];
size_t datalen = 0;
if (newData) {
if (!m_socket->isValid())
break;
datalen = m_socket->recv(data, sizeof(data)-1);
// remove closed socket
if (datalen <= 0)
break;
}
// decode client data
data[datalen] = '\0';
NetMessage message(data, m_listening, listenSince);
m_netQueue->add(&message);
// wait for result
logDebug(lf_network, "[%05d] wait for result", getID());
string result = message.getResult();
if (!m_socket->isValid()) if (!m_socket->isValid())
break; break;
m_socket->send(result.c_str(), result.size()); if (newData) {
m_listening = message.isListening(listenSince); size_t datalen = m_socket->recv(data, sizeof(data)-1);
if (message.isDisconnect()) // remove closed socket
if (datalen <= 0)
break;
data[datalen] = '\0';
} else {
data[0] = '\0';
}
// decode client data
if (message.add(data)) {
m_netQueue->add(&message);
// wait for result
logDebug(lf_network, "[%05d] wait for result", getID());
string result = message.getResult();
if (!m_socket->isValid())
break;
m_socket->send(result.c_str(), result.size());
}
if (message.isDisconnect() || !m_socket->isValid())
break; break;
} }
@@ -151,7 +153,7 @@ void Connection::run()
} }
Network::Network(const bool local, const uint16_t port, WQueue<NetMessage*>* netQueue) Network::Network(const bool local, const uint16_t port, const uint16_t httpPort, WQueue<NetMessage*>* netQueue)
: m_netQueue(netQueue), m_listening(false) : m_netQueue(netQueue), m_listening(false)
{ {
if (local) if (local)
@@ -162,6 +164,11 @@ Network::Network(const bool local, const uint16_t port, WQueue<NetMessage*>* net
if (m_tcpServer != NULL && m_tcpServer->start() == 0) if (m_tcpServer != NULL && m_tcpServer->start() == 0)
m_listening = true; m_listening = true;
if (httpPort>0) {
m_httpServer = new TCPServer(httpPort, "0.0.0.0");
m_httpServer->start();
} else
m_httpServer = NULL;
} }
Network::~Network() Network::~Network()
@@ -192,9 +199,9 @@ void Network::run()
// set timeout // set timeout
tdiff.tv_sec = 1; tdiff.tv_sec = 1;
tdiff.tv_nsec = 0; tdiff.tv_nsec = 0;
int socketCount = m_httpServer ? 2 : 1;
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
int nfds = 2; int nfds = 1+socketCount;
struct pollfd fds[nfds]; struct pollfd fds[nfds];
memset(fds, 0, sizeof(fds)); memset(fds, 0, sizeof(fds));
@@ -204,6 +211,11 @@ void Network::run()
fds[1].fd = m_tcpServer->getFD(); fds[1].fd = m_tcpServer->getFD();
fds[1].events = POLLIN; fds[1].events = POLLIN;
if (m_httpServer) {
fds[2].fd = m_httpServer->getFD();
fds[2].events = POLLIN;
}
#else #else
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
int maxfd; int maxfd;
@@ -212,9 +224,15 @@ void Network::run()
FD_ZERO(&checkfds); FD_ZERO(&checkfds);
FD_SET(m_notify.notifyFD(), &checkfds); FD_SET(m_notify.notifyFD(), &checkfds);
FD_SET(m_tcpServer->getFD(), &checkfds); FD_SET(m_tcpServer->getFD(), &checkfds);
if (m_httpServer) {
FD_SET(m_httpServer->getFD(), &checkfds);
}
(m_notify.notifyFD() > m_tcpServer->getFD()) ? maxfd = (m_notify.notifyFD() > m_tcpServer->getFD()) ?
(maxfd = m_notify.notifyFD()) : (maxfd = m_tcpServer->getFD()); m_notify.notifyFD() : m_tcpServer->getFD();
if (m_httpServer && m_httpServer->getFD()>maxfd) {
maxfd = m_httpServer->getFD();
}
#endif #endif
#endif #endif
@@ -236,7 +254,7 @@ void Network::run()
cleanConnections(); cleanConnections();
continue; continue;
} }
bool newData = false, isHttp = false;
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
// new data from notify // new data from notify
if (fds[0].revents & POLLIN) { if (fds[0].revents & POLLIN) {
@@ -245,6 +263,10 @@ void Network::run()
// new data from socket // new data from socket
if (fds[1].revents & POLLIN) { if (fds[1].revents & POLLIN) {
newData = true;
} else if (m_httpServer && fds[2].revents & POLLIN) {
newData = isHttp = true;
}
#else #else
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
// new data from notify // new data from notify
@@ -254,20 +276,24 @@ void Network::run()
// new data from socket // new data from socket
if (FD_ISSET(m_tcpServer->getFD(), &readfds)) { if (FD_ISSET(m_tcpServer->getFD(), &readfds)) {
newData = true;
} else if (m_httpServer && FD_ISSET(m_httpServer->getFD(), &readfds)) {
newData = isHttp = true;
}
#endif #endif
#endif #endif
if (newData) {
TCPSocket* socket = m_tcpServer->newSocket(); TCPSocket* socket = (isHttp ? m_httpServer : m_tcpServer)->newSocket();
if (socket == NULL) if (socket == NULL)
continue; continue;
Connection* connection = new Connection(socket, m_netQueue); Connection* connection = new Connection(socket, isHttp, m_netQueue);
if (connection == NULL) if (connection == NULL)
continue; continue;
connection->start("connection"); connection->start("connection");
m_connections.push_back(connection); m_connections.push_back(connection);
logInfo(lf_network, "[%05d] connection opened %s", connection->getID(), socket->getIP().c_str()); logInfo(lf_network, "[%05d] %s connection opened %s", connection->getID(), isHttp ? "HTTP" : "client", socket->getIP().c_str());
} }
} }
} }
+98 -41
View File
@@ -26,36 +26,36 @@
#include "notify.h" #include "notify.h"
#include "thread.h" #include "thread.h"
#include <string> #include <string>
#include <cstdio>
#include <algorithm>
/** \file network.h */ /** \file network.h */
using namespace std; using namespace std;
/** forward declaration for class connection */ /** Forward declaration for @a Connection. */
class Connection; class Connection;
/** /**
* class for data/message transfer between connection and baseloop. * Class for data/message transfer between @a Connection and @a MainLoop.
*/ */
class NetMessage class NetMessage
{ {
public: public:
/** /**
* constructs a new instance with data received from the client. * Constructor.
* @param data from client. * @param isHttp whether this is a HTTP message.
* @param listening whether the client is in listening mode.
* @param listenSince start timestamp of listening update.
*/ */
NetMessage(const string data, const bool listening, const time_t listenSince) NetMessage(const bool isHttp)
: m_data(data), m_resultSet(false), m_disconnect(false), m_listening(listening), m_listenSince(listenSince) : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listening(false), m_listenSince(0)
{ {
pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL); pthread_cond_init(&m_cond, NULL);
} }
/** /**
* destructor. * Destructor.
*/ */
~NetMessage() ~NetMessage()
{ {
@@ -73,10 +73,55 @@ private:
public: public:
/** /**
* get the data string. * Add request data received from the client.
* @return the data string. * @param request the request data from the client.
* @param listening whether the client is in listening mode.
* @param listenSince start timestamp of listening update.
* @return true when the request is complete and the response shall be prepared.
*/ */
string getData() const { return m_data; } bool add(string request)
{
if (request.length()>0) {
request.erase(remove(request.begin(), request.end(), '\r'), request.end());
m_request.append(request);
}
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
if (pos!=string::npos) {
if (m_isHttp) {
pos = m_request.find("\n");
m_request.resize(pos); // reduce to first line
// typical first line: GET /ehp/outsidetemp HTTP/1.1
pos = m_request.rfind(" HTTP/");
if (pos!=string::npos) {
m_request.resize(pos); // remove "HTTP/x.x" suffix
}
pos = 0;
while ((pos=m_request.find('%', pos))!=string::npos && pos+2<=m_request.length()) {
unsigned int value1, value2;
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2)<2)
break;
m_request[pos] = (char)(((value1&0x0f)<<4)|(value2&0x0f));
m_request.erase(pos+1, 2);
}
} else if (pos+1==m_request.length()) {
m_request.resize(pos); // reduce to complete lines
}
return true;
}
return m_request.length()==0 && m_listening;
}
/**
* Return whether this is a HTTP message.
* @return whether this is a HTTP message.
*/
bool isHttp() const { return m_isHttp; }
/**
* Return the request string.
* @return the request string.
*/
string getRequest() const { return m_request; }
/** /**
* Wait for the result being set and return the result string. * Wait for the result being set and return the result string.
@@ -89,9 +134,13 @@ public:
while (!m_resultSet) while (!m_resultSet)
pthread_cond_wait(&m_cond, &m_mutex); pthread_cond_wait(&m_cond, &m_mutex);
m_request.clear();
string result = m_result;
m_result.clear();
m_resultSet = false;
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
return m_result; return result;
} }
/** /**
@@ -103,12 +152,12 @@ public:
*/ */
void setResult(const string result, const bool listening, const time_t listenUntil, const bool disconnect) void setResult(const string result, const bool listening, const time_t listenUntil, const bool disconnect)
{ {
pthread_mutex_lock(&m_mutex);
m_result = result; m_result = result;
m_disconnect = disconnect; m_disconnect = disconnect;
m_listening = listening; m_listening = listening;
m_listenSince = listenUntil; m_listenSince = listenUntil;
m_resultSet = true; m_resultSet = true;
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond); pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
} }
@@ -118,7 +167,7 @@ public:
* @param listenSince set to the start time from which to add updates (inclusive). * @param listenSince set to the start time from which to add updates (inclusive).
* @return whether the client is in listening mode. * @return whether the client is in listening mode.
*/ */
bool isListening(time_t& listenSince) { listenSince = m_listenSince; return m_listening; } bool isListening(time_t* listenSince=NULL) { if (listenSince) *listenSince = m_listenSince; return m_listening; }
/** /**
* Return whether the client shall be disconnected. * Return whether the client shall be disconnected.
@@ -127,28 +176,31 @@ public:
bool isDisconnect() { return m_disconnect; } bool isDisconnect() { return m_disconnect; }
private: private:
/** the data string */ /** whether this is a HTTP message. */
string m_data; const bool m_isHttp;
/** the request string. */
string m_request;
/** whether the result was already set. */ /** whether the result was already set. */
bool m_resultSet; bool m_resultSet;
/** the result string */ /** the result string. */
string m_result; string m_result;
/** set to true when the client shall be disconnected. */ /** set to true when the client shall be disconnected. */
bool m_disconnect; bool m_disconnect;
/** mutex variable for exclusive lock */ /** mutex variable for exclusive lock. */
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
/** condition variable for exclusive lock */ /** condition variable for exclusive lock. */
pthread_cond_t m_cond; pthread_cond_t m_cond;
/** whether the client is in listening mode */ /** whether the client is in listening mode. */
bool m_listening; bool m_listening;
/** start timestamp of listening update */ /** start timestamp of listening update. */
time_t m_listenSince; time_t m_listenSince;
}; };
@@ -161,12 +213,13 @@ class Connection : public Thread
public: public:
/** /**
* create a new connection instance. * Constructor.
* @param socket the tcp socket for communication. * @param socket the @a TCPSocket for communication.
* @param netQueue the remote queue for network messages. * @param isHttp whether this is a HTTP message.
* @param netQueue the remote @a WQueue for handling @a NetMessage instances.
*/ */
Connection(TCPSocket* socket, WQueue<NetMessage*>* netQueue) Connection(TCPSocket* socket, const bool isHttp, WQueue<NetMessage*>* netQueue)
: m_socket(socket), m_netQueue(netQueue), m_listening(false) : m_isHttp(isHttp), m_socket(socket), m_netQueue(netQueue)
{ m_id = ++m_ids; } { m_id = ++m_ids; }
virtual ~Connection() { if (m_socket) delete m_socket; } virtual ~Connection() { if (m_socket) delete m_socket; }
@@ -176,35 +229,35 @@ public:
virtual void run(); virtual void run();
/** /**
* close active connection. * Stop this connection.
*/ */
virtual void stop() { m_notify.notify(); Thread::stop(); } virtual void stop() { m_notify.notify(); Thread::stop(); }
/** /**
* return own connection id. * Return the ID of this connection.
* @return id of current connection. * @return the ID of this connection.
*/ */
int getID() { return m_id; } int getID() { return m_id; }
private: private:
/** the tcp socket instance */ /** whether this is a HTTP connection. */
const bool m_isHttp;
/** the @a TCPSocket for communication. */
TCPSocket* m_socket; TCPSocket* m_socket;
/** remote queue for network messages */ /** the remote @a WQueue for handling @a NetMessage instances. */
WQueue<NetMessage*>* m_netQueue; WQueue<NetMessage*>* m_netQueue;
/** notification object for shutdown procedure */ /** notification object for shutdown procedure. */
Notify m_notify; Notify m_notify;
/** id of current connection */ /** the ID of this connection. */
int m_id; int m_id;
/** sumary for opened connections */ /** the IF of the last opened connection. */
static int m_ids; static int m_ids;
/** whether the client is in listening mode */
bool m_listening;
}; };
/** /**
@@ -217,10 +270,11 @@ public:
/** /**
* create a network instance and listening for incoming connections. * create a network instance and listening for incoming connections.
* @param local true to accept connections only for local host. * @param local true to accept connections only for local host.
* @param port the tcp port to listening. * @param port the port to listen for command line connections.
* @param httpPort the port to listen for HTTP connections, or 0.
* @param netQueue the remote queue for network messages. * @param netQueue the remote queue for network messages.
*/ */
Network(const bool local, const uint16_t port, WQueue<NetMessage*>* netQueue); Network(const bool local, const uint16_t port, const uint16_t httpPort, WQueue<NetMessage*>* netQueue);
/** /**
* destructor. * destructor.
@@ -244,9 +298,12 @@ private:
/** the @a MainLoop queue for transferring @a NetMessage instances. */ /** the @a MainLoop queue for transferring @a NetMessage instances. */
WQueue<NetMessage*>* m_netQueue; WQueue<NetMessage*>* m_netQueue;
/** the @a TCPServer instance. */ /** the command line @a TCPServer instance. */
TCPServer* m_tcpServer; TCPServer* m_tcpServer;
/** the HTTP @a TCPServer instance, or NULL. */
TCPServer* m_httpServer;
/** @a Notify object for shutdown procedure. */ /** @a Notify object for shutdown procedure. */
Notify m_notify; Notify m_notify;