diff --git a/sls/trunk/src/client.cc b/sls/trunk/src/client.cc index 2299a06a603ff7809db38495f4593dbe55e686c8..00be2c53b7457b41d0fa91e252a619ebfaafca9b 100644 --- a/sls/trunk/src/client.cc +++ b/sls/trunk/src/client.cc @@ -80,6 +80,6 @@ Client::~Client() {} static Client *login_fail(Connection &c) { std::cout << "CId " << c.getid() << ": Bad authentification.\n"; - c.sendln("Bad authentification."); + c.sendln("KO"); return 0; } diff --git a/sls/trunk/src/server.cc b/sls/trunk/src/server.cc index 7c548dfcba627169f67f326368ca1b7410495eb3..1efde304dce735182ad9180d124fae9dd7b03f67 100644 --- a/sls/trunk/src/server.cc +++ b/sls/trunk/src/server.cc @@ -179,7 +179,8 @@ void *Server::start_client(void *voidconn) { } // stop connexion - conn->disconnect(); + try { conn->disconnect(); } + catch (...) {} // Print closing connection std::cout << "CId " << conn->getid() << ": Closed.\n"; @@ -189,5 +190,7 @@ void *Server::start_client(void *voidconn) { S.threads_.erase(t); pthread_mutex_unlock(&S.threads_mutex_); + delete conn; + return 0; } diff --git a/sls/trunk/src/sll/connection.cc b/sls/trunk/src/sll/connection.cc index a3ee8ca112bf4033aee89a627f26d4af90e52344..597f29bb0b95bce61c675486f75b534cbc44c411 100644 --- a/sls/trunk/src/sll/connection.cc +++ b/sls/trunk/src/sll/connection.cc @@ -51,7 +51,13 @@ Connection::Connection(int fd) : socket_fd_(fd), local_port_(-1), remote_port_(- if (socket_fd_ >= 0) { id_ = getconnid(); - setallinfo_(); + try { + setlocalip_(); + setlocalport_(); + setremoteip_(); + setremoteport_(); + } + catch (...) { } } } @@ -64,17 +70,50 @@ Connection::~Connection() { pthread_mutex_destroy(&w_mutex_); } +/** + * Disconnect socket + */ +void Connection::disconnect() { + // lock connection mutex + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to disconnect"); + } + + // lock all 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_); +} + /** * 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"); + // check args + if (addr == 0 || *addr == 0) + throw Error(ERR_NET, "Trying to connect on a bad address"); - if (port <= 0) - throw Error(ERR_NET, "Trying to Connect on a bad port number"); + if (port <= 0 || port >= 65536) + throw Error(ERR_NET, "Trying to connect on a bad port number"); + // take connection mutex pthread_mutex_lock(&c_mutex_); + + // check already existant connection + if (socket_fd_ >= 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "Connection already established but trying to connect"); + } + + // take read and write mutex pthread_mutex_lock(&r_mutex_); pthread_mutex_lock(&w_mutex_); @@ -113,7 +152,18 @@ void Connection::connect(const char *addr, int port) { } // set infos - setallinfo_(); + try { + setlocalip_(); + setlocalport_(); + setremoteip_(); + setremoteport_(); + } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } pthread_mutex_unlock(&w_mutex_); pthread_mutex_unlock(&r_mutex_); @@ -124,11 +174,21 @@ void Connection::connect(const char *addr, int port) { * 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"); + // check arg + if (port <= 0 || port >= 65536) + throw Error(ERR_NET, "Trying to listen on a bad port number"); + if (max <= 0) + throw Error(ERR_NET, "Trying to listen with bad wait queue size"); - // lock + // take connection mutex pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ >= 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "Connection already established but trying to listen"); + } + + // lock read and write mutex pthread_mutex_lock(&r_mutex_); pthread_mutex_lock(&w_mutex_); @@ -168,67 +228,46 @@ void Connection::listen(int port, int max) { } // 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_fd_ < 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_(); + try { + setlocalip_(); + setlocalport_(); + } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } 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_fd_ < 0) + // keep the socket fd + pthread_mutex_lock(&c_mutex_); + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + // test socket validity + if (socket_fd < 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; + // accept is a read/write operation pthread_mutex_lock(&r_mutex_); pthread_mutex_lock(&w_mutex_); - if ((r_fd = ::accept(socket_fd_, (struct sockaddr *) &r_addr, &r_sin_size)) == -1) { + 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)); } @@ -243,51 +282,59 @@ Connection *Connection::accept() { * Send data on @param buf of size @param len on socket */ void Connection::send(const char* buf, size_t len) { - if (socket_fd_ < 0) - throw Error(ERR_NET, "No connection established but trying to send data"); - + // lock mutex for operation + pthread_mutex_lock(&c_mutex_); 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)); -} + // retreive socket_fd and free conn mutex + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); -/** - * 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_fd_ < 0) - throw Error(ERR_NET, "No connection established but trying to send line"); + // test socket validity + if (socket_fd < 0) { + pthread_mutex_unlock(&w_mutex_); + throw Error(ERR_NET, "No connection established but trying to send data"); + } - pthread_mutex_lock(&w_mutex_); - // write data - int ret = ::send(socket_fd_, buf, len, 0); + // send is a write operation + int ret = ::send(socket_fd_, buf, len, MSG_NOSIGNAL); + + // treat error if (ret == -1) { - pthread_mutex_unlock(&w_mutex_); - if (errno == ECONNRESET) + int errno__ = errno; + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + disconnect_(); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + pthread_mutex_unlock(&r_mutex_); + if (errno__ == ECONNRESET)// || errno__ == EPIPE) throw Error(ERR_NET, "Connection reset by peer"); - throw Error(ERR_NET, "sendln: " + (string) strerror(errno)); + else + throw Error(ERR_NET, "send: " + (string) strerror(errno__)); } - // write '\n' - ret = ::send(socket_fd_, "\n", 1, 0); + // release the mutex pthread_mutex_unlock(&w_mutex_); - if (ret == -1) - throw Error(ERR_NET, "sendln: " + (string) strerror(errno)); } /** * Receive a line */ string Connection::recvln() { - if (socket_fd_ < 0) + // lock mutex for operation + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + // test socket validity + if (socket_fd < 0) { + pthread_mutex_unlock(&r_mutex_); 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'); @@ -298,26 +345,26 @@ string Connection::recvln() { 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); + int ret = ::recv(socket_fd, local_buf, MAX_LINE_SIZE, 0); - if (ret == 0) { + if (ret == -1 || ret == 0) { + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&w_mutex_); + disconnect_(); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); 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)); + if (ret == 0) + throw Error(ERR_NET, "Connection reset by peer"); + else + throw Error(ERR_NET, (string) "recvln: " + strerror(errno)); } - else local_buf[ret] = 0; + local_buf[ret] = 0; // add read data in buffer rbuf_ += local_buf; @@ -327,10 +374,14 @@ string Connection::recvln() { } string Connection::getlocalip() { - if (socket_fd_ < 0) + // get local ip is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); throw Error(ERR_NET, "No connection established but trying to get local ip"); + } - pthread_mutex_lock(&c_mutex_); if (local_ip_.empty()) setlocalip_(); string ip = local_ip_; @@ -339,10 +390,14 @@ string Connection::getlocalip() { } int Connection::getlocalport() { - if (socket_fd_ < 0) + // get local port is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); throw Error(ERR_NET, "No connection established but trying to get local port"); + } - pthread_mutex_lock(&c_mutex_); if (local_port_ == -1) setlocalport_(); int port = local_port_; @@ -351,10 +406,14 @@ int Connection::getlocalport() { } string Connection::getremoteip() { - if (socket_fd_ < 0) + // get remote ip is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); throw Error(ERR_NET, "No connection established but trying to get remote ip"); + } - pthread_mutex_lock(&c_mutex_); if (remote_ip_.empty()) setremoteip_(); string ip = remote_ip_; @@ -363,10 +422,14 @@ string Connection::getremoteip() { } int Connection::getremoteport() { - if (socket_fd_ < 0) + // get remote port is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); throw Error(ERR_NET, "No connection established but trying to get remote port"); + } - pthread_mutex_lock(&c_mutex_); if (remote_port_ == -1) setremoteport_(); int port = remote_port_; @@ -379,89 +442,17 @@ unsigned long int Connection::getid() { } int Connection::getsocket() { - if (socket_fd_ < 0) - throw Error(ERR_NET, "No connection established but trying to get socket fd"); - + // get socket is a conn op pthread_mutex_lock(&c_mutex_); - int ret = socket_fd_; + int socket_fd = socket_fd_; pthread_mutex_unlock(&c_mutex_); - return ret; + + if (socket_fd < 0) + throw Error(ERR_NET, "No connection established but trying to get socket fd"); + + return socket_fd; } /******************************************************************************* ** 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/sll/connection.hh b/sls/trunk/src/sll/connection.hh index 194cd85543b552c10938f6f7ee24bf3914f14143..2c89e9bdae275bf8b700f98c068654f520fefc9b 100644 --- a/sls/trunk/src/sll/connection.hh +++ b/sls/trunk/src/sll/connection.hh @@ -2,17 +2,17 @@ This file is part of SLS. Copyright (C) 2008 Sebastien LUTTRINGER - SLS is free software; you can redistribute it and/or modify + SLL 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, + SLL 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 + along with SLL; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -35,15 +35,14 @@ public: void listen(int port, int max); void disconnect(); - bool connected(); + inline bool connected(); Connection *accept(); // send methods - inline void send(const string &data); void send(const char* buf, size_t len); + inline void send(const string &data); inline void sendln(const string &data); - void sendln(const char* buf, size_t len); // recv methods string recvln(); @@ -61,14 +60,13 @@ public: // protected methods protected: - void socket_(); - void disconnect_(); - - inline void setallinfo_(); - void setlocalip_(); - void setlocalport_(); - void setremoteip_(); - void setremoteport_(); + inline void socket_(); + inline void disconnect_(); + + inline void setlocalip_(); + inline void setlocalport_(); + inline void setremoteip_(); + inline void setremoteport_(); // Protected datas protected: diff --git a/sls/trunk/src/sll/connection.hxx b/sls/trunk/src/sll/connection.hxx index 937ae30aca4507693e19c6a6dcbb775011b6849a..3440140358b3e77989e7bf5229908812c1a4fc5a 100644 --- a/sls/trunk/src/sll/connection.hxx +++ b/sls/trunk/src/sll/connection.hxx @@ -16,10 +16,35 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +# include "error.hh" + +#include +#include +#include +#include + /******************************************************************************* ** Public method ******************************************************************************/ +/** + * 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; +} + /** * Send @param data on socket */ @@ -31,7 +56,8 @@ void Connection::send(const string &data) { * Send @param data followed by '\n' on socket */ void Connection::sendln(const string &data) { - sendln(data.c_str(), data.length()); + string tosend = data + "\n"; + send(tosend.c_str(), tosend.length()); } /******************************************************************************* @@ -39,11 +65,79 @@ void Connection::sendln(const string &data) { ******************************************************************************/ /** - * Set all information about a connection + * Free a socket + * No mutex used ! */ -void Connection::setallinfo_() { - setlocalip_(); - setlocalport_(); - setremoteip_(); - setremoteport_(); +void Connection::disconnect_() { + assert(socket_fd_ >= 0); + + close(socket_fd_); + socket_fd_ = -1; +} + +/** + * 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)); +} + +/** + * Set local ip + * No mutex used ! + */ +void Connection::setlocalip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to set local ip: " + strerror(errno)); + 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; + + if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to set local port: " + strerror(errno)); + local_port_ = ntohs(addr.sin_port); +} + +/** + * Set remote ip + * No mutex used ! + */ +void Connection::setremoteip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to set remote ip: " + strerror(errno)); + 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; + + if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to set remote port: " + strerror(errno)); + remote_port_ = ntohs(addr.sin_port); } diff --git a/sls/trunk/src/sll/slm.hh b/sls/trunk/src/sll/slm.hh index 37587ff749a990788b9d0314ebbd54a721e92cbb..97d6271eeec8e7609eaa59059af44c28094f7d01 100644 --- a/sls/trunk/src/sll/slm.hh +++ b/sls/trunk/src/sll/slm.hh @@ -45,6 +45,7 @@ enum { ERR_SRV = 8, ERR_THREAD = 9, ERR_PARSE = 10, + ERR_SCREENSZ = 11, ERR_NOMEM = 41, ERR_UNKNOWN = 42 };