]> git.llucax.com Git - z.facultad/75.42/plaqui.git/blobdiff - Server/src/tcpserver.cpp
Se arregla el bug que hacia que el cliente levante mal archivos XML grandes.
[z.facultad/75.42/plaqui.git] / Server / src / tcpserver.cpp
index 0f97fe5a762b5fbaebcfc0410ff62685cbad39cf..04fd8bab9128ec1a4014990a7ba27217e926bef1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "plaqui/server/tcpserver.h"
 #include <sigc++/class_slot.h>
 
 #include "plaqui/server/tcpserver.h"
 #include <sigc++/class_slot.h>
+#include <glibmm/timer.h>
 #ifdef DEBUG
 #      include <iostream>
 #endif // DEBUG
 #ifdef DEBUG
 #      include <iostream>
 #endif // DEBUG
@@ -39,35 +40,77 @@ namespace Server {
 
 TCPServer::~TCPServer(void) {
 #ifdef DEBUG
 
 TCPServer::~TCPServer(void) {
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": destructor." << endl;
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": destructor." << endl;
 #endif // DEBUG
 #endif // DEBUG
+       // Mando a terminar todas las conexiones.
+       connections_mutex.lock();
+       for (ConnectionList::iterator con = connections.begin();
+                       con != connections.end(); con++) {
+               (*con)->finish();
+       }
+       ConnectionList::size_type count = connections.size();
+       connections_mutex.unlock();
+       // Espero que terminen realmente.
+       while (count) {
+               Glib::usleep(10000); // 10 milisegundos
+               connections_mutex.lock();
+               count = connections.size();
+               connections_mutex.unlock();
+       }
 }
 
 }
 
-TCPServer::TCPServer(int port):        socket(sockbuf::sock_stream) {
+TCPServer::TCPServer(const Connection::Port& port) throw(sockerr):
+               socket(sockbuf::sock_stream) {
 #ifdef DEBUG
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": port = " << port << endl;
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": port = " << port << endl;
 #endif // DEBUG
 #endif // DEBUG
+       socket.reuseaddr(true);
        socket.bind(port);
 #ifdef DEBUG
        socket.bind(port);
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": escuchando en " << socket.localhost()
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": escuchando en " << socket.localhost()
                << ":" << socket.localport() << "." << endl;
 #endif // DEBUG
        socket.listen(MAX_PENDING_CONNECTIONS);
 #ifdef DEBUG
                << ":" << socket.localport() << "." << endl;
 #endif // DEBUG
        socket.listen(MAX_PENDING_CONNECTIONS);
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": [despues de listen()] escuchando en "
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": [despues de listen()] escuchando en "
                << socket.localhost() << ":" << socket.localport() << "." << endl;
 #endif // DEBUG
 }
 
                << socket.localhost() << ":" << socket.localport() << "." << endl;
 #endif // DEBUG
 }
 
+void TCPServer::finish(void) {
+#ifdef DEBUG
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": finish(void);" << endl;
+#endif // DEBUG
+       Runnable::finish();
+       // Creo una conexión suicida para que el accept() del server retorne
+       // el control y el server pueda terminar realmente.
+       try {
+               sockinetbuf suicida(sockbuf::sock_stream);
+               suicida.connect(socket.localhost(), socket.localport());
+       } catch (const sockerr& e) {
+               // 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());
+       }
+}
+
 void TCPServer::on_connection_finished(Connection* connection) {
 #ifdef DEBUG
 void TCPServer::on_connection_finished(Connection* connection) {
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": on_connection_finished(connection = "
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": on_connection_finished(connection = "
                << connection << ")" << endl;
 #endif // DEBUG
        Glib::Mutex::Lock lock(connections_mutex);
        connections.remove(connection);
 #ifdef DEBUG
                << connection << ")" << endl;
 #endif // DEBUG
        Glib::Mutex::Lock lock(connections_mutex);
        connections.remove(connection);
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": lista de conexiones" << endl;
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": lista de conexiones" << endl;
        for (ConnectionList::const_iterator i = connections.begin();
                        i != connections.end(); i++) {
                cerr << "\t " << *i << endl;
        for (ConnectionList::const_iterator i = connections.begin();
                        i != connections.end(); i++) {
                cerr << "\t " << *i << endl;
@@ -75,54 +118,84 @@ void TCPServer::on_connection_finished(Connection* connection) {
 #endif // DEBUG
 }
 
 #endif // DEBUG
 }
 
-/// \todo TODO: ver tema de timeout o como salir de un accept().
-void TCPServer::real_run(void) {
+void TCPServer::real_run(void) throw() {
 #ifdef DEBUG
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": real_run()" << endl;
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": real_run()" << endl;
 #endif // DEBUG
        Connection* connection;
 #endif // DEBUG
        Connection* connection;
-       while (!stop) {
+       while (!stop()) {
                // Forma grasa de salir del accept: crear conexion que salga al toque.
                // Forma grasa de salir del accept: crear conexion que salga al toque.
-               connection = new_connection(socket.accept());
+               try {
+                       connection = new_connection(socket.accept());
+               } catch (const sockerr& e) { // No se si el accept() puede fallar.
+                       signal_error().emit(e.serrno(),
+                                       string("Error creando conexión nueva: ") + e.errstr());
+                       continue; // Supongo que puede seguir aceptando conexiones.
+               }
+               if (!stop()) {
+                       // Solo avisamos si la conexión que viene no es para matarnos.
+                       _connection_opened(connection->get_host(), connection->get_port());
+               }
 #ifdef DEBUG
 #ifdef DEBUG
-               cerr << __FILE__ <<  ": real_run(): connection = " << connection
+               cerr << __FILE__ << "(" << __LINE__ << ")"
+                       <<  ": real_run(): connection = " << connection
                        << endl;
 #endif // DEBUG
                Glib::Mutex::Lock lock(connections_mutex);
                        << endl;
 #endif // DEBUG
                Glib::Mutex::Lock lock(connections_mutex);
-               // XXX connections_mutex.lock();
                connections.push_back(connection);
 #ifdef DEBUG
                connections.push_back(connection);
 #ifdef DEBUG
-               cerr << __FILE__ <<  ": real_run(): lista de conexiones" << endl;
+               cerr << __FILE__ << "(" << __LINE__ << ")"
+                       <<  ": real_run(): lista de conexiones" << endl;
                for (ConnectionList::const_iterator i = connections.begin();
                                i != connections.end(); i++) {
                        cerr << "\t " << *i << endl;
                }
 #endif // DEBUG
                for (ConnectionList::const_iterator i = connections.begin();
                                i != connections.end(); i++) {
                        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.
                // Conecto la señal para cuando termina una conexión, borrarla.
-               connection->signal_finished().connect(
-                               SigC::bind<Connection*>(
-                                       SigC::slot_class(*this,
-                                               &TCPServer::on_connection_finished),
-                                       connection));
+               connection->signal_finished().connect(SigC::bind(
+                               SigC::slot_class(*this, &TCPServer::on_connection_finished),
+                               connection));
                connection->run();
        }
 }
 
                connection->run();
        }
 }
 
+bool TCPServer::disconnect(const std::string& host, const Connection::Port& port) {
+#ifdef DEBUG
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": 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;
+}
+
+/// \todo TODO Hay que reemplazarlo por una lista generica.
 TCPServer::ConnectionInfoList TCPServer::get_connected(void) {
 #ifdef DEBUG
 TCPServer::ConnectionInfoList TCPServer::get_connected(void) {
 #ifdef DEBUG
-       cerr << __FILE__ <<  ": get_connected()" << endl;
+       cerr << __FILE__ << "(" << __LINE__ << ")"
+               <<  ": get_connected()" << endl;
 #endif // DEBUG
 #endif // DEBUG
-       TCPServer::ConnectionInfoList con;
+       TCPServer::ConnectionInfoList cl;
        Glib::Mutex::Lock lock(connections_mutex);
        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 =
                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;
+}
+
+TCPServer::SignalConnectionOpened& TCPServer::signal_connection_opened(void) {
+       return _connection_opened;
 }
 
 } // namespace Server
 }
 
 } // namespace Server