- Se mejora mucho el manejo y deteccion de errores.
- Tambien se mejora la informacion de debug poniendo el numero de linea.
- Se pone en todos los objetos que se conectan la parte de la conexion en el
constructor para que pueda capturarse una eventual excepcion.
- Se crea una nueva signal_error para avisar sobre cualquier error que pase en
el run() que no puede lanzar excepciones.
##
AC_INIT(configure.in)
-AM_INIT_AUTOMAKE(plaqui_server, 0.9)
+AM_INIT_AUTOMAKE(plaqui_server, 0.10)
AM_MAINTAINER_MODE
AC_ISC_POSIX
#ifndef PLAQUI_COMMAND_H
#define PLAQUI_COMMAND_H
+#include "httperror.h"
#include "httprequest.h"
+#include <socket++/sockstream.h>
#include <string>
#include <vector>
#include <istream>
* Obtiene el comando desde un pedido HTTP completo.
*/
friend std::istream& operator>>(std::istream& is,
- Command& command);
+ Command& command) throw(HTTPError, sockerr);
/**
* Convierte el comando a un pedido HTTP completo.
*/
friend std::ostream& operator<<(std::ostream& os,
- const Command& command);
+ const Command& command) throw(sockerr);
};
* control.
* \param port Puerto al cual conectarse.
*/
- ControlClient(const std::string& host = "localhost",
- const Connection::Port& port = 7522);
+ ControlClient(const std::string& _host = "localhost",
+ const Connection::Port& _port = 7522) throw(sockerr);
/**
* Envía un comando al servidor.
#define PLAQUI_HTTPHEADERS_H
#include "plaqui/server/httperror.h"
+#include <socket++/sockstream.h>
#include <map>
#include <string>
#include <istream>
* Obtiene los datos de las cabeceras HTTP desde un texto.
*/
friend std::istream& operator>>(std::istream& is, HTTPHeaders& h)
- throw(HTTPError);
+ throw(HTTPError, sockerr, ios::failure);
/**
* Convierte las cabeceras HTTP a texto.
*/
friend std::ostream& operator<<(std::ostream& os,
- const HTTPHeaders& h);
+ const HTTPHeaders& h) throw(sockerr);
};
#include "plaqui/server/httperror.h"
#include "plaqui/server/httpmessage.h"
+#include <socket++/sockstream.h>
#include <string>
#include <istream>
#include <ostream>
* Obtiene los datos del pedido HTTP desde un texto.
*/
friend std::istream& operator>>(std::istream& is, HTTPRequest& req)
- throw(HTTPError, std::ios::failure);
+ throw(HTTPError, sockerr, std::ios::failure);
/**
* Convierte el pedido HTTP en texto.
*/
friend std::ostream& operator<<(std::ostream& os,
- const HTTPRequest& req);
+ const HTTPRequest& req) throw(sockerr);
};
#include "plaqui/server/httperror.h"
#include "plaqui/server/httpmessage.h"
+#include <socket++/sockstream.h>
#include <string>
namespace PlaQui {
* Obtiene los datos de la respuesta HTTP desde un texto.
*/
friend std::istream& operator>>(std::istream& is,
- HTTPResponse& resp) throw(Error, std::ios::failure);
+ HTTPResponse& resp)
+ throw(Error, sockerr, std::ios::failure);
/**
* Convierte la respuesta HTTP en texto.
*/
friend std::ostream& operator<<(std::ostream& os,
- const HTTPResponse& resp);
+ const HTTPResponse& resp) throw(sockerr);
};
* \param host Host del cual recibir el estado de la planta.
*/
Receiver(const Connection::Port& port = 7528,
- const std::string& host = "localhost");
+ const std::string& host = "localhost") throw(sockerr);
/**
* Obtiene la señal que avisa cuando se recibió un cuadro.
public:
+ /// Error.
+ typedef unsigned Error;
+
/// Tipo de señal para indicar que se finalizó la tarea.
typedef SigC::Signal0<void> SignalFinished;
+ /// Tipo de señal para indicar que hubo un error.
+ typedef SigC::Signal2<void, const Error&, const std::string&> SignalError;
+
// Atributos.
private:
protected:
+ /// Señal que indica que hubo un error.
+ SignalError error;
+
/**
* Indica si se debe frinalizar la tarea.
*
/**
* Obtiene la señal que avisa cuando la tarea es finalizada.
- *
- * \see finish().
*/
SignalFinished& signal_finished(void);
+ /**
+ * Obtiene la señal que avisa que hubo un error.
+ */
+ SignalError& signal_error(void);
+
};
}
* \param port Puerto en el cual escuchar.
*/
Server(const std::string& plant_filename,
- const Connection::Port& port = 7522);
+ const Connection::Port& port = 7522) throw(sockerr);
/**
* Maneja los comandos recibidos por las conexiones.
*
* \param port Puerto en el cual escuchar.
*/
- TCPServer(const Connection::Port& port);
+ TCPServer(const Connection::Port& port) throw(sockerr);
/**
* Finaliza la tarea.
* \note Para saber cuando la tarea fue finalizada puede utilizar
* la señal signal_finished().
*/
- virtual void finish(bool attach = false);
+ //virtual void finish(bool attach = false);
/**
* Se encarga de borrar una conexión de la lista cuando finaliza.
* \param host Host al cual transmitir.
* \param port Puerto al cual transmitir.
*/
- Transmitter(std::string& _host, Connection::Port& _port);
+ Transmitter(const std::string& _host,
+ const Connection::Port& _port) throw(sockerr);
/**
* Envia datos.
#include "plaqui/server/command.h"
#include "plaqui/server/string.h"
#include <algorithm>
+//#include <exception>
#ifdef DEBUG
# include <iostream>
#endif // DEBUG
Command::~Command(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
Command::Command(const string& _target, const string& _command) {
#ifdef DEBUG
- cerr << __FILE__ << ": target = " << target << " | "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": target = " << target << " | "
<< "command = " << command << endl;
#endif // DEBUG
set_target(_target);
}
}
#ifdef DEBUG
- cerr << __FILE__ << ": build() = " << uri << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": build() = " << uri << endl;
#endif // DEBUG
}
void Command::add_arg(const unsigned& arg) {
#ifdef DEBUG
- cerr << __FILE__ << ": add_arg(arg = " << arg << ") = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": add_arg(arg = " << arg << ") = "
<< String().from(arg) << endl;
#endif // DEBUG
args.push_back(String().from(arg));
build();
}
-istream& operator>>(istream& is, Command& command) {
+istream& operator>>(istream& is, Command& command) throw(HTTPError, sockerr) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator>>()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator>>()" << endl;
#endif // DEBUG
// Obtengo datos del Request HTTP.
is >> static_cast<HTTPRequest&>(command);
return is;
}
-ostream& operator<<(ostream& os, const Command& command) {
+ostream& operator<<(ostream& os, const Command& command) throw (sockerr) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator<<()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator<<()" << endl;
#endif // DEBUG
// Manda el request HTTP con la URI que representa el comando.
os << static_cast<const HTTPRequest&>(command);
Connection::~Connection(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
Connection::Connection(const sockbuf::sockdesc& sd):
socket(sd) {
#ifdef DEBUG
- cerr << __FILE__ << ": sd = " << sd.sock;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": sd = " << sd.sock;
#endif // DEBUG
host = socket->peerhost();
port = socket->peerport();
Connection::Connection(const sockbuf::type& type, const std::string& host,
const Port& port): socket(type), host(host), port(port) {
#ifdef DEBUG
- cerr << __FILE__ << ": type = " << type << " | host = " << host
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": type = " << type << " | host = " << host
<< " | port = " << port << endl;
#endif // DEBUG
}
Connection::Connection(const std::string& host, const Port& port):
host(host), port(port) {
#ifdef DEBUG
- cerr << __FILE__ << ": host = " << host << " | port = " << port << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": host = " << host << " | port = " << port << endl;
#endif // DEBUG
}
void Connection::finish(bool attach) {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": finish(attach = " << attach << ")." << endl;
+#endif // DEBUG
//socket_mutex.lock();
- socket->shutdown(sockbuf::shut_readwrite);
+ try {
+ socket->shutdown(sockbuf::shut_readwrite);
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ }
//socket_mutex.unlock();
Runnable::finish(attach);
}
ControlClient::~ControlClient(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
// TODO Temporal: espero que el receiver muera.
receiver.finish(true);
}
-ControlClient::ControlClient(const string& host, const Connection::Port& port):
- Connection(sockbuf::sock_stream, host, port) {
+ControlClient::ControlClient(const string& _host,
+ const Connection::Port& _port) throw(sockerr):
+ Connection(sockbuf::sock_stream, _host, _port) {
#ifdef DEBUG
- cerr << __FILE__ << ": host = " << host
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": host = " << host
<< " | port = " << port << endl;
#endif // DEBUG
+ socket->connect(host.c_str(), port);
+ host = socket->localhost();
+ port = socket->localport();
}
void ControlClient::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run." << endl;
#endif // DEBUG
try {
- socket->connect(host.c_str(), port);
} catch (const sockerr& e) {
- // Poner una señal de error específica?
- error_received(1);
- finish();
+ // TODO Poner una señal de error específica?
+ error(e.serrno(), e.errstr());
return;
}
- host = socket->localhost();
- port = socket->localport();
// TODO sacar signal_connected?
connected();
// TODO Temporal: el receiver empieza a escuchar.
socket >> response;
// Si se cerró el socket.
} catch (const ios::failure& e) {
- stop = true;
- continue;
+ // TODO poner buenos codigos de error.
+ error(1000000, "Se desconectó.");
+ return;
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ return;
// Si hay un error al parsear la respuesta.
} catch (const HTTPResponse::Error& e) {
#ifdef DEBUG
- cerr << __FILE__ << " : real_run() ERROR nro: " << e << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << " : real_run() ERROR nro: " << e << endl;
#endif // DEBUG
- // TODO - pasar como parametro codigo de error o algo.
+ // TODO - es un error recuperable? O manda señal error()?
error_received(e);
continue;
}
}
void ControlClient::send(const Command& command) {
- socket << command << flush;
+ try {
+ socket << command << flush;
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ finish();
+ }
#ifdef DEBUG
- cerr << __FILE__ << ": send() Enviado!" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": send() Enviado!" << endl;
#endif // DEBUG
}
// TODO - temporal
Receiver::SignalFrameReceived& ControlClient::signal_frame_received(void) {
+ // XXX - cuidado, esto puede dar quilombo si no esta protegido por un mutex,
+ // aunque no deberia porque la señal no es llamada hasta que no se empice
+ // la transmision y la señal se conecta antes de pedir la transmision.
return receiver.signal_frame_received();
}
ControlServer::~ControlServer(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
ControlServer::ControlServer(const sockbuf::sockdesc& sd):
Connection(sd) {
#ifdef DEBUG
- cerr << __FILE__ << ": sd = " << sd.sock << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": sd = " << sd.sock << endl;
#endif // DEBUG
}
void ControlServer::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run()" << endl;
#endif // DEBUG
//char buf[BUFSIZ];
while (!stop) {
try {
//Glib::Mutex::Lock lock(socket_mutex);
socket >> command;
- // Si se cerró el socket.
} catch (const ios::failure& e) {
- stop = true;
- continue;
+ // TODO poner buenos codigos de error.
+ error(1000000, "Se desconectó.");
+ return;
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ return;
+ // Si se cerró el socket.
+ //} catch (const ios::failure& e) {
+ // stop = true;
+ // continue;
// Si hay un error al parsear el comando, se envia una respuesta con el
// error.
} catch (const HTTPError& e) {
#ifdef DEBUG
- cerr << __FILE__ << " : real_run() ERROR: status_code = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << " : real_run() ERROR: status_code = "
<< e.code << " | reason = " << HTTPMessage::reason(e.code)
<< " | desc = " << e.what() << endl;
#endif // DEBUG
bool is_first = true;
while (!stop && socket.getline(buf, BUFSIZ)) {
#ifdef DEBUG
- cerr << __FILE__ << " Recibiendo inea: " << buf << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << " Recibiendo inea: " << buf << endl;
#endif // DEBUG
int len = strlen(buf);
// Si tiene un retorno de carro, lo elimina.
}
*/
#ifdef DEBUG
- cerr << __FILE__ << " : real_run() Despachando comando: target = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << " : real_run() Despachando comando: target = "
<< command.get_target() << " | command = " << command.get_command()
<< " | args = [" << String::join(command.get_args(), ", ") << "]"
<< endl;
//Glib::Mutex::Lock lock(socket_mutex);
socket << response << flush;
#ifdef DEBUG
- cerr << __FILE__ << ": send() Enviado!" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": send() Enviado!" << endl;
#endif // DEBUG
}
HTTPError::~HTTPError(void) throw() {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
HTTPError::HTTPError(unsigned code, const std::string& desc) throw():
runtime_error(desc), code(code) {
#ifdef DEBUG
- cerr << __FILE__ << ": code = " << code << " | desc = " << desc << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": code = " << code << " | desc = " << desc << endl;
#endif // DEBUG
}
// $Id$
//
-#include "plaqui/server/httpheaders.h"
#include "plaqui/server/httperror.h"
+#include "plaqui/server/httpmessage.h"
+#include "plaqui/server/httpheaders.h"
#include "plaqui/server/string.h"
//#include <cstdlib>
#ifdef DEBUG
HTTPHeaders::~HTTPHeaders(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
-istream& operator>>(istream& is, HTTPHeaders& h) throw(HTTPError) {
+istream& operator>>(istream& is, HTTPHeaders& h)
+ throw(HTTPError, sockerr, ios::failure) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator>>()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator>>()" << endl;
#endif // DEBUG
char buf[BUFSIZ];
- is.getline(buf, BUFSIZ);
+ // Fin del stream, no había cabeceras.
+ if (!is.getline(buf, BUFSIZ)) {
+ throw ios::failure("eof");
+ }
string sbuf = buf;
string::size_type pos = sbuf.find(":");
if (pos == string::npos) {
// FIXME poner mejores excepciones.
- throw HTTPError(400, sbuf + ": No es una cabecera válida.");
+ throw HTTPError(HTTPMessage::BAD_REQUEST, sbuf + ": No es una cabecera válida.");
}
h[sbuf.substr(0, pos)] = String(sbuf.substr(pos + 1)).trim();
#ifdef DEBUG
- cerr << __FILE__ << " " << sbuf.substr(0, pos) << " = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << " " << sbuf.substr(0, pos) << " = "
<< h[sbuf.substr(0, pos)] << endl;
#endif // DEBUG
return is;
}
-ostream& operator<<(ostream& os, const HTTPHeaders& h) {
+ostream& operator<<(ostream& os, const HTTPHeaders& h) throw(sockerr) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator<<()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator<<()" << endl;
#endif // DEBUG
for (HTTPHeaders::const_iterator i = h.begin();
i != h.end(); ++i) {
HTTPMessage::~HTTPMessage(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
HTTPMessage::HTTPMessage(const string& _body, const string& _version):
version(_version) {
#ifdef DEBUG
- cerr << __FILE__ << ": version = " << version << " | body ("
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": version = " << version << " | body ("
<< _body.length() << ") = " << _body << endl;
#endif // DEBUG
headers["Accept-Ranges"] = "bytes";
istream& operator>>(istream& is, HTTPMessage& m) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator>>()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator>>()" << endl;
#endif // DEBUG
char buf[BUFSIZ];
while (is.getline(buf, BUFSIZ)) {
ostream& operator<<(ostream& os, const HTTPMessage& m) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator<<()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator<<()" << endl;
#endif // DEBUG
return os << m.headers << "\r\n" // Fin de cabeceras
<< m.body;
HTTPRequest::~HTTPRequest(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
const string& query, const string& body, const string& version):
HTTPMessage(body, version), method(method), uri(uri), query(query) {
#ifdef DEBUG
- cerr << __FILE__ << ": uri = " << uri << " | "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": uri = " << uri << " | "
<< "method = " << method_str() << " | "
<< "query = " << query << " | "
<< "body.length = " << body.length() << " | "
}
istream& operator>>(istream& is, HTTPRequest& req)
- throw(HTTPError, ios::failure) {
+ throw(HTTPError, sockerr, ios::failure) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator>>()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator>>()" << endl;
#endif // DEBUG
char buf[BUFSIZ];
// Obtengo primera línea (request)
if (!is.getline(buf, BUFSIZ)) {
- // No hay más líneas.
- throw ios::failure("socket closed");
+ // Fin de archivo.
+ throw ios::failure("eof");
}
#ifdef DEBUG
- cerr << __FILE__ << ":\tRecibiendo linea: " << buf << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ":\tRecibiendo linea: " << buf << endl;
#endif // DEBUG
String line(buf);
// Si es la primera línea, es el request.
return is;
}
-ostream& operator<<(ostream& os, const HTTPRequest& req) {
+ostream& operator<<(ostream& os, const HTTPRequest& req) throw(sockerr) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator<<()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator<<()" << endl;
#endif // DEBUG
os << req.method_str() << " " << req.uri;
if (req.query.length()) {
HTTPResponse::~HTTPResponse(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
HTTPResponse::HTTPResponse(const string& body, const string& version):
HTTPMessage(body, version) {
#ifdef DEBUG
- cerr << __FILE__ << ": body.length = " << body.length()
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": body.length = " << body.length()
<< " | version = " << version << endl;
#endif // DEBUG
}
HTTPResponse::HTTPResponse(const HTTPError& error):
status_code(error.code) {
#ifdef DEBUG
- cerr << __FILE__ << ": HTTPError(status_code = " << error.code
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": HTTPError(status_code = " << error.code
<< ", reason = " << HTTPMessage::reason(error.code) << ", desc = " << error.what()
<< ")" << endl;
#endif // DEBUG
- set_body(string("<plaqui><error desc=\"") + error.what() + "\" /></plaqui>");
+ set_body(string("<response desc=\"") + error.what() + "\" />");
}
HTTPResponse::HTTPResponse(unsigned status_code, const string& body):
HTTPMessage(body), status_code(status_code) {
#ifdef DEBUG
- cerr << __FILE__ << ": status_code = " << status_code
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": status_code = " << status_code
<< " | body.length = " << body.length() << endl;
#endif // DEBUG
}
istream& operator>>(istream& is, HTTPResponse& resp)
- throw (HTTPResponse::Error, ios::failure) {
+ throw (HTTPResponse::Error, sockerr, ios::failure) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator>>()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator>>()" << endl;
#endif // DEBUG
char buf[BUFSIZ];
// Obtengo primera línea (request)
if (!is.getline(buf, BUFSIZ)) {
- // No hay mas líneas.
- throw ios::failure("socket closed");
+ // Fin de archivo.
+ throw ios::failure("eof");
}
#ifdef DEBUG
- cerr << __FILE__ << ":\tRecibiendo linea: " << buf << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ":\tRecibiendo linea: " << buf << endl;
#endif // DEBUG
String line(buf);
// Si es la primera línea, es el request.
return is;
}
-ostream& operator<<(ostream& os, const HTTPResponse& resp) {
+ostream& operator<<(ostream& os, const HTTPResponse& resp) throw(sockerr) {
#ifdef DEBUG
- cerr << __FILE__ << ": operator<<()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": operator<<()" << endl;
#endif // DEBUG
os << "HTTP/" << resp.version << " " << resp.status_code << " "
<< HTTPMessage::reason(resp.status_code) << "\r\n";
#include <glibmm/timer.h>
#include <sigc++/slot.h>
#include <fstream>
-#include <iterator>
-#include <algorithm>
#ifdef DEBUG
# include <iostream>
#endif // DEBUG
Plant::~Plant(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
// Termino transmisiones.
Glib::Mutex::Lock lock(transmissions_mutex);
Plant::Plant(const string& filename): simulator(filename), filename(filename) {
#ifdef DEBUG
- cerr << __FILE__ << ": constructor. filename = " << filename << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": constructor. filename = " << filename << endl;
#endif // DEBUG
// TODO plant
/* simulator.add_pump("bomba1");
void Plant::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run." << endl;
#endif // DEBUG
while (!stop) {
simulator_mutex.lock();
}
bool Plant::transmission_start(string& host, Connection::Port& port) {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": transmission_start(host = " << host <<
+ ", port = " << port << ")." << endl;
+#endif // DEBUG
Glib::Mutex::Lock lock(transmissions_mutex);
for (TransmitterList::iterator i = transmissions.begin();
i != transmissions.end(); i++) {
if (((*i)->get_host() == host) && ((*i)->get_port() == port)) {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": transmission_start ERROR: ya existe."
+ << endl;
+#endif // DEBUG
return false;
}
}
Transmitter* trans;
try {
trans = new Transmitter(host, port);
- } catch (...) { // TODO - Hace mas selectivo el catch?
- delete trans;
+ } catch (const sockerr& e) { // TODO - Hace mas selectivo el catch?
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": transmission_start ERROR (" << e.serrno()
+ << "): " << e.errstr() << endl;
+#endif // DEBUG
+ //delete trans;
return false;
+// } catch (...) { // TODO - Hace mas selectivo el catch?
+//#ifdef DEBUG
+// cerr << __FILE__ << "(" << __LINE__ << ")"
+// << ": transmission_start ERROR: desconocido."
+// << endl;
+//#endif // DEBUG
+// //delete trans;
+// return false;
}
transmissions.push_back(trans);
trans->run();
+ host = trans->get_host();
+ port = trans->get_port();
return true;
}
bool Plant::transmission_stop(const string& host,
const Connection::Port& port) {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": transmission_stop(host = " << host <<
+ ", port = " << port << ")." << endl;
+#endif // DEBUG
Glib::Mutex::Lock lock(transmissions_mutex);
for (TransmitterList::iterator i = transmissions.begin();
i != transmissions.end(); i++) {
}
bool Plant::set_open(const std::string& element, bool open) {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": set_open(element = " << element <<
+ ", open = " << open << ")." << endl;
+#endif // DEBUG
Glib::Mutex::Lock lock(simulator_mutex);
return simulator.set_open(element, open);
}
const string Plant::get_xml(void) const {
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": get_xml()." << endl;
+#endif // DEBUG
ostringstream oss;
- try {
- ifstream ifs(filename.c_str());
- ifs >> noskipws;
- copy(istream_iterator<char>(ifs), istream_iterator<char>(),
- ostream_iterator<char>(oss));
- } catch (...) { // TODO hacerlo mas selectivo?
- return "";
- }
+ ifstream ifs(filename.c_str());
+ ifs >> oss.rdbuf();
return oss.str();
}
}
*/
-//const std::string& Plant::get_name(void) const {
-// return name;
+//const std::string& Plant::get_filename(void) const {
+// return filename;
//}
/// \todo FIXME esto deberia estar protegido por un mutex.
Receiver::~Receiver(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
-Receiver::Receiver(const Connection::Port& port, const string& host):
- Connection(sockbuf::sock_dgram, host, port) {
+Receiver::Receiver(const Connection::Port& port, const string& host)
+ throw(sockerr): Connection(sockbuf::sock_dgram, host, port) {
#ifdef DEBUG
- cerr << __FILE__ << ": port = " << port
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": port = " << port
<< " | host = " << host << endl;
#endif // DEBUG
//socket->bind(port);
// XXX EL XML DEBE EMPEZAR Y FINALIZAR EN UNA LINEA SEPARADA.
void Receiver::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run." << endl;
#endif // DEBUG
char buf[BUFSIZ];
bool in_frame = false;
stringstream ss;
- while (!stop && socket.getline(buf, BUFSIZ)) {
+ while (!stop) {
+ try {
+ if (!socket.getline(buf, BUFSIZ)) {
+ return; // Se terminó la transmision.
+ }
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ return;
+ }
string sbuf = buf;
if (in_frame) {
string::size_type pos = sbuf.find(FRAME_END);
Runnable::~Runnable(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor(this = " << this << ")"
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor(this = " << this << ")"
<< endl;
#endif // DEBUG
}
Runnable::Runnable(void): thread(0), stop(false) {
#ifdef DEBUG
- cerr << __FILE__ << ": constructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": constructor." << endl;
#endif // DEBUG
}
void Runnable::static_run(Runnable* runner) {
#ifdef DEBUG
- cerr << __FILE__ << ": static_run(runner = " << runner << ")"
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": static_run(runner = " << runner << ")"
<< endl;
#endif // DEBUG
runner->real_run();
void Runnable::run(bool detach) {
#ifdef DEBUG
- cerr << __FILE__ << ": run(detach = " << detach << ")" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": run(detach = " << detach << ")" << endl;
#endif // DEBUG
// Si vamos a correr la tarea en un thread.
if (detach) {
void Runnable::finish(bool attach) {
#ifdef DEBUG
- cerr << __FILE__ << ": finish(attach = " << attach << ")" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": finish(attach = " << attach << ")" << endl;
#endif // DEBUG
stop = true;
if (attach) {
return finished;
}
+Runnable::SignalError& Runnable::signal_error(void) {
+ return error;
+}
+
} // namespace Server
} // namespace PlaQui
#include "plaqui/server/connection.h"
#include "plaqui/server/controlserver.h"
#include <sigc++/class_slot.h>
-// FIXME - sacar sstream (a menos que se necesite)
#include <sstream>
+#include <exception>
#ifdef DEBUG
# include "plaqui/server/string.h"
# include <iostream>
Server::~Server(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
// Termino plantas.
Glib::Mutex::Lock lock(plants_mutex);
}
}
-Server::Server(const string& plant_filename, const Connection::Port& port):
- TCPServer(port) {
+Server::Server(const string& plant_filename, const Connection::Port& port)
+ throw(sockerr): TCPServer(port) {
#ifdef DEBUG
- cerr << __FILE__ << ": port = " << port << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": port = " << port << endl;
#endif // DEBUG
// FIXME
Glib::Mutex::Lock lock(plants_mutex);
plants["default"]->run();
}
-Connection* Server::new_connection(
- const sockbuf::sockdesc& sd) {
+Connection* Server::new_connection(const sockbuf::sockdesc& sd) {
#ifdef DEBUG
- cerr << __FILE__ << ": new_connection(sd = " << sd.sock << ")"
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": new_connection(sd = " << sd.sock << ")"
<< endl;
#endif // DEBUG
ControlServer* connection = new ControlServer(sd);
return connection;
}
-void Server::on_plant_updated(const Plant* plant) {
-#ifdef DEBUG
- cerr << __FILE__ << ": on_plant_updated(plant = " << plant << ")." << endl;
-#endif // DEBUG
-}
-
void Server::on_plant_finished(const char* plant) {
#ifdef DEBUG
- cerr << __FILE__ << ": on_plant_finished(plant_name = " << plant << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": on_plant_finished(plant_name = " << plant << endl;
#endif // DEBUG
Glib::Mutex::Lock lock(plants_mutex);
plants.erase(plant);
void Server::on_control_command_received(const Command& command,
ControlServer* controlserver) {
#ifdef DEBUG
- cerr << __FILE__ << ": on_control_command_received(target = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": on_control_command_received(target = "
<< command.get_target() << ", command = " << command.get_command()
<< ", args = [" << String::join(command.get_args(), ", ") << "])"
<< endl;
// FIXME
stringstream xml;
xml << "<serverstatus>" << endl;
- xml << "\t<version>0.9</version>" << endl;
+ xml << "\t<version>" VERSION "</version>" << endl;
xml << "\t<authors>" << endl;
xml << "\t\t<author>Nicolás Dimov</author>" << endl;
xml << "\t\t<author>Leandro Lucarella</author>" << endl;
return new HTTPResponse(HTTPMessage::NOT_FOUND,
string("<response desc=\"No existe la planta ") + plant + "\" />");
}
+ // TODO try/catch?
string xml = plants[plant]->get_xml();
if (xml.length()) {
return new HTTPResponse(HTTPMessage::OK, xml);
TCPServer::~TCPServer(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
Glib::Mutex::Lock lock(connections_mutex);
for (ConnectionList::iterator con = connections.begin();
}
}
-TCPServer::TCPServer(const Connection::Port& port): socket(sockbuf::sock_stream) {
+TCPServer::TCPServer(const Connection::Port& port) throw(sockerr):
+ socket(sockbuf::sock_stream) {
#ifdef DEBUG
- cerr << __FILE__ << ": port = " << port << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": port = " << port << endl;
#endif // DEBUG
// FIXME
//cerr << "recvtimeout = " << socket.recvtimeout(1) << endl;
//cerr << "sendtimeout = " << socket.sendtimeout(1) << endl;
socket.bind(port);
#ifdef DEBUG
- cerr << __FILE__ << ": escuchando en " << socket.localhost()
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": escuchando en " << socket.localhost()
<< ":" << socket.localport() << "." << endl;
#endif // DEBUG
socket.listen(MAX_PENDING_CONNECTIONS);
#ifdef DEBUG
- cerr << __FILE__ << ": [despues de listen()] escuchando en "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": [despues de listen()] escuchando en "
<< socket.localhost() << ":" << socket.localport() << "." << endl;
#endif // DEBUG
}
-void TCPServer::finish(bool attach) {
+/*void TCPServer::finish(bool attach) {
//socket_mutex.lock();
socket.shutdown(sockbuf::shut_readwrite);
//socket_mutex.unlock();
Runnable::finish(attach);
-}
+}*/
void TCPServer::on_connection_finished(Connection* connection) {
#ifdef DEBUG
- cerr << __FILE__ << ": on_connection_finished(connection = "
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": on_connection_finished(connection = "
<< connection << ")" << endl;
#endif // DEBUG
Glib::Mutex::Lock lock(connections_mutex);
connections.remove(connection);
#ifdef DEBUG
- cerr << __FILE__ << ": lista de conexiones" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": lista de conexiones" << endl;
for (ConnectionList::const_iterator i = connections.begin();
i != connections.end(); i++) {
cerr << "\t " << *i << endl;
/// \todo TODO: ver tema de timeout o como salir de un accept().
void TCPServer::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run()" << endl;
#endif // DEBUG
Connection* connection;
while (!stop) {
// Forma grasa de salir del accept: crear conexion que salga al toque.
- connection = new_connection(socket.accept());
+ try {
+ connection = new_connection(socket.accept());
+ } catch (const sockerr& e) { // No se si el accept() puede fallar.
+ error(e.serrno(), e.errstr());
+ continue; // Supongo que puede seguir aceptando conexiones.
+ }
#ifdef DEBUG
- cerr << __FILE__ << ": real_run(): connection = " << connection
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run(): connection = " << connection
<< endl;
#endif // DEBUG
Glib::Mutex::Lock lock(connections_mutex);
// XXX connections_mutex.lock();
connections.push_back(connection);
#ifdef DEBUG
- cerr << __FILE__ << ": real_run(): lista de conexiones" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run(): lista de conexiones" << endl;
for (ConnectionList::const_iterator i = connections.begin();
i != connections.end(); i++) {
cerr << "\t " << *i << endl;
bool TCPServer::disconnect(const std::string& host, const Connection::Port& port) {
#ifdef DEBUG
- cerr << __FILE__ << ": disconnect(host = " << host
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": disconnect(host = " << host
<< ", port = " << port << ")" << endl;
#endif // DEBUG
Glib::Mutex::Lock lock(connections_mutex);
return false;
}
+/// \todo TODO Hay que reemplazarlo por una lista generica.
TCPServer::ConnectionInfoList TCPServer::get_connected(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": get_connected()" << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": get_connected()" << endl;
#endif // DEBUG
TCPServer::ConnectionInfoList cl;
Glib::Mutex::Lock lock(connections_mutex);
Transmitter::~Transmitter(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": destructor." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": destructor." << endl;
#endif // DEBUG
}
-Transmitter::Transmitter(string& _host, Connection::Port& _port):
- Connection(sockbuf::sock_dgram, _host, _port) {
+Transmitter::Transmitter(const string& _host, const Connection::Port& _port)
+ throw(sockerr): Connection(sockbuf::sock_dgram, _host, _port) {
#ifdef DEBUG
- cerr << __FILE__ << ": _host = " << _host
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": _host = " << _host
<< " | _port = " << _port << endl;
#endif // DEBUG
socket->connect(host.c_str(), port);
- // Reasigno el host y puerto bien, tanto de este objeto como los que se
- // environ para indicar su valor correcto.
- host = socket->peerhost();
- port = socket->peerport();
- _host = socket->peerhost();
- _port = socket->peerport();
+ // Reasigno el host y puerto bien.
+ host = socket->peerhost();
+ port = socket->peerport();
+#ifdef DEBUG
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": (real) host = " << _host
+ << " | port = " << _port << endl;
+#endif // DEBUG
}
/// \todo debría dar una excepción (?)
void Transmitter::real_run(void) {
#ifdef DEBUG
- cerr << __FILE__ << ": real_run()." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": real_run()." << endl;
#endif // DEBUG
// No hace nada, porque solo actua cuando se manda algo con send().
while (!stop) {
- Glib::usleep(1000);
+ Glib::usleep(500000); // 1/2 segundo
}
}
void Transmitter::send(const string& data) {
#ifdef DEBUG
- cerr << __FILE__ << ": send(data = " << data << ")." << endl;
+ cerr << __FILE__ << "(" << __LINE__ << ")"
+ << ": send(data = " << data << ")." << endl;
#endif // DEBUG
- socket << data << flush;
+ if (stop) {
+ return;
+ }
+ try {
+ socket << data << flush;
+ } catch (const sockerr& e) {
+ error(e.serrno(), e.errstr());
+ stop = true;
+ }
}
} // namespace Server
@PACKAGE_LIBS@ \
-lsocket++ \
../src/libplaquiserver.a \
- ../../Model/src/model.a
+ ../../Model/src/libplaquimodel.a
client_test_LDADD = \
@PACKAGE_LIBS@ \
ControlClient* client = NULL;
+void on_error(const Runnable::Error& code, const string& desc) {
+ cerr << "--------------------------------------------------------" << endl;
+ cerr << "Error en el cliente:" << endl;
+ cerr << "Código: " << code << endl;
+ cerr << "Descripción: " << desc << endl;
+ cerr << "--------------------------------------------------------" << endl;
+}
+
void on_finished(void) {
client = NULL;
}
try {
// Corre el cliente.
client = new ControlClient(host, port);
+ client->signal_error().connect(SigC::slot(on_error));
client->signal_finished().connect(SigC::slot(on_finished));
client->signal_connected().connect(SigC::slot(on_connected));
client->signal_ok_received().connect(SigC::slot(on_ok_received));
using namespace std;
using namespace PlaQui::Server;
+void on_error(const Runnable::Error& code, const string& desc) {
+ cerr << "--------------------------------------------------------" << endl;
+ cerr << "Error en el servidor:" << endl;
+ cerr << "Código: " << code << endl;
+ cerr << "Descripción: " << desc << endl;
+ cerr << "--------------------------------------------------------" << endl;
+}
+
int main(int argc, char* argv[]) {
// Termina con mas informacion si hay una excepcion no manejada.
// Inicializa threads.
Glib::thread_init();
+ Server* server = NULL;
try {
- // Corre el server.
- Server server(filename, port);
- server.run(false);
+ // Crea el server (empieza a escuchar).
+ server = new Server(filename, port);
} catch (const sockerr& e) {
cerr << "Socket Error: " << e.operation() << " | serrno = "
<< e.serrno() << " | errstr = " << e.errstr() << endl;
} else if (e.benign()) {
cerr << "Es: recoverable read/write error like EINTR etc." << endl;
}
+ return e.serrno();
} catch (const exception& e) {
cerr << "Error: " << e.what() << endl;
+ return 1;
} catch (const char* e) {
cerr << "Error: " << e << endl;
+ return 2;
} catch (...) {
cerr << "Error desconocido!" << endl;
+ return 3;
}
+ // Conecto señal para atender errores.
+ server->signal_error().connect(SigC::slot(on_error));
+
+ // Corre el server.
+ server->run(false);
+
+ // Como no detachee el server, lo tengo que eliminar a mano.
+ delete server;
+
return 0;
}