From a0481d50f6da9cac5efd3502c3657b3fc461ec0d Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sun, 16 Nov 2003 03:49:23 +0000 Subject: [PATCH] - Se mejora el manejo de errores (excepciones) en los tests (y en algunas otras clases, pero falta). Ahora se manda bien la ControlClient::signal_connected() cuando se conecta (bien) y ControlClient::signal_finished() cuando no se puede conectar (o cuando se desconecta). La signal_connected() para mi pierde sentido con la existencia de la signal_finished() pero se deja por las dudas. - Se arregla un bug en la prueba del cliente (daba segfault si se desconectaba). - Se agrega host y port a Connection, cambiandose los metodos get_peerhost() y get_peerport() por get_host() y get_port(). - Se agrega un esqueleto muy (pero muy) primitivo de la planta y la lista de plantas al servidor. - Se mejora el "switch" de comandos del Server. - Se implementa el comando connection/stop. - Se agregan metodos de conversion a distintos tipo (con templates) al String. - Se crea un tipo Connection::Port para ser consistente a la hora de usar numeros de puertos (antes usaba a veces int y a veces unsigned, en realidad faltan "migrar" cosas todavia). - TODO actualizada. :) --- Server/TODO | 6 +- Server/include/plaqui/server/connection.h | 28 ++- Server/include/plaqui/server/httpmessage.h | 1 + Server/include/plaqui/server/plant.h | 92 ++++++++++ Server/include/plaqui/server/server.h | 34 +++- Server/include/plaqui/server/string.h | 24 +++ Server/include/plaqui/server/tcpserver.h | 27 ++- Server/src/Makefile | 2 +- Server/src/connection.cpp | 26 +-- Server/src/controlclient.cpp | 15 +- Server/src/server.cpp | 195 ++++++++++++--------- Server/src/string.cpp | 15 ++ Server/src/tcpserver.cpp | 42 ++++- Server/tests/Makefile | 2 +- Server/tests/client_test.cpp | 27 ++- Server/tests/server_test.cpp | 28 ++- docs/cliente_servidor.dia | Bin 2648 -> 2769 bytes 17 files changed, 422 insertions(+), 142 deletions(-) create mode 100644 Server/include/plaqui/server/plant.h diff --git a/Server/TODO b/Server/TODO index 20674f4..5bc5734 100644 --- a/Server/TODO +++ b/Server/TODO @@ -1,6 +1,6 @@ $Id$ -- Agregar timeouts (recvtimeout y sendtimeout). +- Agregar timeouts (recvtimeout() y sendtimeout()). - Darle bola al header Connection para saber si cerramos la conexión al finalizar el request o no. -- Ver por que el ControlClient tira una señal de error despues de una respuesta - buena. +- Hacer un try/catch en cada llamada al socket por si se desconecto, para que no + muera con un segmentation fault. diff --git a/Server/include/plaqui/server/connection.h b/Server/include/plaqui/server/connection.h index 0d7660a..504875a 100644 --- a/Server/include/plaqui/server/connection.h +++ b/Server/include/plaqui/server/connection.h @@ -38,12 +38,12 @@ namespace Server { /// Conexión. class Connection: public Runnable { - // Constantes. + // Tipos. - protected: + public: - /// Tamaño del buffer usado para enviar y recibir datos. - //static const int BUFFER_SIZE = 4096; + /// Puerto. + typedef unsigned Port; // Atributos. @@ -52,6 +52,12 @@ namespace Server { /// Socket a usar en la conexión. iosockinet socket; + /// Host. + std::string host; + + /// Puerto. + Port port; + /// Mutex para el socket. //Glib::Mutex socket_mutex; @@ -76,7 +82,15 @@ namespace Server { * * \param type Tipo de socket a usar. */ - Connection(sockbuf::type type); + Connection(const sockbuf::type& type); + + /** + * Constructor. + * + * \param host Host a donde conectarse. + * \param port Puerto a donde conectarse. + */ + Connection(const std::string& host, const Port& port); /** * Finaliza la conexión. @@ -92,12 +106,12 @@ namespace Server { /** * Obtiene el nombre del host local de la conexión. */ - std::string get_peerhost(void); + const std::string& get_host(void) const; /** * Obtiene el puerto local de la conexión. */ - unsigned get_peerport(void); + const Port& get_port(void) const; }; diff --git a/Server/include/plaqui/server/httpmessage.h b/Server/include/plaqui/server/httpmessage.h index 2f6f957..5897d14 100644 --- a/Server/include/plaqui/server/httpmessage.h +++ b/Server/include/plaqui/server/httpmessage.h @@ -46,6 +46,7 @@ namespace Server { static const unsigned OK = 200; static const unsigned BAD_REQUEST = 401; static const unsigned NOT_FOUND = 404; + static const unsigned CONFLICT = 409; static const unsigned LENGTH_REQUIRED = 411; static const unsigned INTERNAL_SERVER_ERROR = 500; static const unsigned NOT_IMPLEMENTED = 501; diff --git a/Server/include/plaqui/server/plant.h b/Server/include/plaqui/server/plant.h new file mode 100644 index 0000000..92f6afd --- /dev/null +++ b/Server/include/plaqui/server/plant.h @@ -0,0 +1,92 @@ +// vim: set noexpandtab tabstop=4 shiftwidth=4: +//---------------------------------------------------------------------------- +// PlaQui +//---------------------------------------------------------------------------- +// This file is part of PlaQui. +// +// PlaQui 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. +// +// PlaQui 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 PlaQui; if not, write to the Free Software Foundation, Inc., 59 Temple +// Place, Suite 330, Boston, MA 02111-1307 USA +//---------------------------------------------------------------------------- +// Creado: sáb nov 15 17:29:44 ART 2003 +// Autores: Leandro Lucarella +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#ifndef PLAQUI_PLANT_H +#define PLAQUI_PLANT_H + +#include "plaqui/server/runnable.h" +#include + +namespace PlaQui { + +namespace Server { + + /// Planta Química. + class Plant: public Runnable { + + + // Tipos. + + public: + + /// Tipo de señal para indicar que se actualizó la planta. + typedef SigC::Signal0 SignalUpdated; + + + // Atributos. + + private: + + /// Señal para indicar que se actualizó la planta. + SignalUpdated updated; + + + // Métodos. + + protected: + + /** + * Corre la planta (la monitorea o la simula). + */ + virtual void real_run(void); + + public: + + /** + * Destructor. + */ + virtual ~Plant(void); + + /** + * Constructor desde un archivo. + * + * \param filename Nombre del archivo de donde obtener la planta. + */ + Plant(const std::string& filename); + + /** + * Obtiene la señal para indicar que se actualizó la planta. + */ + SignalUpdated& signal_updated(void); + + }; + +} + +} + +#endif // PLAQUI_PLANT_H diff --git a/Server/include/plaqui/server/server.h b/Server/include/plaqui/server/server.h index 8c92ca8..1179fdc 100644 --- a/Server/include/plaqui/server/server.h +++ b/Server/include/plaqui/server/server.h @@ -31,6 +31,7 @@ #include "plaqui/server/tcpserver.h" #include "plaqui/server/controlserver.h" #include "plaqui/server/transmitter.h" +#include "plaqui/server/plant.h" #include "plaqui/server/command.h" #include #include @@ -53,8 +54,8 @@ namespace Server { /// Lista de conexiones de control. typedef std::list TransmitterList; - // TODO: - // typedef std::list PlantList; + /// Lista de plantas químicas. + typedef std::list PlantList; // Atributos. @@ -63,8 +64,14 @@ namespace Server { /// Transmisiones del estado de las plantas. TransmitterList transmissions; - // TODO: - // PlantList plants; + /// Mutex para las transmisiones. + Glib::Mutex transmissions_mutex; + + // Plantas disponibles en el servidor. + PlantList plants; + + /// Mutex para las plantas. + Glib::Mutex plants_mutex; // Métodos. @@ -79,6 +86,21 @@ namespace Server { */ virtual Connection* new_connection(const sockbuf::sockdesc& sd); + /** + * Maneja el comando server/status. + */ + HTTPResponse* cmd_server_status(void) const; + + /** + * Maneja el comando connection/list. + */ + HTTPResponse* cmd_connection_list(void); + + /** + * Maneja el comando connection/stop. + */ + HTTPResponse* cmd_connection_stop(const Command& command); + public: /** @@ -122,11 +144,9 @@ namespace Server { /** * Maneja los comandos recibidos por las conexiones. - * - * \todo Hacer un tipo Command abstracto o algo así. */ void on_control_command_received(const Command& command, - ControlServer* server); + ControlServer* controlserver); }; diff --git a/Server/include/plaqui/server/string.h b/Server/include/plaqui/server/string.h index ecd253a..41e83ac 100644 --- a/Server/include/plaqui/server/string.h +++ b/Server/include/plaqui/server/string.h @@ -29,6 +29,7 @@ #define PLAQUI_STRING_H #include +#include #include namespace PlaQui { @@ -104,6 +105,29 @@ namespace Server { static String join(const std::vector& v, const std::string& sep); + /** + * Convierte un string a otro tipo. + * + * \param p Parametro del tipo al que se quiere convertir. + */ + template < class T > T& to(T& p) const { + std::stringstream ss(*this); + ss >> p; + return p; + } + + /** + * Convierte un tipo a string. + * + * \param p Parametro del tipo que se quiere convertir a string. + */ + template < class T > String& from(const T& p) { + std::stringstream ss; + ss << p; + ss >> (*this); + return *this; + } + }; } diff --git a/Server/include/plaqui/server/tcpserver.h b/Server/include/plaqui/server/tcpserver.h index 1cd344f..17ce3b1 100644 --- a/Server/include/plaqui/server/tcpserver.h +++ b/Server/include/plaqui/server/tcpserver.h @@ -65,7 +65,7 @@ namespace Server { /// Host. std::string host; /// Port. - unsigned port; + Connection::Port port; }; /// Lista de información de conexiones de control. @@ -78,12 +78,12 @@ namespace Server { /// Socket para escuchar conexiones. sockinetbuf socket; - /// Mutex para las conexiones. - Glib::Mutex connections_mutex; - /// Conexiones de control. ConnectionList connections; + /// Mutex para las conexiones. + Glib::Mutex connections_mutex; + // Métodos. private: @@ -116,7 +116,18 @@ namespace Server { * * \param port Puerto en el cual escuchar. */ - TCPServer(int port); + TCPServer(const Connection::Port& port); + + /** + * Finaliza la tarea. + * + * \param attach Si es true, la función no retorna hasta que no + * finalice la tearea (no recomendable). + * + * \note Para saber cuando la tarea fue finalizada puede utilizar + * la señal signal_finished(). + */ + virtual void finish(bool attach = false); /** * Se encarga de borrar una conexión de la lista cuando finaliza. @@ -125,6 +136,12 @@ namespace Server { */ void on_connection_finished(Connection* connection); + /** + * Detiene una conexión. + */ + bool disconnect(const std::string& host, + const Connection::Port& port); + /** * Obtiene una lista conexiones de control abiertas. */ diff --git a/Server/src/Makefile b/Server/src/Makefile index c998e98..d8e95f3 100644 --- a/Server/src/Makefile +++ b/Server/src/Makefile @@ -34,7 +34,7 @@ CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_BASE_DIR) \ `pkg-config --cflags glibmm-2.0 gthread-2.0` CXXFLAGS+=-g -DDEBUG #CXXFLAGS+=-g -#CXXFLAGS+=-O3 +#CXXFLAGS+=-O2 #LDFLAGS=-lsocket++ `pkg-config --libs glibmm-2.0 gthread-2.0` TARGETS=server.a diff --git a/Server/src/connection.cpp b/Server/src/connection.cpp index 1dc6b6d..1b328c6 100644 --- a/Server/src/connection.cpp +++ b/Server/src/connection.cpp @@ -46,17 +46,29 @@ Connection::~Connection(void) { Connection::Connection(const sockbuf::sockdesc& sd): socket(sd) { #ifdef DEBUG - cerr << __FILE__ << ": sd = " << sd.sock << endl; + cerr << __FILE__ << ": sd = " << sd.sock; +#endif // DEBUG + host = socket->peerhost(); + port = socket->peerport(); +#ifdef DEBUG + cerr << " | host = " << host << " | port = " << port << endl; #endif // DEBUG } -Connection::Connection(sockbuf::type type): +Connection::Connection(const sockbuf::type& type): socket(type) { #ifdef DEBUG cerr << __FILE__ << ": type = " << type << 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; +#endif // DEBUG +} + void Connection::finish(bool attach) { //socket_mutex.lock(); socket->shutdown(sockbuf::shut_readwrite); @@ -64,17 +76,11 @@ void Connection::finish(bool attach) { Runnable::finish(attach); } -string Connection::get_peerhost(void) { - //socket_mutex.lock(); - string host = socket->peerhost(); - //socket_mutex.unlock(); +const string& Connection::get_host(void) const { return host; } -unsigned Connection::get_peerport(void) { - //socket_mutex.lock(); - unsigned port = socket->peerport(); - //socket_mutex.unlock(); +const Connection::Port& Connection::get_port(void) const { return port; } diff --git a/Server/src/controlclient.cpp b/Server/src/controlclient.cpp index b26385c..f33fff5 100644 --- a/Server/src/controlclient.cpp +++ b/Server/src/controlclient.cpp @@ -55,15 +55,16 @@ void ControlClient::real_run(void) { #ifdef DEBUG cerr << __FILE__ << ": real_run." << endl; #endif // DEBUG - socket->connect(host.c_str(), port); - // TODO - mejorar manejo de errores de conexion. - // volver a poner signal_disconnected()? reciclar signal_error_received() - // y/o llamarla signal_error()? - if (false) { + try { + socket->connect(host.c_str(), port); + } catch (const sockerr& e) { + // Poner una señal de error específica? + error_received(1); finish(); - } else { - connected(); + return; } + // TODO sacar a la mierda? + connected(); while (!stop) { HTTPResponse response; try { diff --git a/Server/src/server.cpp b/Server/src/server.cpp index 37f5c1c..d4dd52a 100644 --- a/Server/src/server.cpp +++ b/Server/src/server.cpp @@ -93,115 +93,138 @@ bool Server::stop_transmission(string host, int port) { /// \todo Implementar. void Server::on_control_command_received(const Command& command, - ControlServer* server) { + ControlServer* controlserver) { #ifdef DEBUG cerr << __FILE__ << ": on_control_command_received(target = " << command.get_target() << ", command = " << command.get_command() << ", args = [" << String::join(command.get_args(), ", ") << "])" << endl; #endif // DEBUG - HTTPResponse response(HTTPMessage::OK); + HTTPResponse* response; + //bool stop_controlserver = false; if (command.get_target() == "server") { -#ifdef DEBUG - cerr << __FILE__ << ": server" << endl; -#endif // DEBUG if (command.get_command() == "status") { - // FIXME - stringstream response_xml; - response_xml << "" << endl; - response_xml << " " << endl; - response_xml << " PlaQui v0.6" << endl; - response_xml << " " << endl; - response_xml << " " << endl; - response_xml << "

PlaQui

" << endl; - response_xml << "

versión 0.6

" << endl; - response_xml << "

Comando

" << endl; - response_xml << "
    " << endl; - response_xml << "
  • Target: " << command.get_target() << endl; - response_xml << "
  • Command: " << command.get_command() << endl; - response_xml << "
  • Argumentos:" << endl; - response_xml << "
      " << endl; - for (Command::Arguments::const_iterator i = command.get_args().begin(); - i != command.get_args().end(); i++) { - response_xml << "
    1. " << *i << "
    2. " << endl; - } - response_xml << "
    " << endl; - response_xml << "
" << endl; - response_xml << "

Desarrollado por

" << endl; - response_xml << "
    " << endl; - response_xml << "
  • Nicolás Dimov.
  • " << endl; - response_xml << "
  • Leandro Lucarella.
  • " << endl; - response_xml << "
  • Ricardo Markiewicz.
  • " << endl; - response_xml << "
" << endl; - response_xml << "
" << endl; - response_xml << " Copyleft 2003 - bajo los " << endl; - response_xml << " términos de la licencia GPL" << endl; - response_xml << "
" << endl; - response_xml << " " << endl; - response_xml << "" << endl; - response.status_code = HTTPMessage::OK; - response.set_body(response_xml.str()); + response = cmd_server_status(); } else if (command.get_command() == "stop") { - stop = true; - response.set_body("El server se apagará en instantes..."); + finish(); + response = new HTTPResponse(HTTPMessage::OK, + "El server se apagará en instantes..."); } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'server' taget!"); + response = new HTTPResponse(HTTPMessage::NOT_FOUND, + "Invalid command for 'server' taget!"); } } else if (command.get_target() == "connection") { if (command.get_command() == "list") { - // FIXME - TCPServer::ConnectionInfoList cil = get_connected(); - stringstream response_xml; - response_xml << "" << endl; - response_xml << " " << endl; - response_xml << " PlaQui v0.6" << endl; - response_xml << " " << endl; - response_xml << " " << endl; - response_xml << "

PlaQui

" << endl; - response_xml << "

versión 0.6

" << endl; - response_xml << "

Lista de conexiones:

" << endl; - response_xml << "
    " << endl; - for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin(); - i != cil.end(); i++) { - response_xml << "
  • " << i->host - << ":" << i->port << " [host << "/" << i->port << "\">deconectar]
  • " - << endl; - } - response_xml << "
" << endl; - response_xml << "
" << endl; - response_xml << " Copyleft 2003 - bajo los " << endl; - response_xml << " términos de la licencia GPL" << endl; - response_xml << "
" << endl; - response_xml << " " << endl; - response_xml << "" << endl; - response.status_code = HTTPMessage::OK; - response.set_body(response_xml.str()); + response = cmd_connection_list(); } else if (command.get_command() == "stop") { - // TODO server->finish(); - response.set_body("La conexión se cerrará en instantes..."); + response = cmd_connection_stop(command); } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'connection' taget!"); + response = new HTTPResponse(HTTPMessage::NOT_FOUND, + "Invalid command for 'connection' taget!"); } } else if (command.get_target() == "transmission") { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'transmission' taget!"); + response = new HTTPResponse(HTTPMessage::NOT_FOUND, + "Invalid command for 'transmission' taget!"); } else if (command.get_target() == "plant") { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'plant' taget!"); + response = new HTTPResponse(HTTPMessage::NOT_FOUND, + "Invalid command for 'plant' taget!"); } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid Target!"); + response = new HTTPResponse(HTTPMessage::NOT_FOUND, "Invalid taget!"); } // FIXME - response.headers["Content-Type"] = "text/html; charset=iso-8859-1"; - response.headers["Connection"] = "close"; - server->send(response); + response->headers["Content-Type"] = "text/html; charset=iso-8859-1"; + //response->headers["Connection"] = "close"; + controlserver->send(*response); + delete response; // FIXME con timeout no debería ser necesario. Verificar cabecera Connection // para saber si hay que finish()earlo o no. - // server->finish(); + //if (stop_controlserver) { + // controlserver->finish(); + //} +} + +HTTPResponse* Server::cmd_server_status(void) const { + // FIXME + stringstream response_xml; + response_xml << "" << endl; + response_xml << " " << endl; + response_xml << " PlaQui v0.7" << endl; + response_xml << " " << endl; + response_xml << " " << endl; + response_xml << "

PlaQui

" << endl; + response_xml << "

versión 0.7

" << endl; +/* response_xml << "

Comando

" << endl; + response_xml << "
    " << endl; + response_xml << "
  • Target: " << command.get_target() << endl; + response_xml << "
  • Command: " << command.get_command() << endl; + response_xml << "
  • Argumentos:" << endl; + response_xml << "
      " << endl; + for (Command::Arguments::const_iterator i = command.get_args().begin(); + i != command.get_args().end(); i++) { + response_xml << "
    1. " << *i << "
    2. " << endl; + } + response_xml << "
    " << endl; + response_xml << "
" << endl; +*/ response_xml << "

Desarrollado por

" << endl; + response_xml << "
    " << endl; + response_xml << "
  • Nicolás Dimov.
  • " << endl; + response_xml << "
  • Leandro Lucarella.
  • " << endl; + response_xml << "
  • Ricardo Markiewicz.
  • " << endl; + response_xml << "
" << endl; + response_xml << "
" << endl; + response_xml << " Copyleft 2003 - bajo los " << endl; + response_xml << " términos de la licencia GPL" << endl; + response_xml << "
" << endl; + response_xml << " " << endl; + response_xml << "" << endl; + return new HTTPResponse(HTTPMessage::OK, response_xml.str()); +} + +HTTPResponse* Server::cmd_connection_list(void) { + // FIXME + TCPServer::ConnectionInfoList cil = get_connected(); + stringstream response_xml; + response_xml << "" << endl; + response_xml << " " << endl; + response_xml << " PlaQui v0.7" << endl; + response_xml << " " << endl; + response_xml << " " << endl; + response_xml << "

PlaQui

" << endl; + response_xml << "

versión 0.7

" << endl; + response_xml << "

Lista de conexiones:

" << endl; + response_xml << "
    " << endl; + for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin(); + i != cil.end(); i++) { + response_xml << "
  • " << i->host + << ":" << i->port << " [host << "/" << i->port << "\">deconectar]
  • " + << endl; + } + response_xml << "
" << endl; + response_xml << "
" << endl; + response_xml << " Copyleft 2003 - bajo los " << endl; + response_xml << " términos de la licencia GPL" << endl; + response_xml << "
" << endl; + response_xml << " " << endl; + response_xml << "" << endl; + return new HTTPResponse(HTTPMessage::OK, response_xml.str()); +} + +HTTPResponse* Server::cmd_connection_stop(const Command& command) { + const Command::Arguments& args = command.get_args(); + Connection::Port port; + if (args.size() < 2) { + return new HTTPResponse(HTTPMessage::CONFLICT, + "Faltan argumentos."); + } else if (disconnect(args[0], String(args[1]).to(port))) { + return new HTTPResponse(HTTPMessage::OK, + string("La conexión a ") + args[0] + ":" + args[1] + + " se cerrará en instantes..."); + } else { + return new HTTPResponse(HTTPMessage::NOT_FOUND, + string("No existe una conexión a ") + args[0] + + ":" + args[1]); + } } } // namespace Server diff --git a/Server/src/string.cpp b/Server/src/string.cpp index 97dd19f..8f9b2db 100644 --- a/Server/src/string.cpp +++ b/Server/src/string.cpp @@ -93,6 +93,21 @@ String String::join(const vector& v, const string& sep) { return ss.str(); } +/* +template < class T > T& String::to(T& p) const { + stringstream ss(*this); + ss >> p; + return p; +} + +template < class T > String& String::from(const T& p) { + stringstream ss; + ss << p; + ss >> (*this); + return *this; +} +*/ + } // namespace Server } // namespace PlaQui diff --git a/Server/src/tcpserver.cpp b/Server/src/tcpserver.cpp index 0f97fe5..d15f34d 100644 --- a/Server/src/tcpserver.cpp +++ b/Server/src/tcpserver.cpp @@ -43,10 +43,15 @@ TCPServer::~TCPServer(void) { #endif // DEBUG } -TCPServer::TCPServer(int port): socket(sockbuf::sock_stream) { +TCPServer::TCPServer(const Connection::Port& port): socket(sockbuf::sock_stream) { #ifdef DEBUG cerr << __FILE__ << ": port = " << port << endl; #endif // DEBUG + // FIXME + //cerr << "recvtimeout = " << socket.recvtimeout(1) << endl; + //cerr << "sendtimeout = " << socket.sendtimeout(1) << endl; + //cerr << "recvtimeout = " << socket.recvtimeout(1) << endl; + //cerr << "sendtimeout = " << socket.sendtimeout(1) << endl; socket.bind(port); #ifdef DEBUG cerr << __FILE__ << ": escuchando en " << socket.localhost() @@ -59,6 +64,13 @@ TCPServer::TCPServer(int port): socket(sockbuf::sock_stream) { #endif // DEBUG } +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 = " @@ -110,19 +122,35 @@ void TCPServer::real_run(void) { } } +bool TCPServer::disconnect(const std::string& host, const Connection::Port& port) { +#ifdef DEBUG + cerr << __FILE__ << ": disconnect(host = " << host + << ", port = " << port << ")" << endl; +#endif // DEBUG + Glib::Mutex::Lock lock(connections_mutex); + for (ConnectionList::iterator con = connections.begin(); + con != connections.end(); con++) { + if (((*con)->get_host() == host) && ((*con)->get_port() == port)) { + (*con)->finish(); + return true; + } + } + return false; +} + TCPServer::ConnectionInfoList TCPServer::get_connected(void) { #ifdef DEBUG cerr << __FILE__ << ": get_connected()" << endl; #endif // DEBUG - TCPServer::ConnectionInfoList con; + TCPServer::ConnectionInfoList cl; Glib::Mutex::Lock lock(connections_mutex); - for (ConnectionList::const_iterator i = connections.begin(); - i != connections.end(); i++) { + for (ConnectionList::const_iterator con = connections.begin(); + con != connections.end(); con++) { TCPServer::ConnectionInfo ci = - { (*i)->get_peerhost(), (*i)->get_peerport() }; - con.push_back(ci); + { (*con)->get_host(), (*con)->get_port() }; + cl.push_back(ci); } - return con; + return cl; } } // namespace Server diff --git a/Server/tests/Makefile b/Server/tests/Makefile index c5bfc63..2479290 100644 --- a/Server/tests/Makefile +++ b/Server/tests/Makefile @@ -40,7 +40,7 @@ CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_DIR) \ `pkg-config --cflags glibmm-2.0 gthread-2.0` CXXFLAGS+=-g -DDEBUG #CXXFLAGS+=-g -#CXXFLAGS+=-O3 +#CXXFLAGS+=-O2 LDFLAGS=-lsocket++ `pkg-config --libs glibmm-2.0 gthread-2.0` #-L$(LIB_FILES) TARGETS=server_test client_test diff --git a/Server/tests/client_test.cpp b/Server/tests/client_test.cpp index 3f9f52c..4605619 100644 --- a/Server/tests/client_test.cpp +++ b/Server/tests/client_test.cpp @@ -90,7 +90,10 @@ int main(int argc, char* argv[]) { client->signal_error_received().connect(SigC::slot(on_error_received)); client->run(); char buf[BUFSIZ]; - while (client && cin.getline(buf, BUFSIZ)) { + while (cin.getline(buf, BUFSIZ)) { + if (!client) { + break; + } vector v = String(buf).split(' '); switch (v.size()) { case 0: @@ -110,10 +113,28 @@ int main(int argc, char* argv[]) { break; } } + } catch (const sockerr& e) { + cerr << "Socket Error: " << e.operation() << " | serrno = " + << e.serrno() << " | errstr = " << e.errstr() << endl; + if (e.io()) { + cerr << "Es: non-blocking and interrupt io recoverable error." + << endl; + } else if (e.arg()) { + cerr << "Es: incorrect argument supplied. recoverable error." + << endl; + } else if (e.op()) { + cerr << "Es: operational error. recovery difficult." << endl; + } else if (e.conn()) { + cerr << "Es: connection error." << endl; + } else if (e.addr()) { + cerr << "Es: address error." << endl; + } else if (e.benign()) { + cerr << "Es: recoverable read/write error like EINTR etc." << endl; + } + } catch (const exception& e) { + cerr << "Error: " << e.what() << endl; } catch (const char* e) { cerr << "Error: " << e << endl; - } catch (exception& e) { - cerr << "Error: " << e.what() << endl; } catch (...) { cerr << "Error desconocido!" << endl; } diff --git a/Server/tests/server_test.cpp b/Server/tests/server_test.cpp index f9989b5..033bb2e 100644 --- a/Server/tests/server_test.cpp +++ b/Server/tests/server_test.cpp @@ -57,13 +57,31 @@ int main(int argc, char* argv[]) { Glib::thread_init(); try { - // Corre el server. - Server server(port); - server.run(false); + // Corre el server. + Server server(port); + server.run(false); + } catch (const sockerr& e) { + cerr << "Socket Error: " << e.operation() << " | serrno = " + << e.serrno() << " | errstr = " << e.errstr() << endl; + if (e.io()) { + cerr << "Es: non-blocking and interrupt io recoverable error." + << endl; + } else if (e.arg()) { + cerr << "Es: incorrect argument supplied. recoverable error." + << endl; + } else if (e.op()) { + cerr << "Es: operational error. recovery difficult." << endl; + } else if (e.conn()) { + cerr << "Es: connection error." << endl; + } else if (e.addr()) { + cerr << "Es: address error." << endl; + } else if (e.benign()) { + cerr << "Es: recoverable read/write error like EINTR etc." << endl; + } + } catch (const exception& e) { + cerr << "Error: " << e.what() << endl; } catch (const char* e) { cerr << "Error: " << e << endl; - } catch (exception e) { - cerr << "Error: " << e.what() << endl; } catch (...) { cerr << "Error desconocido!" << endl; } diff --git a/docs/cliente_servidor.dia b/docs/cliente_servidor.dia index 656218c6d86a29bbdc197656987fcb72dc7cfd98..cad9d442b557cc3c19d37c7ea440f9bbaf5cd5e8 100644 GIT binary patch literal 2769 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 Xry~2T{*DBh+-5rzg>m=oiBr1*wdCb$! zJ&CWo@9y%SZvW;(|IxAKtmb4+(+!u|oM%kZ#B#nz+doeIEl8Q9B$JzWKM&rmPFZ|V z>-=Iy(g{lnRw*U%>M}42FvfMSVr+y19>8mh1|Ln zx{-q=V#UMO<*=;9q0#+au!v@d?(i;g|Hx@U?H>?*OFkx7ztqFUWJ%M4*{?i_c(+sB z4(TG&#oE>I@$WPgg}`6_`djD6&TUMxth@Eg(krv*y8Aclz?DcA(z4dqIp^EEJVb6! zO8Pk}~Mj=m=jq`0GWzH;D?%K~u_=GVJkez)NcEj3%NzBQloXCSj@9&NaEN z(_YNyDb2FchLE)n1Z$pL26iH(y|m}K_FC0q>RkDnW3`Y?I2I4N{YBsLl&%I~qkQO9 zG7PiwpV|YM&4}(GL%nfb!sR$59^LVcPOF!lJ2GSO^13_Y3D4#vq}@&?mdeXYzqvZ{ zmM>B!T~A+6-!)DZ1P#wM=kapJ)A^KzC%CduMHcn);JGp)b#rr7t?!`j37g)=!VGGj zrQt~w$3qdrLP66t36f|A5}Bp zHE>C4Q2!Pj622&hq?468>W{2f;g9;ys^za=!7YfmZz$qMRFH6LMi14+8H%>buR+AE zesp&%Vc8Vi(aUv5HU!*yN=_q_YM!x4LSj&Mh`mOXy_V+C**qqqy(nu&TS-fu1E(eT!U84Dz`jIbMgSH)OjFX1fKO zb2D1_&(F6X|NG^akN<-5@=222;E}*1y+)6eMdpTc5zRtyM=eKGmzSx zhD|MN1`}~x=hnVLm0wL4n)D7&&H&?0Q00uiqP( zsIcSuY)U-gDn$hoqoB|Zg?1>kL!liC?NDfck%jjDNsC+RDv0!wa@E>5-^FB$8V=Oxf#F# z&;+0fKofu_08Idz05n142Q+>FOfm|STwRzH7=lUu7ADya!UkbdU{;MydwwRa!;F(v^ZW z@BW}k^kh_2{>@ZIhxQ`R7O`OSn1$PsMw@{`n(~L%;fqWr5<_nTVVmi(aPKN@q0TU+ zg})xu@Yi_HUt7%`_MuE~pgo(w+;jrGGoJwa$mnzeWAh1IDc$)KzMoT)WHTlN{pfz$Ji70G9wR0bByO1aJx962K*ZO8}Qn+ahCIXYP@)E#%^Lmkb^t-@lA586^rn zLW5qJv-HXY#(HIrn}@Ay9)5xU&Ge61dF2(mSJF&8sdCtp9~rTXT{+80gOzUYTa2_; zX)#Br9#}<7t8nzK!abo?;7bY`w$#@P2^vZie1rx;<19gActZ1V&KWcY$Sz_=fc*1E zjDgzmvyukU;tbJZV9Xp2Rb*`K1)Z?p!;Yc;H7}p7?Btuy`qCJBj%8}oSxqr3YBJcW z-&Xv5Th79gPEd@2Vhj{xpcn(i7%0ZP?G0zewwc}N#-Te+^00I0tKWTg9upblP3q6b znEZXg-oO8-ID-bk-m|dx8q|zo^EKFf?FDVVrW#*I&$^8O?7#+_2%OzV6&h|v5kFCR z-x}@q41P-APsx#XDn{(7ByndS;eY?bnFke7N*+cB*XgP%<7>6#?HkTOf7L_(xmG>2{U+AtqJfcKBq#4r zl?LbLi)pEzZr_;26+)I$+{1Ghj!<8W?ZJA7u-+l8ci7Tb2l|t4yyqGhX|H;?TA0rFqsFzJpZEStWW;nDtjp><5odVGxg zoKqIG*Uymy2un}-s?5$t4p!XM98gy+LvEXz%=1XjQkt4fR58z|nrZ_~Z*3b^1DJlg z**w@ft7*s)IbIot$|t#(U>U2VR}~Gc;w)By^{pa*6O$!Pi`VjZl9JiYcmD_5SWv1z G=l}pO{xDbo -- 2.43.0