]> git.llucax.com Git - z.facultad/75.42/plaqui.git/commitdiff
Retoques finales:
authorLeandro Lucarella <llucax@gmail.com>
Sun, 30 Nov 2003 20:06:34 +0000 (20:06 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Sun, 30 Nov 2003 20:06:34 +0000 (20:06 +0000)
- Se mejora la documentacion:
  * Se termina de agrupar las signals en el doxygen.
  * Se agrega descripcion del namespace PlaQui y PlaQui::Server.
  * Se completa el manual de usuario del servidor.
- Se agrega metodo add_plant() a Server en vez de levantar una planta
  hardcodeada. La planta por default ahora se agrega en el programa.
- Se agrega una signal_connection_opened al TCPServer para dar un poco mas de
  feedback desde el programa por la salida estandar.
- Se mejora el programa servidor, en especial la salida y la impresion de
  errores.
- Otras limpiezas del codigo.

18 files changed:
Server/include/plaqui/server/connection.h
Server/include/plaqui/server/controlclient.h
Server/include/plaqui/server/controlserver.h
Server/include/plaqui/server/documentacion.h
Server/include/plaqui/server/receiver.h
Server/include/plaqui/server/server.h
Server/include/plaqui/server/tcpserver.h
Server/src/Makefile.am
Server/src/connection.cpp
Server/src/controlclient.cpp
Server/src/controlserver.cpp
Server/src/httpresponse.cpp
Server/src/main.cpp
Server/src/plant.cpp
Server/src/response.cpp
Server/src/server.cpp
Server/src/tcpserver.cpp
docs/mainpage.h

index c700fcb7d6bbecb033cf1c1ccac9e36532dc16bd..c35337be24329066828f03aa2ede21887acc2e07 100644 (file)
@@ -109,12 +109,12 @@ namespace Server {
                        /**
                         * Obtiene el nombre del host local de la conexión.
                         */
-                       const std::string get_host(void) const;
+                       const std::string& get_host(void) const;
 
                        /**
                         * Obtiene el puerto local de la conexión.
                         */
-                       const Port get_port(void) const;
+                       const Port& get_port(void) const;
 
        };
 
index 3d0448b7bccaf5e668cc94c99758e21cd40c7c1d..2cc26ad3c91fa902e2ea27fbf34237985586df95 100644 (file)
@@ -40,11 +40,6 @@ namespace Server {
        /// Conexión para enviar comandos de control a una planta.
        class ControlClient: public Connection {
 
-               /////////////////////////////////////////////////////////////////////
-               // Tipos.
-
-               public:
-
                /////////////////////////////////////////////////////////////////////
                /// \name Señales
                //@{
index a6d24f08608267ee8808c9ba17544d53c241f0d1..a04bee7dc70a39637b4cfa4a788d05363d2a3779 100644 (file)
@@ -42,13 +42,19 @@ namespace Server {
        class ControlServer: public Connection {
 
                /////////////////////////////////////////////////////////////////////
-               // Tipos.
+               /// \name Señales
+               //@{
 
                public:
 
                        /// Tipo de señal para indicar que se recibió un comando.
                        typedef SigC::Signal1<void, const Command&> SignalCommandReceived;
 
+                       /// Obtiene la señal que avisa cuando se recibió un comando.
+                       SignalCommandReceived& signal_command_received(void);
+
+               //@}
+
                /////////////////////////////////////////////////////////////////////
                // Atributos.
 
@@ -86,11 +92,6 @@ namespace Server {
                         */
                        void send(const Response& response);
 
-                       /**
-                        * Obtiene la señal que avisa cuando se recibió un comando.
-                        */
-                       SignalCommandReceived& signal_command_received(void);
-
        };
 
 }
index 36eddb0055f13b9821a9b40e53f9f3ba1d47c07c..06a78ba289568fcab92bea901ae2e9b0b672e365 100644 (file)
@@ -3,7 +3,7 @@
 \section page_server_general Descripción General
        El servidor está dividido en 2 módulos que provean 2 servicios diferentes.
 
-       \subsection page_server_general_control Módulo de Control.
+       \subsection page_server_general_control Módulo de Control
                El módulo de control se basa en el protocolo TCP y se encarga de listar
                los archivos de planta disponibles en el servidor, permitiendo cambiar
                las propiedades de cada uno y conocer su estado en términos generales
@@ -23,7 +23,7 @@
                Este módulo está implementado por las clases PlaQui::Server::ControlServer
                y PlaQui::Server::ControlClient.
 
-       \subsection page_server_general_transmision Módulo de Transmisión.
+       \subsection page_server_general_transmision Módulo de Transmisión
                Este módulo se encarga de transmitir la simulación en tiempo real por UDP
                (como si fuera un video). Comienza luego de que el módulo de control recibe
                una petición de transmisión y continúa transmitiendo (en un principio)
@@ -43,7 +43,7 @@
                PlaQui::Server::Receiver.
 
 
-\section page_server_protocolo Comandos del Módulo de Control.
+\section page_server_protocolo Comandos del Módulo de Control
        Todos los comandos son rutas de archivos. En un principio no se van a utilizar
        los <em>query string</em> de los datos pasados por GET ni datos adicionales
        recibidos por POST. Es decir, de un <em>request</em> HTTP solo se usara la ruta
@@ -72,7 +72,7 @@
        - <tt>transmission</tt>: Comandos para las transmisiones.
        - <tt>plant</tt>: Comandos para las plantas.
                          
-       \subsection page_server_protocolo_general Comandos para el Servidor.
+       \subsection page_server_protocolo_general Comandos para el Servidor
                Los comandos para el servidor, como se vio previamente, comienzan con
                <tt>/server/</tt> seguido de alguna de las siguientes opciones:
                <table>
@@ -90,7 +90,7 @@
                        </tr>
                </table>
 
-       \subsection page_server_protocolo_control Comandos para una Conexión de Control.
+       \subsection page_server_protocolo_control Comandos para una Conexión de Control
                Todos los comandos de transmisiones comienzan con <tt>/connection/</tt>
                y continúan con alguna de las siguientes opciones:
                <table>
                                <td>Nada.</td>
                        </tr>
                </table>
-               \note Los nombres entre <tt>[</tt> y <tt>]</tt> denotan un argumento.
+               \note Los nombres entre <tt>[</tt> y <tt>]</tt> representan un argumento.
 
-       \subsection page_server_protocolo_transmision Comandos para una Transmisión.
+       \subsection page_server_protocolo_transmision Comandos para una Transmisión
                Todos los comandos de transmisiones comienzan con <tt>/transmission/</tt>
                y continúan con alguna de las siguientes opciones:
                <table>
                                <td>Nada.</td>
                        </tr>
                </table>
-               \note Los nombres entre <tt>[</tt> y <tt>]</tt> denotan un argumento.
+               \note Los nombres entre <tt>[</tt> y <tt>]</tt> representan un argumento.
 
-       \subsection page_server_protocolo_planta Comandos para una Planta.
+       \subsection page_server_protocolo_planta Comandos para una Planta
                Todos los comandos de plantas comienzan con <tt>/plant/</tt> y continúan con
                alguna de las siguientes opciones:
                <table>
                                <td>Nada.</td>
                        </tr>
                </table>
-               \note Los nombres entre <tt>[</tt> y <tt>]</tt> denotan un argumento.
+               \note Los nombres entre <tt>[</tt> y <tt>]</tt> representan un argumento.
 
-\section page_server_uso Modo de uso.
-       Para utilizar el servidor es necesario disponer de un archivo XML de planta
-       (por ejemplo, generado por el Constructor).
+\section page_server_uso Modo de uso
+       \subsection page_server_uso_inicio Inicio del servidor
+               Para iniciar el servidor es necesario disponer de un archivo XML de
+               planta (por ejemplo, generado por el Constructor).
 
-       Invocación del servidor:
-       \verbatim ./plaqui-server [archivo] [puerto] \endverbatim
+               Invocación del servidor:
+               \verbatim ./plaqui-server [archivo] [puerto] \endverbatim
 
-       Ambos argumentos son opcionales. El primero, <tt>[archivo]</tt>, es la
-       ubicación del archivo con la descripción de la planta a simular (por omisión
-       <tt>planta.xml</tt>). El segundo, <tt>[puerto]</tt>, es el puerto en el cual
-       se van a atender las peticiones al servidor (por omisión 7522).
+               Ambos argumentos son opcionales. El primero, <tt>[archivo]</tt>, es la
+               ubicación del archivo con la descripción de la planta a simular (por omisión
+               <tt>planta.xml</tt>). El segundo, <tt>[puerto]</tt>, es el puerto en el cual
+               se van a atender las peticiones al servidor (por omisión 7522).
+
+       \subsection page_server_uso_estado Estado del servidor
+               Mientras el servidor se ejecuta, va imprimiendo en la salida estándar su
+               estado. Se imprime cada vez que llega una conexión entrante y cada vez que
+               se detecta un error.
+
+               Otro tipo de información del estado del servidor puede ser obtenida desde
+               el cliente a través del comando <tt>/server/info</tt> (ver
+               \ref page_server_protocolo_general).
+
+               \note Los errores se imprimen en la salida de error, no en la salida
+                     estándar.
+
+       \subsection page_server_uso_fin Finalización del servidor
+               Hay varias formas de finalizar el servidor:
+               - Enviando una señal de interrupción (<tt>SIGINT</tt>), por ejemplo,
+                 presionando la combinación de teclas <tt>CTRL-C</tt>.
+               - Enviando una señal de salida (<tt>SIGQUIT</tt>) o de terminación
+                 (<tt>SIGTERM</tt>), por ejemplo, a través del comando
+                 <tt>kill(1)</tt>.
+               - Enviando un comando <tt>/server/stop</tt> desde un cliente (ver
+                 \ref page_server_protocolo_general).
+
+               Cualquiera de estos métodos es válido y finaliza el servidor de forma
+               correcta.
 
 */
+
+/** \namespace PlaQui::Server
+
+Infrastructura cliente-servidor para PlaQui.
+
+Bajo este espacio de nombres (namespace) se encuentran todas las clases para la
+comunicación cliente-servidor de PlaQui. Esto no incluye la interfaz gráfica del
+cliente.
+
+*/
+
index ddf4fd3810021335d7b88d6d036f0ef5eeafa845..c41847707a938536801630923ab6fd4039853cce 100644 (file)
@@ -52,14 +52,20 @@ namespace Server {
                        static const std::string FRAME_END;
 
                /////////////////////////////////////////////////////////////////////
-               // Tipos.
+               /// \name Señales
+               //@{
 
                public:
 
                        /// Tipo de señal para indicar que se recibió un cuadro.
                        typedef SigC::Signal1<void, const std::string&> SignalFrameReceived;
 
+                       /// Obtiene la señal que avisa cuando se recibió un cuadro.
+                       SignalFrameReceived& signal_frame_received(void);
+
+               //@}
 
+               /////////////////////////////////////////////////////////////////////
                // Atributos.
 
                private:
@@ -93,11 +99,6 @@ namespace Server {
                        Receiver(const Connection::Port& port = 7528,
                                        const std::string& host = "localhost") throw(sockerr);
 
-                       /**
-                        * Obtiene la señal que avisa cuando se recibió un cuadro.
-                        */
-                       SignalFrameReceived& signal_frame_received(void);
-
        };
 
 }
index 20458bbcd6e7693a56df4d37fb1e6264bf3a7ae5..cae6f7cc7eb2de37bf2cc567dfa93d78f4d15e0a 100644 (file)
@@ -156,11 +156,21 @@ namespace Server {
                        /**
                         * Constructor.
                         *
-                        * \param plant_filename Nombre del archivo con la planta a cargar.
-                        * \param port           Puerto en el cual escuchar.
+                        * \param port Puerto en el cual escuchar.
                         */
-                       Server(const std::string& plant_filename,
-                                       const Connection::Port& port = 7522) throw(sockerr);
+                       Server(const Connection::Port& port = 7522) throw(sockerr);
+
+                       /**
+                        * Agrega una planta al servidor.
+                        *
+                        * \param name     Nombre que utilizará el servidor para identificar
+                        *                 a la planta.
+                        * \param filename Nombre del archivo con la planta a cargar.
+                        * \return true si se agregó la planta, false si ya existía una
+                        *         planta con ese nombre.
+                        */
+                       bool add_plant(const std::string& name,
+                                       const std::string& filename);
 
                        /**
                         * Maneja los comandos recibidos por las conexiones.
index 66fe3be524a141f88e4f60f3d7b8222039b28c7c..5277f2bf188d2b9fb4c867495c518bfcf7c743ab 100644 (file)
@@ -31,6 +31,7 @@
 #include "plaqui/server/runnable.h"
 #include "plaqui/server/connection.h"
 #include <socket++/sockinet.h>
+#include <sigc++/signal.h>
 #include <list>
 #include <vector>
 
@@ -73,14 +74,33 @@ namespace Server {
                        /// Lista de información de conexiones de control.
                        typedef std::vector<ConnectionInfo> ConnectionInfoList;
 
+               /////////////////////////////////////////////////////////////////////
+               /// \name Señales
+               //@{
+
+               public:
+
+                       /// Tipo de señal para indicar que se inició una conexión.
+                       typedef SigC::Signal2<void, const std::string&,
+                                       const Connection::Port&> SignalConnectionOpened;
+
+                       /// Obtiene la señal que avisa que se inició una conexión.
+                       SignalConnectionOpened& signal_connection_opened(void);
+
+               //@}
+
                /////////////////////////////////////////////////////////////////////
                // Atributos.
 
-               protected: //FIXME
+               protected:
 
                        /// Socket para escuchar conexiones.
                        sockinetbuf socket;
-               private: // FIXME
+
+               private:
+
+                       /// Señal que indica que se inició una conexión.
+                       SignalConnectionOpened _connection_opened;
 
                        /// Conexiones de control.
                        ConnectionList connections;
index 7238456ae68b8991ffbf45ee7449a0f97c03ba45..5e1cc84f259826100acc7ca0bb7662bdd9ce31de 100644 (file)
@@ -28,7 +28,7 @@
 INCLUDES = \
        -I../include \
        -I../../Model/include \
-       -DDEBUG \
+##     -DDEBUG \
        -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
        -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
        @PACKAGE_CFLAGS@
index 31aaf1a4b0c3b5214e2485128732077f513c349b..cf0e293cdb4a92cd79a310b31e6be230db23e029 100644 (file)
@@ -88,11 +88,11 @@ void Connection::finish(void) {
        }
 }
 
-const string Connection::get_host(void) const {
+const string& Connection::get_host(void) const {
        return host;
 }
 
-const Connection::Port Connection::get_port(void) const {
+const Connection::Port& Connection::get_port(void) const {
        return port;
 }
 
index 1f965854125c73dfaac79fca2afaa04f4fc23fd5..e4293ae9b835274596c04e947e49510723cd76b0 100644 (file)
@@ -44,7 +44,7 @@ ControlClient::~ControlClient(void) {
        cerr << __FILE__ << "(" << __LINE__ << ")"
                << ": destructor." << endl;
 #endif // DEBUG
-       // TODO Temporal: espero que el receiver muera.
+       // FIXME Temporal: espero que el receiver muera.
        if (receiver) {
                receiver->finish();
        }
@@ -64,6 +64,7 @@ ControlClient::ControlClient(const string& _host,
                << ": host = " << host
                << " | port = " << port << endl;
 #endif // DEBUG
+       // FIXME temporal
        receiver = new Receiver(7528, host);
        receiver->signal_finished().connect(SigC::slot_class(*this,
                                &ControlClient::on_receiver_finished));
@@ -86,7 +87,7 @@ void ControlClient::real_run(void) throw() {
                        socket >> response;
                // Si se cerró el socket.
                } catch (const ios::failure& e) {
-                       // TODO poner buenos codigos de error.
+                       // FIXME poner buenos codigos de error.
                        signal_error().emit(1000000, "Se desconectó.");
                        return;
                } catch (const sockerr& e) {
@@ -101,8 +102,7 @@ void ControlClient::real_run(void) throw() {
                        cerr << __FILE__ << "(" << __LINE__ << ")"
                                << " : real_run() ERROR nro: " << e << endl;
 #endif // DEBUG
-                       // TODO - es un error recuperable? O manda señal error()?
-                       error_received(e, "La respuesta recibida es inválida");
+                       signal_error().emit(e, "La respuesta recibida es inválida");
                        continue;
                }
                switch (response.get_code()) {
index 1c253c5e012496521a03072c831a7a8936a80be6..966e362aa96ced609d070f65a36f2a463d993786 100644 (file)
@@ -29,8 +29,6 @@
 #include "plaqui/server/command.h"
 #include "plaqui/server/httperror.h"
 #include "plaqui/server/httpresponse.h"
-//#include <cstring>
-//#include <sstream>
 #ifdef DEBUG
 #      include "plaqui/server/string.h"
 #      include <iostream>
@@ -62,23 +60,17 @@ void ControlServer::real_run(void) throw() {
        cerr << __FILE__ << "(" << __LINE__ << ")"
                << ": real_run()" << endl;
 #endif // DEBUG
-       //char buf[BUFSIZ];
        while (!stop()) {
                Command command;
                try {
-                       //Glib::Mutex::Lock lock(socket_mutex);
                        socket >> command;
                } catch (const ios::failure& e) {
                        // TODO poner buenos codigos de error.
-                       signal_error().emit(1000000, "Se desconectó.");
+                       signal_error().emit(200000, "Se desconectó.");
                        return;
                } catch (const sockerr& e) {
                        signal_error().emit(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) {
@@ -88,48 +80,9 @@ void ControlServer::real_run(void) throw() {
                                << e.code << " | reason = " << HTTPMessage::reason(e.code)
                                << " | desc = " << e.what() << endl;
 #endif // DEBUG
-                       //Glib::Mutex::Lock lock(socket_mutex);
                        socket << HTTPResponse(e) << flush;
                        continue;
                }
-               // TODO agregar las verificaciones de abajo a HTTPRequest y padres.
-               // Actualizacion: Estoy usando trim() en casi todos lados, no debería
-               // ser necesario.
-/*
-               // Primera línea no vacía (que debe ser el request).
-               bool is_first = true;
-               while (!stop && socket.getline(buf, BUFSIZ)) {
-#ifdef DEBUG
-                       cerr << __FILE__ << "(" << __LINE__ << ")"
-                       << "  Recibiendo inea: " << buf << endl;
-#endif // DEBUG
-                       int len = strlen(buf);
-                       // Si tiene un retorno de carro, lo elimina.
-                       if (len && (buf[len-1] == '\r')) {
-                               buf[--len] = '\0';
-                       }
-                       // Si tiene contenido, lo agrego a la información del request.
-                       if (len) {
-                               // Si es la primera línea, es el request.
-                               if (is_first) {
-                                       request.set_request(buf, socket->peerhost(),
-                                                       socket->peerport());
-                                       is_first = false;
-                               } else {
-                                       // TODO request.parse_header(buf);
-                               }
-                       // Si viene la línea vacía
-                       } else {
-                               // Si no es la primera, terminan las cabeceras HTTP.
-                               if (!is_first) {
-                                       // Podría ir un break.
-                                       stop = true;
-                                       continue;
-                               }
-                               // Si es la primera, no pasa nada, sigue esperando un request.
-                       }
-               }
-*/
 #ifdef DEBUG
                cerr << __FILE__ << "(" << __LINE__ << ")"
                        << " : real_run() Despachando comando: target = "
@@ -143,7 +96,6 @@ void ControlServer::real_run(void) throw() {
 }
 
 void ControlServer::send(const Response& response) {
-       //Glib::Mutex::Lock lock(socket_mutex);
        socket << response << flush;
 #ifdef DEBUG
        cerr << __FILE__ << "(" << __LINE__ << ")"
index 0177ae35cf44c9b5aef2f0c0f687569af5b4d85e..2ae86a9b043890df97e37c45088ff4da9d7d6660 100644 (file)
@@ -122,9 +122,7 @@ istream& operator>>(istream& is, HTTPResponse& resp)
        if (line.length() != 3) {
                throw HTTPResponse::INVALID_HTTP_RESPONSE_CODE;
        }
-       stringstream ss;
-       ss << line; // TODO ver forma mas linda de convertir
-       ss >> resp.status_code;
+       to(line, resp.status_code);
        is >> static_cast<HTTPMessage&>(resp);
        return is;
 }
index 89409213e63ae028c90d025b79bd33f402a53e62..a18a0a0ddb3d41244cc585c27a790f325f3e120c 100644 (file)
@@ -40,28 +40,37 @@ using namespace PlaQui::Server;
 Server* server = NULL;
 
 void on_error(const Runnable::Error& code, const string& desc) {
-       cerr << "--------------------------------------------------------" << endl;
-       cerr << "Error en el servidor:" << endl;
+       cerr << "ERROR EN EL SERVIDOR" << endl;
        cerr << "Código: " << code << endl;
        cerr << "Descripción: " << desc << endl;
-       cerr << "--------------------------------------------------------" << endl;
 }
 
 void on_finished(void) {
-       cerr << "Murió el servidor!" << endl;
+       cout << "Servidor finalizado!" << endl;
        server = NULL;
 }
 
+void on_connection_opened(const string& host, const Connection::Port& port) {
+       cout << "Se abrió una nueva conexión a " << host << ":" << port << "."
+               << endl;
+}
+
 void on_signal(int signal) {
+       static bool called = false;
+       if (!called) {
+               cout << "Se recibe señal " << signal << "." << endl;
+       }
        switch (signal) {
                case SIGINT:
                case SIGTERM:
                case SIGQUIT:
-                       if (server) {
+                       if (!called && server) {
+                               cout << "Terminando servidor... " << flush;
                                server->finish();
                        }
                        break;
        }
+       called = true;
 }
 
 int main(int argc, char* argv[]) {
@@ -69,9 +78,14 @@ int main(int argc, char* argv[]) {
        // Termina con mas informacion si hay una excepcion no manejada.
        set_terminate(__gnu_cxx::__verbose_terminate_handler);
 
+       // Calculo número de revisión.
+       string rev = "$Rev$";
+       rev = rev.substr(6, rev.length() - 8);
+
        // Bienvenida.
-       cout << "PlaQui Server. Modo de uso: " << endl;
-       cout << "\t" << argv[0] << " [planta] [puerto]" << endl;
+       cout << "PlaQui Server version " << VERSION << " (revisión " << rev
+               << ")." << endl;
+       cout << "Modo de uso: " << argv[0] << " [planta] [puerto]" << endl;
 
        // Acepta argumentos.
        string filename = "planta.xml";
@@ -96,28 +110,17 @@ int main(int argc, char* argv[]) {
 
        try {
                // Crea el server (empieza a escuchar).
-               server = new Server(filename, port);
+               server = new Server(port);
        } catch (const sockerr& e) {
                cerr << "Socket Error: " << e.operation() << " | serrno = "
                        << e.serrno() << " | errstr = " << e.errstr() << endl;
                if (e.serrno() == 98) {
                        cerr << "No se puede usar el puerto " << port << " porque ya está "
                                "siendo utilizado por otro programa." << 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;
+               } else {
+                       cerr << "Error al crear el socket: operación: " << e.operation()
+                               << ", código: " << e.serrno() << ", descripción: "
+                               << e.errstr() << endl;
                }
                return e.serrno();
        } catch (const exception& e) {
@@ -137,19 +140,24 @@ int main(int argc, char* argv[]) {
        // Conecto señal para atender la finalización del server.
        server->signal_finished().connect(SigC::slot(on_finished));
 
+       // Conecto señal para saber cuando se abre una nueva conexión.
+       server->signal_connection_opened().connect(SigC::slot(on_connection_opened));
+
+       // Agrego planta.
+       if (!server->add_plant("default", filename)) {
+               cerr << "Advertencia: Ya existe una planta llamada 'default'. "
+                       "No se puede agregar la planta almacenada en '" << filename
+                       << "'." << endl;
+       }
+
        // Corre el server.
        server->run();
+       cout << "Atendiendo conexiones en el puerto " << port << "." << endl;
 
        // Espera a que el server se muera.
        while (server) {
-               //cerr << "-----------------\n\nAHHHHHHH\n\n----------------" << endl;
-               Glib::usleep(100000); // 0,1 segundos
+               Glib::usleep(500000); // 0,5 segundos
        }
-       // Espera un segundo más por las dudas, para asegurarse de que terminó.
-       Glib::usleep(1000000); // 1 segundo
-
-       // Como no detachee el server, lo tengo que eliminar a mano.
-       //delete server;
 
        return 0;
 }
index 1187c517533840a389d7db58ef29802ef7ceed4c..f3a0a98c2962c846955440429b982463a76b90c7 100644 (file)
@@ -67,18 +67,6 @@ Plant::Plant(const string& filename): simulator(filename), filename(filename),
        cerr << __FILE__ << "(" << __LINE__ << ")"
                << ": constructor. filename = " << filename << endl;
 #endif // DEBUG
-       // TODO plant
-/*     simulator.add_pump("bomba1");
-       simulator.add_conduct("c");
-       simulator.add_conduct("c1");
-       simulator.add_drainage("d");
-       simulator.add_tank("tanque");
-       
-       simulator.connect("bomba1", "c", Model::IConector::OUT);
-       simulator.connect("c", "tanque", Model::IConector::OUT);
-       simulator.connect("tanque", "c1", Model::IConector::OUT);
-       simulator.connect("c1", "d", Model::IConector::OUT);
-*/     
 }
 
 void Plant::real_run(void) throw() {
@@ -130,22 +118,13 @@ bool Plant::transmission_start(string& host, Connection::Port& port) {
        Transmitter* trans;
        try {
                trans = new Transmitter(host, port);
-       } catch (const sockerr& e) { // TODO - Hace mas selectivo el catch?
+       } catch (const sockerr& e) {
 #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->signal_finished().connect(SigC::bind(
@@ -210,7 +189,7 @@ const string Plant::get_xml(void) const {
 #endif // DEBUG
        ostringstream oss;
        ifstream ifs(filename.c_str());
-       // XXX Saco la línea de definición de XML (<?xml ?>), ver si esta hecho muy
+       // FIXME Saco la línea de definición de XML (<?xml ?>), ver si esta hecho muy
        // feo.
        ifs.ignore(50, '\n'); // Ignora 50 caracteres o hasta un enter.
        ifs >> oss.rdbuf();
@@ -227,29 +206,6 @@ void Plant::set_paused(bool paused_) {
        paused = paused_;
 }
 
-/*
-bool Plant::transmission_exists(const string& host,
-               const Connection::Port& port) {
-       Glib::Mutex::Lock lock(transmissions_mutex);
-       for (TransmitterList::const_iterator i = transmissions.begin();
-                       i != transmissions.end(); i++) {
-               if (((*i)->get_host() == host) && ((*i)->get_oprt() == port)) {
-                       return true;
-               }
-       }
-       return false; // No la encontró.
-}
-*/
-
-//const std::string& Plant::get_filename(void) const {
-//     return filename;
-//}
-
-/// \todo FIXME esto deberia estar protegido por un mutex.
-//Plant::SignalUpdated& Plant::signal_updated(void) {
-//     return updated;
-//}
-
 } // namespace Server
 
 } // namespace PlaQui
index 9e4c87fe2096f264dfb72c5cd1eace0375dc9ea2..3a3f4bfb569e7accf25f44425b1d29ceb584834d 100644 (file)
@@ -166,7 +166,6 @@ istream& operator>>(istream& is, Response& resp)
        return is;
 }
 
-/// \todo TODO hacer el metodo build como en command.
 ostream& operator<<(ostream& os, const Response& resp) {
 #ifdef DEBUG
        cerr << __FILE__ << "(" << __LINE__ << ")" << ": operator<<()" << endl;
index 5e7197acd3adcae385a75e83735332b97f2d2d00..692db97a0228d378b6e8271b558dde909be82a81 100644 (file)
@@ -64,19 +64,25 @@ Server::~Server(void) {
        }
 }
 
-Server::Server(const string& plant_filename, const Connection::Port& port)
+Server::Server(const Connection::Port& port)
                throw(sockerr): TCPServer(port) {
 #ifdef DEBUG
        cerr << __FILE__ << "(" << __LINE__ << ")"
                <<  ": port = " << port << endl;
 #endif // DEBUG
-       // FIXME - hacer que se puedan cargar mas plantas bien.
+}
+
+bool Server::add_plant(const string& name, const string& filename) {
        Glib::Mutex::Lock lock(plants_mutex);
-       plants["default"] = new Plant(plant_filename);
-       plants["default"]->signal_finished().connect(SigC::bind(
-                       SigC::slot_class(*this, &Server::on_plant_finished),
-                       "default"));
-       plants["default"]->run();
+       if (plants.find(name) == plants.end()) { // No existe
+               plants[name] = new Plant(filename);
+               plants[name]->signal_finished().connect(SigC::bind(
+                               SigC::slot_class(*this, &Server::on_plant_finished),
+                               name.c_str()));
+               plants[name]->run();
+               return true;
+       }
+       return false;
 }
 
 Connection* Server::new_connection(const sockbuf::sockdesc& sd) {
@@ -86,11 +92,9 @@ Connection* Server::new_connection(const sockbuf::sockdesc& sd) {
                << endl;
 #endif // DEBUG
        ControlServer* connection = new ControlServer(sd);
-       // TODO verificar si el new se hace bien? no creo.
        connection->signal_command_received().connect(SigC::bind(
                        SigC::slot_class(*this, &Server::on_control_command_received),
                        connection));
-       // TODO: 
        return connection;
 }
 
@@ -103,7 +107,6 @@ void Server::on_plant_finished(const char* plant) {
        plants.erase(plant);
 }
 
-/// \todo Terminar de implementar.
 void Server::on_control_command_received(const Command& command,
                ControlServer* controlserver) {
 #ifdef DEBUG
@@ -121,7 +124,8 @@ void Server::on_control_command_received(const Command& command,
                        response = new Response(Response::OK,
                                        "El server se cerrará en instantes");
                        // XXX - Sin mandar la respuesta enseguida podría ser que el server
-                       // cierre la conexión antes de mandar la respuesta.
+                       // cierre la conexión antes de mandar la respuesta. En las pruebas
+                       // esto nunca pasó.
                        //response->headers["Content-Type"] = "text/xml; charset=iso-8859-1";
                        //controlserver->send(*response);
                        //delete response;
@@ -178,19 +182,11 @@ void Server::on_control_command_received(const Command& command,
                response = new Response(Response::INVALID_TARGET, command.get_target()
                                + " es un destino inválido");
        }
-       // FIXME
-       //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.
-       //if (stop_controlserver) {
-       //      controlserver->finish();
-       //}
 }
 
 Response* Server::cmd_server_info(void) const {
-       // FIXME
        stringstream xml;
        xml << "<serverstatus>" << endl;
        xml << "\t<version>" VERSION "</version>" << endl;
@@ -204,7 +200,7 @@ Response* Server::cmd_server_info(void) const {
 }
 
 Response* Server::cmd_connection_list(void) {
-       // FIXME
+       // TODO implementar con lista genérica.
        TCPServer::ConnectionInfoList cil = get_connected();
        stringstream xml;
        xml << "<list type=\"connection\">" << endl;
@@ -235,10 +231,10 @@ Response* Server::cmd_connection_stop(const Command& command) {
 }
 
 Response* Server::cmd_transmission_list(void) {
-       // FIXME
+       // TODO implementar con lista genérica.
        stringstream xml;
        xml << "<list type=\"transmission\">" << endl;
-/*TODO plants_mutex.lock();
+/*FIXME        plants_mutex.lock();
        for (PlantList::const_iterator i = plants.begin();
                        i != plants.end(); i++) {
                trans
@@ -331,7 +327,6 @@ Response* Server::cmd_plant_get(const Command& command) {
                return new Response(Response::PLANT_NOT_FOUND,
                                string("No existe la planta '") + plant + "'");
        }
-       // TODO try/catch?
        string xml = plants[plant]->get_xml();
        if (xml.length()) {
                return new Response(xml);
@@ -391,7 +386,7 @@ Response* Server::cmd_plant_set_frequency(const Command& command) {
        }
        unsigned hz;
        to(command.get_args()[1], hz);
-       /* TODO poner cantidad real que tomó: hz = */plants[name]->set_frequency(hz);
+       plants[name]->set_frequency(hz);
        String shz;
        shz.from(hz);
        return new Response(Response::OK,
index 61d3e11753e7413ea10cca0a948f25e1a518a220..3e4d1c8eb98beb025a879482891dfcd2ce08fd58 100644 (file)
@@ -66,11 +66,6 @@ TCPServer::TCPServer(const Connection::Port& port) throw(sockerr):
        cerr << __FILE__ << "(" << __LINE__ << ")"
                <<  ": 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.reuseaddr(true);
        socket.bind(port);
 #ifdef DEBUG
@@ -98,7 +93,7 @@ void TCPServer::finish(void) {
                sockinetbuf suicida(sockbuf::sock_stream);
                suicida.connect(socket.localhost(), socket.localport());
        } catch (const sockerr& e) {
-               // FIXME
+               // FIXME mejorar codigos de error.
                signal_error().emit(100000 + e.serrno(), string("No se pudo crear "
                                        "conexión 'suicida' para terminar el servidor: ")
                                        + e.errstr());
@@ -134,16 +129,17 @@ void TCPServer::real_run(void) throw() {
                try {
                        connection = new_connection(socket.accept());
                } catch (const sockerr& e) { // No se si el accept() puede fallar.
-                       signal_error().emit(e.serrno(), e.errstr());
+                       signal_error().emit(e.serrno(),
+                                       string("Error creando conexión nueva: ") + e.errstr());
                        continue; // Supongo que puede seguir aceptando conexiones.
                }
+               _connection_opened(connection->get_host(), connection->get_port());
 #ifdef DEBUG
                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__ << "(" << __LINE__ << ")"
@@ -153,8 +149,6 @@ void TCPServer::real_run(void) throw() {
                        cerr << "\t " << *i << endl;
                }
 #endif // DEBUG
-               // XXX connections_mutex.unlock(); // Si pongo el mutex antes del run(),
-               //                                    muere.
                // Conecto la señal para cuando termina una conexión, borrarla.
                connection->signal_finished().connect(SigC::bind(
                                SigC::slot_class(*this, &TCPServer::on_connection_finished),
@@ -197,6 +191,10 @@ TCPServer::ConnectionInfoList TCPServer::get_connected(void) {
        return cl;
 }
 
+TCPServer::SignalConnectionOpened& TCPServer::signal_connection_opened(void) {
+       return _connection_opened;
+}
+
 } // namespace Server
 
 } // namespace PlaQui
index 9f7eddf6186f248a362f3ab346fa6f7e41173128..a369335d5c4c746acdf37ce9cec2c567195d6a02 100644 (file)
@@ -38,7 +38,7 @@
                - socket++ ( >= 1.12.10): Wrapper de socket portables en C++ streams
                  [http://members.aon.at/hstraub/linux/socket++/]
 
-       \subsection requerimientos Requerimientos de Hardware y SO.
+       \subsection requerimientos Requerimientos de Hardware y SO
                PlaQui fue desarrollado bajo Debian GNU/Linux sid (http://www.debian.org/),
                pero debería andar en cualquier GNU/Linux e incluso probablemente en otros
                Unixes (e incluso podría llegar a andar en WIN32). La versión para el
                        - Procesador: PII 400 Mhz
                        - Memoria RAM: 64 MB
 
-       \subsection instalacion Instalación.
-       El programa se divide en 4 módulos:
-       - Modelo: es el módulo que se encarga de la simulación y el modelo \c
-         físico de la planta (es una biblioteca).
-       - \ref page_server "Servidor": es la infrastructura de red. Comprende tanto
-         el servidor como el cliente en cuando al manejo de la red (es una
-         biblioteca y un  programa).
-       - Cliente: es el cliente gráfico que permite ver la simulación (es un
-         programa).
-       - Constructor: es el programa para diseñar la planta química que será
-         simulada por el modelo en el servidor (es un programa).
-
-       La instalación puede realizarse de dos formas: instalando módulo por
-       módulo o instalando todos los módulos a la vez.
+       \subsection instalacion Instalación
+               El programa se divide en 4 módulos:
+               - Modelo: es el módulo que se encarga de la simulación y el modelo \c
+                 físico de la planta (es una biblioteca).
+               - \ref page_server "Servidor": es la infrastructura de red. Comprende tanto
+                 el servidor como el cliente en cuando al manejo de la red (es una
+                 biblioteca y un  programa).
+               - Cliente: es el cliente gráfico que permite ver la simulación (es un
+                 programa).
+               - Constructor: es el programa para diseñar la planta química que será
+                 simulada por el modelo en el servidor (es un programa).
+
+               La instalación puede realizarse de dos formas: instalando módulo por
+               módulo o instalando todos los módulos a la vez.
 
                \subsubsection instalacion_global Instalación Global
-               Para instalar todos los programas es sencillo.
-               -# Descomprimir el paquete:
-                  \verbatim tar -xvzf plaqui-proyect.tar.gz \endverbatim
-               -# Entrar al directorio del proyecto:
-                  \verbatim cd plaqui \endverbatim
-               -# Inicializar el proyecto:
-                  \verbatim aclocal && autoconf && automake -a \endverbatim
-               -# Configurar la compilación del proyecto (generalmente basta con):
-                  \verbatim ./configure \endverbatim
-                  Esto lo instala por defecto en /usr/local, se puede
-                  especificar otra ruta con la opcion \c --prefix
-               -# Compilar el proyecto:
-                  \verbatim make \endverbatim
-               -# Instalar el proyecto:
-                  \verbatim make install \endverbatim
+                       Para instalar todos los programas es sencillo.
+                       -# Descomprimir el paquete:
+                          \verbatim tar -xvzf plaqui-proyect.tar.gz \endverbatim
+                       -# Entrar al directorio del proyecto:
+                          \verbatim cd plaqui \endverbatim
+                       -# Inicializar el proyecto:
+                          \verbatim aclocal && autoconf && automake -a \endverbatim
+                       -# Configurar la compilación del proyecto (generalmente basta con):
+                          \verbatim ./configure \endverbatim
+                          Esto lo instala por defecto en <tt>/usr/local</tt>, se puede
+                          especificar otra ruta con la opcion <tt>--prefix</tt>.
+                       -# Compilar el proyecto:
+                          \verbatim make \endverbatim
+                       -# Instalar el proyecto:
+                          \verbatim make install \endverbatim
+
+                       \note Para realizar el último paso, dependiendo de si usó la
+                             opción <tt>--prefix</tt> o no, es posible que necesite
+                             permisos de superusuario (<tt>root</tt>).
 
                \subsubsection instalacion_global Instalación Por Partes
-               El procedimiento es muy similar al anterior:
-               -# Descomprimir el paquete:
-                  \verbatim tar -xvzf plaqui-proyect.tar.gz \endverbatim
-               -# Entrar al directorio del módulo [Módulo]:
-                  \verbatim cd plaqui/[Módulo] \endverbatim
-               -# Inicializar el módulo:
-                  \verbatim aclocal && autoconf && automake -a \endverbatim
-               -# Configurar la compilación del módulo (generalmente basta con):
-                  \verbatim ./configure \endverbatim
-               -# Compilar el módulo:
-                  \verbatim make \endverbatim
-               -# Instalar el módulo:
-                  \verbatim make install \endverbatim
+                       El procedimiento es muy similar al anterior:
+                       -# Descomprimir el paquete:
+                          \verbatim tar -xvzf plaqui-proyect.tar.gz \endverbatim
+                       -# Entrar al directorio del módulo [Módulo]:
+                          \verbatim cd plaqui/[Módulo] \endverbatim
+                       -# Inicializar el módulo:
+                          \verbatim aclocal && autoconf && automake -a \endverbatim
+                       -# Configurar la compilación del módulo (generalmente basta con):
+                          \verbatim ./configure \endverbatim
+                       -# Compilar el módulo:
+                          \verbatim make \endverbatim
+                       -# Instalar el módulo:
+                          \verbatim make install \endverbatim
+
+                       \note Para realizar el último paso, dependiendo de si usó la
+                             opción <tt>--prefix</tt> o no, es posible que necesite
+                             permisos de superusuario (<tt>root</tt>).
 
 \section mainpage_servidor Servidor
        Puede ver la documentación del servidor en \ref page_server
 
 */
+
+/** \namespace PlaQui
+
+Diseñador, simulador y controlador de plantas químicas distribuido.
+
+El Programa se divide en 4 módulos. Los módulo que se comportan como
+biblioteca compartida tienen a su vez un espacio de nombres (namespace)
+anidado: PlaQui::Model y PlaQui::Server.
+
+*/
+