diff --git a/sls/trunk/Makefile.am b/sls/trunk/Makefile.am index 0b5ba4ad5bf4e73fc1ae9a31608dcf5c9c20f461..31cfe385ac90359e6aee4f99e3c2165670474b43 100644 --- a/sls/trunk/Makefile.am +++ b/sls/trunk/Makefile.am @@ -27,7 +27,14 @@ sls_SOURCES= src/sls.hh \ src/cron.hh \ src/cron.cc \ src/server.hh \ - src/server.cc + src/server.cc \ + src/connection.hh \ + src/connection.hxx \ + src/connection.cc \ + src/client.hh \ + src/client.cc \ + src/client_console.cc \ + src/client_daemon.cc CLEANFILES= *~ '\#*' diff --git a/sls/trunk/TODO b/sls/trunk/TODO new file mode 100644 index 0000000000000000000000000000000000000000..6e098cb649ea1ea39725a1afa2158dc214161d5e --- /dev/null +++ b/sls/trunk/TODO @@ -0,0 +1,4 @@ +Gerer les control-C sur les sockets. Le server ne ferme pas la connection... +Implementer un conn id pour qu'un serveur puisse numeroter les connecxions + + diff --git a/sls/trunk/src/client.cc b/sls/trunk/src/client.cc new file mode 100644 index 0000000000000000000000000000000000000000..ae6b77fedd5512d93f31e90f509386313739be48 --- /dev/null +++ b/sls/trunk/src/client.cc @@ -0,0 +1,68 @@ +/* + 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 "client.hh" + +/******************************************************************************* +** Method of Classes +*******************************************************************************/ +Client *Client::login(Connection &c) { + string slogin = c.recvln(); + string spass = c.recvln(); + + // FIXME: find better method than fucking magic number + char loginbuf[512]; + char passbuf[512]; + + + if (sscanf(spass.c_str(), "PASS %512s\n", passbuf) != 1) + return login_fail(c); + + if (sscanf(slogin.c_str(), "HOST %512s\n", loginbuf) == 1) { + std::cout << "Host " << loginbuf << " logged from " << c.getremoteip() + << " on port " << c.getremoteport() << ".\n"; + return new Daemon(c); + } + else if (sscanf(slogin.c_str(), "USER %512s\n", loginbuf) == 1) { + return new Console(c); + } + + return login_fail(c); +} + +Client *Client::login_fail(Connection &c) { + std::cout << "Bad authentification from " << c.getremoteip() << " on port " + << c.getremoteport() << ".\n"; + c.sendln("Bad authentification."); + return 0; +} + +/******************************************************************************* +** Public Classes +*******************************************************************************/ + +Client::Client(Connection &c) : c_ (c) {} + +Client::~Client() {} + + + +void Client::exec() { + assert(0); +} diff --git a/sls/trunk/src/client.hh b/sls/trunk/src/client.hh new file mode 100644 index 0000000000000000000000000000000000000000..9db042a612937b70809f291b32f9f2020fcbf847 --- /dev/null +++ b/sls/trunk/src/client.hh @@ -0,0 +1,62 @@ +/* + 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 +*/ + +#ifndef CLIENT_HH +# define CLIENT_HH + +# include "connection.hh" + +/*! +** Client Class + */ +class Client { +public: + Client(Connection &c); + virtual ~Client(); + + virtual void exec(); + + static Client *login(Connection &c); + +protected: + Connection c_; + +private: + static Client *login_fail(Connection &c); +}; + +/*! +** Client Daemon Class + */ +class Daemon: public Client { +public: + Daemon(Connection &c); + void exec(); +}; + +/*! +** Client Console Class + */ +class Console : public Client { +public: + Console(Connection &c); + void exec(); +}; + + +#endif diff --git a/sls/trunk/src/client_console.cc b/sls/trunk/src/client_console.cc new file mode 100644 index 0000000000000000000000000000000000000000..b7e2da8dbf1b0cd2e1b2b6dfe1abed707243d600 --- /dev/null +++ b/sls/trunk/src/client_console.cc @@ -0,0 +1,26 @@ +/* + 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 "client.hh" + +Console::Console(Connection &c) : Client(c) {} + +void Console::exec() { + c_.sendln("You are a console !!"); +} diff --git a/sls/trunk/src/client_daemon.cc b/sls/trunk/src/client_daemon.cc new file mode 100644 index 0000000000000000000000000000000000000000..4e32f3c862fa48cbf02ad0e45f11d267b1fd917a --- /dev/null +++ b/sls/trunk/src/client_daemon.cc @@ -0,0 +1,27 @@ +/* + 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 "client.hh" + +Daemon::Daemon(Connection &c) : Client(c) {} + +void Daemon::exec() { + c_.sendln("EXIT"); + while (1) { c_.sendln("toto"); } +} diff --git a/sls/trunk/src/connection.cc b/sls/trunk/src/connection.cc new file mode 100644 index 0000000000000000000000000000000000000000..547292283727c4d2c52b94b6857be69540a319f9 --- /dev/null +++ b/sls/trunk/src/connection.cc @@ -0,0 +1,438 @@ +/* + 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 "connection.hh" +#include "error.hh" + +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + ** Public method + ******************************************************************************/ + +/** + * Constructor + * + * @param fd socket of the connection (-1) is not exist + */ +Connection::Connection(int fd) : socket_fd_(fd), local_port_(-1), remote_port_(-1) { + pthread_mutex_init(&c_mutex_, 0); + pthread_mutex_init(&r_mutex_, 0); + pthread_mutex_init(&w_mutex_, 0); + + if (socket_fd_ >= 0) + setallinfo_(); +} + +/** + * Destructor + */ +Connection::~Connection() { + pthread_mutex_destroy(&c_mutex_); + pthread_mutex_destroy(&r_mutex_); + pthread_mutex_destroy(&w_mutex_); +} + +/** + * Create connection with @param addr on port @param port + */ +void Connection::connect(const char *addr, int port) { + if (socket_fd_ >= 0) + throw Error(ERR_NET, "Connection already established but trying to connect"); + + if (port <= 0) + throw Error(ERR_NET, "Trying to Connect on a bad port number"); + + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + // retrieve remote host info + struct hostent *h = gethostbyname(addr); + if (h == 0) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to resolve: " + addr + ": " + hstrerror(h_errno)); + } + + // create socket + try { socket_(); } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + // fill sockaddr + struct sockaddr_in daddr; + daddr.sin_family = AF_INET; + daddr.sin_port = htons(port); + daddr.sin_addr = *((struct in_addr *) h->h_addr); + memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero); + + // connect + if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) { + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to connect to " + addr + ": " + hstrerror(h_errno)); + } + + // set infos + setallinfo_(); + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Listen on @param port with queue size of max @param max + */ +void Connection::listen(int port, int max) { + if (socket_fd_ >= 0) + throw Error(ERR_NET, "Connection already established but trying to listen"); + + // lock + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + // create socket + try { socket_(); } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + // fill sockaddr + struct sockaddr_in saddr; + + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = INADDR_ANY; + memset(saddr.sin_zero, '\0', sizeof saddr.sin_zero); + + // bind on socket + if (bind(socket_fd_, (struct sockaddr *)&saddr, sizeof saddr) == -1) { + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to bind: " + strerror(errno)); + } + + // listen on socket + if (::listen(socket_fd_, max) == -1) { + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to listen: " + strerror(errno)); + } + + // set all infos + setallinfo_(); + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Disconnect socket + */ +void Connection::disconnect() { + if (socket < 0) + throw Error(ERR_NET, "No connection established but trying to disconnect"); + + // lock all mutex + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + disconnect_(); + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Return the connection sate + * Cannot be const, du to mutex locking + * + * @return see description + */ +bool Connection::connected() { + // get connection mutex + + pthread_mutex_lock(&c_mutex_); + + bool ret = (socket_fd_ >= 0); + + pthread_mutex_unlock(&c_mutex_); + + return ret; +} + +/** + * Accept new connection on a listening socket + * + * @return null on error, else a new connection + */ +Connection *Connection::accept() { + if (socket < 0) + throw Error(ERR_NET, "No connection established but trying to accept"); + + struct sockaddr_in r_addr; + socklen_t r_sin_size = sizeof r_addr; + int r_fd; + + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + if ((r_fd = ::accept(socket_fd_, (struct sockaddr *) &r_addr, &r_sin_size)) == -1) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "accept: " + strerror(errno)); + } + + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&w_mutex_); + + return new Connection(r_fd); +} + +/** + * Send data on @param buf of size @param len on socket + */ +void Connection::send(const char* buf, size_t len) { + if (socket < 0) + throw Error(ERR_NET, "No connection established but trying to send data"); + + pthread_mutex_lock(&w_mutex_); + int ret = ::send(socket_fd_, buf, len, 0); + pthread_mutex_unlock(&w_mutex_); + + if (ret == -1 && errno == ECONNRESET) + throw Error(ERR_NET, "Connection reset by peer"); + if (ret == -1) + throw Error(ERR_NET, "send: " + (string) strerror(errno)); +} + +/** + * Send data on @param buf of size @param len followed by '\n' on socket + */ +void Connection::sendln(const char* buf, size_t len) { + if (socket < 0) + throw Error(ERR_NET, "No connection established but trying to send line"); + + pthread_mutex_lock(&w_mutex_); + // write data + int ret = ::send(socket_fd_, buf, len, 0); + if (ret == -1) { + pthread_mutex_unlock(&w_mutex_); + if (errno == ECONNRESET) + throw Error(ERR_NET, "Connection reset by peer"); + throw Error(ERR_NET, "sendln: " + (string) strerror(errno)); + } + + // write '\n' + ret = ::send(socket_fd_, "\n", 1, 0); + pthread_mutex_unlock(&w_mutex_); + if (ret == -1) + throw Error(ERR_NET, "sendln: " + (string) strerror(errno)); +} + +/** + * Receive a line + */ +string Connection::recvln() { + if (socket < 0) + throw Error(ERR_NET, "No connection established but trying to receive line"); + + pthread_mutex_lock(&r_mutex_); + do { + // check EOL char + size_t offset = rbuf_.find('\n'); + if (offset != string::npos) { + string s = rbuf_.substr(0, offset); + rbuf_.erase(0, offset + 1); + pthread_mutex_unlock(&r_mutex_); + return s; + } + + // do poll fd here ? + + // read data + static char local_buf[MAX_LINE_SIZE]; + int ret = ::recv(socket_fd_, local_buf, MAX_LINE_SIZE, 0); + + if (ret == 0) { + pthread_mutex_unlock(&r_mutex_); + throw Error(ERR_NET, "Connection reset by peer"); + } + + if (ret == -1) { + *local_buf = 0; + + // unlock before error + pthread_mutex_unlock(&r_mutex_); + + throw Error(ERR_NET, (string) "recvln: " + strerror(errno)); + } + else local_buf[ret] = 0; + + // add read data in buffer + rbuf_ += local_buf; + + } while (1); + assert(1); +} + +string Connection::getlocalip() { + pthread_mutex_lock(&c_mutex_); + if (local_ip_.empty()) + setlocalip_(); + string ip = local_ip_; + pthread_mutex_unlock(&c_mutex_); + return ip; +} + +int Connection::getlocalport() { + pthread_mutex_lock(&c_mutex_); + if (local_port_ == -1) + setlocalport_(); + int port = local_port_; + pthread_mutex_unlock(&c_mutex_); + return port; +} + +string Connection::getremoteip() { + pthread_mutex_lock(&c_mutex_); + if (remote_ip_.empty()) + setremoteip_(); + string ip = remote_ip_; + pthread_mutex_unlock(&c_mutex_); + return ip; +} + +int Connection::getremoteport() { + pthread_mutex_lock(&c_mutex_); + if (remote_port_ == -1) + setremoteport_(); + int port = remote_port_; + pthread_mutex_unlock(&c_mutex_); + return port; +} + +int Connection::getsocket() { + pthread_mutex_lock(&c_mutex_); + int ret = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + return ret; +} + +/******************************************************************************* + ** Protected method + ******************************************************************************/ + +/** + * Reserve a socket + * No mutex used ! + */ +void Connection::socket_() { + assert(socket_fd_ == -1); + int yes = 1; + + if ((socket_fd_ = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) + throw Error(ERR_NET, (string) "Unable to open socket: " + strerror(errno)); + + if (::setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + throw Error(ERR_NET, (string) "Unable to set socket options: " + strerror(errno)); +} + +/** + * Free a socket + * No mutex used ! + */ +void Connection::disconnect_() { + assert(socket_fd_ >= 0); + + close(socket_fd_); + socket_fd_ = -1; +} + +/** + * Set local ip + * No mutex used ! + */ +void Connection::setlocalip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + ::getsockname(socket_fd_, (struct sockaddr*) &addr, &len); + local_ip_ = inet_ntoa(addr.sin_addr); +} + +/** + * Set local port + * No mutex used ! + */ +void Connection::setlocalport_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + ::getsockname(socket_fd_, (struct sockaddr*) &addr, &len); + local_port_ = ntohs(addr.sin_port); +} + +/** + * Set remote ip + * No mutex used ! + */ +void Connection::setremoteip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + ::getpeername(socket_fd_, (struct sockaddr*) &addr, &len); + remote_ip_ = inet_ntoa(addr.sin_addr); +} + +/** + * Set remote port + * No mutex used ! + */ +void Connection::setremoteport_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + ::getpeername(socket_fd_, (struct sockaddr*) &addr, &len); + remote_port_ = ntohs(addr.sin_port); +} diff --git a/sls/trunk/src/connection.hh b/sls/trunk/src/connection.hh new file mode 100644 index 0000000000000000000000000000000000000000..0379ff73877b761a55f0841e8d8716cf7065ac16 --- /dev/null +++ b/sls/trunk/src/connection.hh @@ -0,0 +1,88 @@ +/* + 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 +*/ + +#ifndef CONNECTION_HH +# define CONNECTION_HH + +# include + +class Connection { + // public methods +public: + Connection(int fd = -1); + virtual ~Connection(); + + void connect(const char *addr, int port); + void listen(int port, int max); + + void disconnect(); + bool connected(); + + Connection *accept(); + + // send methods + inline void send(const string &data); + void send(const char* buf, size_t len); + inline void sendln(const string &data); + void sendln(const char* buf, size_t len); + + // recv methods + string recvln(); + + // info methods + string getlocalip(); + int getlocalport(); + + string getremoteip(); + int getremoteport(); + + int getsocket(); + + // protected methods +protected: + void socket_(); + void disconnect_(); + + inline void setallinfo_(); + void setlocalip_(); + void setlocalport_(); + void setremoteip_(); + void setremoteport_(); + + // Protected datas +protected: + int socket_fd_; // connection socket + + // storage of info about connection + int local_port_; + int remote_port_; + + string local_ip_; + string remote_ip_; + + string rbuf_; // read buffer + string wbuf_; // write buffer + + pthread_mutex_t c_mutex_; // connection mutex + pthread_mutex_t r_mutex_; // read mutex + pthread_mutex_t w_mutex_; // write mutex +}; + +# include "connection.hxx" + +#endif diff --git a/sls/trunk/src/connection.hxx b/sls/trunk/src/connection.hxx new file mode 100644 index 0000000000000000000000000000000000000000..92b5bf707be7ffcd518a966ccdffef9199538145 --- /dev/null +++ b/sls/trunk/src/connection.hxx @@ -0,0 +1,49 @@ +/* + 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 +*/ + +/******************************************************************************* + ** Public method + ******************************************************************************/ + +/** + * Send @param data on socket + */ +void Connection::send(const string &data) { + send(data.c_str(), data.length()); +} + +/** + * Send @param data followed by '\n' on socket + */ +void Connection::sendln(const string &data) { + sendln(data.c_str(), data.length()); +} + +/******************************************************************************* + ** Protected method + ******************************************************************************/ + +/** + * Set all information about a connection + */ +void Connection::setallinfo_() { + setlocalip_(); + setlocalport_(); + setremoteip_(); + setremoteport_(); +} diff --git a/sls/trunk/src/error.cc b/sls/trunk/src/error.cc index ca3372387e90097ee59c7eb648a8cc4e1c9fb1a6..385d6afeb602a7b8f06e4d66969f474f73e1c8ae 100644 --- a/sls/trunk/src/error.cc +++ b/sls/trunk/src/error.cc @@ -75,6 +75,23 @@ void Error::code(int v) val_ = v; } +/*! +** Concatenate @param s before error message +*/ +void Error::prefix(const string &s) { + string buf = s + msg_.str(); + + msg_.str(""); + msg_ << buf; +} + +/*! +** Concatenate @param s to errror message +*/ +void Error::suffix(const string &s) { + msg_ << s; +} + /*! ** Copy operator */ @@ -124,3 +141,4 @@ Error &operator>>(Error &e, const string &s) e.msg_ << buf; return e; } + diff --git a/sls/trunk/src/error.hh b/sls/trunk/src/error.hh index 4e183e8ce9ffb986f51aff88f3d6e5bd28f6182f..b91555b86a1d53799e37a3d5a10eac748157b1e6 100644 --- a/sls/trunk/src/error.hh +++ b/sls/trunk/src/error.hh @@ -32,10 +32,16 @@ class Error public: Error(int i, string s = ""); Error(const Error &e); + void print() const; string message() const; + + void suffix(const string &); + void prefix(const string &); + int code() const; void code(int); + Error &operator=(const Error &rhs); friend ostream &operator<<(ostream &o, const Error &e); friend Error &operator<<(Error &e, const string &s); diff --git a/sls/trunk/src/option.cc b/sls/trunk/src/option.cc index 9630fa8b8935b95789528ef43962d38a83768ff3..3c813f6113789873e4bf6e2adcae8565bfe72f5b 100644 --- a/sls/trunk/src/option.cc +++ b/sls/trunk/src/option.cc @@ -79,6 +79,7 @@ Option &Option::load(int argc, char *argv[]) { switch (option) { case 'h': usage(*argv, std::cout); + exit(ERR_NO); break; case 'p': port = atoi(optarg); @@ -96,7 +97,7 @@ Option &Option::load(int argc, char *argv[]) { logfile = optarg; break; case 'V': - std::cerr << "version : " << VERSION << std::endl; + std::cerr << "Version: " << VERSION << std::endl; exit(ERR_NO); case 'D': daemon = false; @@ -157,7 +158,7 @@ void Option::print(ostream &s) const { s << "Database file: " << database << std::endl << "Log file: " << logfile << std::endl << "Pid file: " << pidfile << std::endl - << "TCP Port: " << port << std::endl + << "TCP port: " << port << std::endl << "Max conn: " << maxconn << std::endl << "Debug mode: " << !daemon << std::endl; } diff --git a/sls/trunk/src/server.cc b/sls/trunk/src/server.cc index 11961752af37515b1f6067e7fdf48934f5431cb6..e5a6d1f00cb02b50e4d9b5c0e2718b921e0fcafc 100644 --- a/sls/trunk/src/server.cc +++ b/sls/trunk/src/server.cc @@ -18,36 +18,180 @@ #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() : socket_(0), thread_count_(0) {} +Server::Server() : max_conn_ (0), verbose_(false) { + pthread_mutex_init(&threads_mutex_, 0); +} /*! - * Start server. Creating socket + * Destructor */ -void Server::start() { - +Server::~Server() { + pthread_mutex_destroy(&threads_mutex_); } /*! - * @return if server is started or not + * Start server. */ -bool Server::started() const { - return socket_ != 0; +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); + } } /*! - * Start server. Destroy socket + * 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; } -/*! - * Server listen routine. This create new thead. +/** + * @return if server is started */ -void Server::listen(size_t max_thread) { - assert(max_thread > 0); +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; } diff --git a/sls/trunk/src/server.hh b/sls/trunk/src/server.hh index 95afbf3d043c10d8e2d640288ad6765c490725b0..4077fc62d6e5913b5d6637f88d1fdd1677fb8107 100644 --- a/sls/trunk/src/server.hh +++ b/sls/trunk/src/server.hh @@ -19,28 +19,47 @@ #ifndef SERVER_HH # define SERVER_HH +# include "connection.hh" + # include +# include class Server { public: - typedef std::set stringset; + typedef std::set Stringset; + typedef std::set Threadset; + + enum e_client { + CLI_DAEMON, + CLI_CONSOLE + }; public: Server(); + ~Server(); - void start(); + void start(int port, size_t max_conn, bool verbose = false); void stop(); - void listen(size_t max_thread); - bool started() const; + bool started(); + + e_client login(); + + static void *start_client(void *); private: - stringset logged_hosts_; - stringset logged_users_; + Stringset logged_hosts_; + Stringset logged_users_; - int socket_; - size_t max_thread_; - size_t thread_count_; + Threadset threads_; + pthread_mutex_t threads_mutex_; + + Connection conn_; + size_t max_conn_; + bool verbose_; }; +void *start_client(void *fd); + + #endif diff --git a/sls/trunk/src/sls.cc b/sls/trunk/src/sls.cc index e1807485b1257bddedb32425161adde7475d2e13..2312df32faa1756c649739d8fe5289b0b19b44cf 100644 --- a/sls/trunk/src/sls.cc +++ b/sls/trunk/src/sls.cc @@ -76,6 +76,8 @@ int main(int argc, char *argv[]) O.print(std::cout); } + // FIXME: Signals catchers + // Open DB D.open(O.database); @@ -83,8 +85,7 @@ int main(int argc, char *argv[]) C.start(); // start network - S.start(); - S.listen(O.maxconn); + S.start(O.port, O.maxconn, O.verbose); // stop scheduler C.stop(); @@ -95,6 +96,9 @@ int main(int argc, char *argv[]) return ERR_NO; } catch (const Error &e) { + // Stop cron + C.stop(); + // Close server if started if (S.started()) S.stop(); diff --git a/sls/trunk/src/sls.hh b/sls/trunk/src/sls.hh index a9cb217b115e82afa0d52799a07c894590f575f5..6624b61fea2005659ff78857bf1757b7dc9a6357 100644 --- a/sls/trunk/src/sls.hh +++ b/sls/trunk/src/sls.hh @@ -42,6 +42,8 @@ enum { ERR_PROTO = 5, ERR_AUTH = 6, ERR_DB = 7, + ERR_SRV = 8, + ERR_THREAD = 9, ERR_NOMEM = 41, ERR_UNKNOWN = 42 }; @@ -50,8 +52,7 @@ enum { // Gonstant // ----------------------------------------------------------------------------- - -static const string VERSION = (string) "Testing.\nBuild at " + __DATE__ + " " + __TIME__ + "."; +static const string VERSION = (string) "testing.\nBuild: " + __DATE__ + " " + __TIME__ + "."; //static const string VERSION = "1.0"; static const int MAX_LINE_SIZE = 512;