]> git.llucax.com Git - z.facultad/75.42/plaqui.git/commitdiff
- Se mejora el manejo de errores (excepciones) en los tests (y en algunas otras
authorLeandro Lucarella <llucax@gmail.com>
Sun, 16 Nov 2003 03:49:23 +0000 (03:49 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Sun, 16 Nov 2003 03:49:23 +0000 (03:49 +0000)
  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. :)

17 files changed:
Server/TODO
Server/include/plaqui/server/connection.h
Server/include/plaqui/server/httpmessage.h
Server/include/plaqui/server/plant.h [new file with mode: 0644]
Server/include/plaqui/server/server.h
Server/include/plaqui/server/string.h
Server/include/plaqui/server/tcpserver.h
Server/src/Makefile
Server/src/connection.cpp
Server/src/controlclient.cpp
Server/src/server.cpp
Server/src/string.cpp
Server/src/tcpserver.cpp
Server/tests/Makefile
Server/tests/client_test.cpp
Server/tests/server_test.cpp
docs/cliente_servidor.dia

index 20674f436ba638ffbd9edb18b6fe1fcd2df5aa78..5bc5734ff2c5bbedfbab708a6eb927f0598aeaaf 100644 (file)
@@ -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.
index 0d7660a1eb236394722c809baee09e6361903bf7..504875a317c471e4c346145b365efd5ae5f2098c 100644 (file)
@@ -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;
 
        };
 
index 2f6f9578ad6b2accf143e78aae4454a87ef6b2cd..5897d148c07096e009874c4a7bd327b68deec159 100644 (file)
@@ -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 (file)
index 0000000..92f6afd
--- /dev/null
@@ -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 <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#ifndef PLAQUI_PLANT_H
+#define PLAQUI_PLANT_H
+
+#include "plaqui/server/runnable.h"
+#include <sigc++/signal.h>
+
+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<void> 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
index 8c92ca806942011126082d0607507ecdf67c6cb3..1179fdc2b9ae3524519238a088d5b63f646ca3f7 100644 (file)
@@ -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 <socket++/sockinet.h>
 #include <string>
@@ -53,8 +54,8 @@ namespace Server {
                        /// Lista de conexiones de control.
                        typedef std::list<Transmitter*> TransmitterList;
 
-                       // TODO:
-                       // typedef std::list<Plant*> PlantList;
+                       /// Lista de plantas químicas.
+                       typedef std::list<Plant*> 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);
 
        };
 
index ecd253a8bc53e251aadcb34ab35fbee9112dbe4c..41e83acd70ef5b3bd7f5095e41ae259587901a52 100644 (file)
@@ -29,6 +29,7 @@
 #define PLAQUI_STRING_H
 
 #include <string>
+#include <sstream>
 #include <vector>
 
 namespace PlaQui {
@@ -104,6 +105,29 @@ namespace Server {
                        static String join(const std::vector<std::string>& 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;
+                       }
+
        };
 
 }
index 1cd344f4da3599eea86ddade2da09cfc7df9783c..17ce3b12ca79c71d9dc95578e2c4c905e3b13cab 100644 (file)
@@ -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.
                         */
index c998e98ae9c69d0518d7521e7ab2d3b58a637029..d8e95f3878fbd4d5f4945116d4673870e5b159f3 100644 (file)
@@ -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
index 1dc6b6d3d9a45d01385021035114312d84aa0194..1b328c643e0d71d51228edf11cef177e95685a25 100644 (file)
@@ -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;
 }
 
index b26385c7fd357393a0ff804ef767e6b46e8b2e75..f33fff5f3197989621377d30f6cc3d8d20006494 100644 (file)
@@ -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 {
index 37f5c1c75b7d26d7ca1e6d763d6a21a2ee02f36b..d4dd52a42a0c26707dab7567870c1e39afd8681f 100644 (file)
@@ -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 << "<html>" << endl;
-                       response_xml << "    <head>" << endl;
-                       response_xml << "        <title>PlaQui v0.6</title>" << endl;
-                       response_xml << "    </head>" << endl;
-                       response_xml << "    <body>" << endl;
-                       response_xml << "        <h1>PlaQui</h1>" << endl;
-                       response_xml << "        <p>versión 0.6</p>" << endl;
-                       response_xml << "        <h2>Comando</h2>" << endl;
-                       response_xml << "        <ul>" << endl;
-                       response_xml << "           <li><b>Target:</b> " << command.get_target() << endl;
-                       response_xml << "           <li><b>Command:</b> " << command.get_command() << endl;
-                       response_xml << "           <li><b>Argumentos:</b>" << endl;
-                       response_xml << "               <ol>" << endl;
-                       for (Command::Arguments::const_iterator i = command.get_args().begin();
-                                       i != command.get_args().end(); i++) {
-                               response_xml << "                   <li>" << *i << "</li>" << endl;
-                       }
-                       response_xml << "               </ol>" << endl;
-                       response_xml << "        </ul>" << endl;
-                       response_xml << "        <h2>Desarrollado por</h2>" << endl;
-                       response_xml << "        <ul>" << endl;
-                       response_xml << "            <li>Nicolás Dimov.</li>" << endl;
-                       response_xml << "            <li>Leandro Lucarella.</li>" << endl;
-                       response_xml << "            <li>Ricardo Markiewicz.</li>" << endl;
-                       response_xml << "        </ul>" << endl;
-                       response_xml << "        <address>" << endl;
-                       response_xml << "             Copyleft 2003 - bajo los " << endl;
-                       response_xml << "             términos de la licencia GPL" << endl;
-                       response_xml << "        </address>" << endl;
-                       response_xml << "    </body>" << endl;
-                       response_xml << "</html>" << 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 << "<html>" << endl;
-                       response_xml << "    <head>" << endl;
-                       response_xml << "        <title>PlaQui v0.6</title>" << endl;
-                       response_xml << "    </head>" << endl;
-                       response_xml << "    <body>" << endl;
-                       response_xml << "        <h1>PlaQui</h1>" << endl;
-                       response_xml << "        <p>versión 0.6</p>" << endl;
-                       response_xml << "        <h2>Lista de conexiones:</h2>" << endl;
-                       response_xml << "        <ul>" << endl;
-                       for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin();
-                                       i != cil.end(); i++) {
-                               response_xml << "       <li>" << i->host
-                                       << ":" << i->port << " [<a href=\"/connection/disconnect/"
-                                       << i->host << "/" << i->port << "\">deconectar</a>]</li>"
-                                       << endl;
-                       }
-                       response_xml << "        </ul>" << endl;
-                       response_xml << "        <address>" << endl;
-                       response_xml << "             Copyleft 2003 - bajo los " << endl;
-                       response_xml << "             términos de la licencia GPL" << endl;
-                       response_xml << "        </address>" << endl;
-                       response_xml << "    </body>" << endl;
-                       response_xml << "</html>" << 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 << "<html>" << endl;
+       response_xml << "    <head>" << endl;
+       response_xml << "        <title>PlaQui v0.7</title>" << endl;
+       response_xml << "    </head>" << endl;
+       response_xml << "    <body>" << endl;
+       response_xml << "        <h1>PlaQui</h1>" << endl;
+       response_xml << "        <p>versión 0.7</p>" << endl;
+/*     response_xml << "        <h2>Comando</h2>" << endl;
+       response_xml << "        <ul>" << endl;
+       response_xml << "           <li><b>Target:</b> " << command.get_target() << endl;
+       response_xml << "           <li><b>Command:</b> " << command.get_command() << endl;
+       response_xml << "           <li><b>Argumentos:</b>" << endl;
+       response_xml << "               <ol>" << endl;
+       for (Command::Arguments::const_iterator i = command.get_args().begin();
+                       i != command.get_args().end(); i++) {
+               response_xml << "                   <li>" << *i << "</li>" << endl;
+       }
+       response_xml << "               </ol>" << endl;
+       response_xml << "        </ul>" << endl;
+*/     response_xml << "        <h2>Desarrollado por</h2>" << endl;
+       response_xml << "        <ul>" << endl;
+       response_xml << "            <li>Nicolás Dimov.</li>" << endl;
+       response_xml << "            <li>Leandro Lucarella.</li>" << endl;
+       response_xml << "            <li>Ricardo Markiewicz.</li>" << endl;
+       response_xml << "        </ul>" << endl;
+       response_xml << "        <address>" << endl;
+       response_xml << "             Copyleft 2003 - bajo los " << endl;
+       response_xml << "             términos de la licencia GPL" << endl;
+       response_xml << "        </address>" << endl;
+       response_xml << "    </body>" << endl;
+       response_xml << "</html>" << 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 << "<html>" << endl;
+       response_xml << "    <head>" << endl;
+       response_xml << "        <title>PlaQui v0.7</title>" << endl;
+       response_xml << "    </head>" << endl;
+       response_xml << "    <body>" << endl;
+       response_xml << "        <h1>PlaQui</h1>" << endl;
+       response_xml << "        <p>versión 0.7</p>" << endl;
+       response_xml << "        <h2>Lista de conexiones:</h2>" << endl;
+       response_xml << "        <ul>" << endl;
+       for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin();
+                       i != cil.end(); i++) {
+               response_xml << "       <li>" << i->host
+                       << ":" << i->port << " [<a href=\"/connection/stop/"
+                       << i->host << "/" << i->port << "\">deconectar</a>]</li>"
+                       << endl;
+       }
+       response_xml << "        </ul>" << endl;
+       response_xml << "        <address>" << endl;
+       response_xml << "             Copyleft 2003 - bajo los " << endl;
+       response_xml << "             términos de la licencia GPL" << endl;
+       response_xml << "        </address>" << endl;
+       response_xml << "    </body>" << endl;
+       response_xml << "</html>" << 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
index 97dd19f5123eee3d9de4fd23ed59ef1ca38c983c..8f9b2dbe6b410677fced804480a3fa37ea7a9d8a 100644 (file)
@@ -93,6 +93,21 @@ String String::join(const vector<string>& 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
index 0f97fe5a762b5fbaebcfc0410ff62685cbad39cf..d15f34ddb31bcae01ff02c840975c04ad55da495 100644 (file)
@@ -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
index c5bfc639a1c37f99a09e0ea3b885b698eb5c26a0..24792909457bfd56e0b6d4858dca6c1060a4f78f 100644 (file)
@@ -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
index 3f9f52ce2d36327e8556b76328752bb681a51201..4605619ab83cf67dc7ef4addf0d660bc487f7bc8 100644 (file)
@@ -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<string> 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;
        }
index f9989b5573bca730c86355351feb8459bd11cbf4..033bb2e892271b0f99e03cdde784f6bf9e8f9a1e 100644 (file)
@@ -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;
        }
index 656218c6d86a29bbdc197656987fcb72dc7cfd98..cad9d442b557cc3c19d37c7ea440f9bbaf5cd5e8 100644 (file)
Binary files a/docs/cliente_servidor.dia and b/docs/cliente_servidor.dia differ