/* This file is part of SLS. Copyright (C) 2008 Sebastien LUTTRINGER SLS 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; version 2 of the License. SLS 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 SLS; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sls.hh" #include "server.hh" #include "error.hh" #include "connection.hh" #include "client.hh" #include #include #include #include #include #include #include #include #include static const int BACKLOG = 10; /*! * Constructor */ Server::Server() : max_conn_ (0), verbose_(false) { pthread_mutex_init(&threads_mutex_, 0); } /*! * Destructor */ Server::~Server() { pthread_mutex_destroy(&threads_mutex_); } /*! * Start server. */ void Server::start(int port, size_t max_conn, bool verbose) { if (max_conn <= 0) throw Error(ERR_SRV, "Too less max connection allowed"); if (conn_.connected()) throw Error(ERR_SRV, "Server already started"); // Set options max_conn_ = max_conn; verbose_ = verbose; // listen on connection conn_.listen(port, BACKLOG); // treat new connections while (1) { // accept incoming connection Connection *nc = conn_.accept(); // check max conn if (threads_.size() >= max_conn_) { std::cout << "Connection refused from ip " << nc->getremoteip() << " on port " << nc->getremoteport() << ": Max connections reached.\n"; nc->disconnect(); continue; } // Print connection std::cout << "New connection from ip " << nc->getremoteip() << " on port " << nc->getremoteport(); if (verbose_) std::cout << " (socket " << nc->getsocket() << ")" ; std::cout << ".\n"; // Create new thread pthread_t t; pthread_attr_t t_attr; if (pthread_attr_init(&t_attr) != 0) { nc->disconnect(); delete nc; throw Error(ERR_THREAD, (string) "Unable to init thread attr: " + strerror(errno)); } // Set thread detachable. This mean it free ressource when its // execution is terminated. It's very important ! if (pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED) != 0) { pthread_attr_destroy(&t_attr); nc->disconnect(); delete nc; throw Error(ERR_THREAD, (string) "Unable to set thread attr: " + strerror(errno)); } if (pthread_create(&t, &t_attr, start_client, nc) != 0) { pthread_attr_destroy(&t_attr); nc->disconnect(); delete nc; throw Error(ERR_THREAD, (string) "Unable to create thread: " + strerror(errno)); } pthread_attr_destroy(&t_attr); } } /*! * Stop server. */ void Server::stop() { pthread_mutex_lock(&threads_mutex_); // close all open thread for (Threadset::iterator it = threads_.begin(); it != threads_.end(); ++it) pthread_cancel((*it)); // empty liste threads_.clear(); pthread_mutex_unlock(&threads_mutex_); // close connexion conn_.disconnect(); // reset max_conn_ max_conn_ = 0; } /** * @return if server is started */ bool Server::started() { return conn_.connected(); } /** * Entry point for new thread that represent client machine * * @param vfd pointer to the server socket * * @return error code */ void *Server::start_client(void *voidconn) { extern Server S; assert(S.started()); const pthread_t t = pthread_self(); Connection *conn = (Connection *) voidconn; assert(conn); // add into thread set pthread_mutex_lock(&S.threads_mutex_); S.threads_.insert(t); pthread_mutex_unlock(&S.threads_mutex_); try { Client *client = Client::login(*conn); if (client != 0) { client->exec(); delete client; } } catch (const Error &e) { std::cerr << "On connection " << conn->getremoteip() << " port " << conn->getremoteport() << ": " << e << ".\n"; } // stop connexion conn->disconnect(); // Print closing connection std::cout << "Disconnected from ip " << conn->getremoteip() << " on port " << conn->getremoteport() << ".\n"; // remove from thread set pthread_mutex_lock(&S.threads_mutex_); S.threads_.erase(t); pthread_mutex_unlock(&S.threads_mutex_); return 0; }