From 0cf4dc9bf7fa527751fd7dc425f882fc86888132 Mon Sep 17 00:00:00 2001 From: Gerd v. Egidy Date: Fri, 6 Oct 2006 14:11:25 +0000 Subject: [PATCH] libt2n: (gerd) fixes & improvements --- src/server.cpp | 8 ++ src/server.hxx | 4 + src/socket_server.cpp | 216 ++++++++++++++++++++++++++++++++++++++++++++++--- src/socket_server.hxx | 17 +++-- src/t2n_exception.hxx | 38 +++++----- 5 files changed, 246 insertions(+), 37 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index b749afa..a319cf4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -76,6 +76,14 @@ void server::check_timeout() i->second->check_timeout(); } +void server::fill_connection_buffers(void) +{ + std::map::iterator ie=connections.end(); + for(std::map::iterator i=connections.begin(); i != ie; i++) + if (!i->second->is_closed()) + i->second->fill_buffer(); +} + bool server::get_packet(std::string& data, unsigned int& conn_id) { // todo: this is somehow unfair: the first connections in the map get checked more diff --git a/src/server.hxx b/src/server.hxx index 3d28584..7b45ac6 100644 --- a/src/server.hxx +++ b/src/server.hxx @@ -103,7 +103,11 @@ class server bool get_packet(std::string& data, unsigned int& conn_id); + void fill_connection_buffers(void); + protected: + void log(log_level_values level, const std::string& message) + { log(level,message.c_str()); } void log(log_level_values level, const char* message); }; diff --git a/src/socket_server.cpp b/src/socket_server.cpp index f94d959..6ef9317 100644 --- a/src/socket_server.cpp +++ b/src/socket_server.cpp @@ -17,7 +17,26 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "socket_server.hxx" +#include "t2n_exception.hxx" + +using namespace std; namespace libt2n { @@ -25,43 +44,218 @@ namespace libt2n socket_server::socket_server(int port, const char* ip) : server() { - type=tcp; + socket_type=tcp_s; } -socket_server::socket_server(const char* path, mode_t chmod, const char* user, const char* group) +socket_server::socket_server(const char* path, mode_t filemode, const char* user, const char* group) : server() { - type=unix; + socket_type=unix_s; unix_path=path; - struct sockaddr_un unix_name; - /* Create the socket. */ - socket = socket (PF_UNIX, SOCK_STREAM, 0); - if (socket < 0) + sock = socket (PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { string err="error opening socket: "; - err+=::strerror(errno); + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + set_socket_options(sock); + + /* Give the socket a name. */ + struct sockaddr_un unix_name; + unix_name.sun_family = AF_UNIX; + strncpy (unix_name.sun_path, unix_path.c_str(),sizeof(unix_name.sun_path)); + + /* just to make sure there is no other socket file */ + unlink (unix_name.sun_path); + + if (bind (sock, (struct sockaddr *) &unix_name, sizeof (unix_name)) < 0) + { + string err="error binding socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + /* change permissions */ + if (chmod (unix_name.sun_path, filemode) != 0) + { + string err="error changing permission: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + struct passwd *socket_user = getpwnam (user); + if (socket_user == NULL) + { + string err="error getting socket user: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + struct group *socket_group = getgrnam (group); + if (socket_group == NULL) + { + string err="error getting socket group: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + if (chown (unix_name.sun_path, socket_user->pw_uid, socket_group->gr_gid) != 0) + { + string err="error changing socket ownership: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + if (listen (sock, 5) < 0) + { + string err="error listening to socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + /* clear & insert server sock into the fd_tab to prepare select */ + FD_ZERO(&connection_set); + FD_SET (sock, &connection_set); +} + +void socket_server::set_socket_options(int sock) +{ + int i=1; + + /* fast reuse enable */ + if (setsockopt(sock,SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) + { + string err="error setting socket option: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } -// throw EXCEPTION(network_server_error,err); + /* keepalive enable */ + if (setsockopt(sock,SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i)) < 0) + { + string err="error setting socket option: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); } + /* close on exec */ + int fdflags; + fdflags=fcntl(sock,F_GETFD, 0); + if (fdflags < 0) + { + string err="fcntl error on socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + fdflags |= FD_CLOEXEC; + if (fcntl(sock,F_SETFD,fdflags) < 0) + { + string err="fcntl error on socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + + /* non-blocking mode */ + int flflags; + flflags=fcntl(sock,F_GETFL,0); + if (flflags < 0) + { + string err="fcntl error on socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + flflags |= O_NONBLOCK; + if (fcntl(sock,F_SETFL,flflags) < 0) + { + string err="fcntl error on socket: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } } socket_server::~socket_server() { - close(socket); + close(sock); - if (type==unix) + if (socket_type==unix_s) unlink(unix_path.c_str()); } +void socket_server::new_connection() +{ +} void socket_server::fill_buffer(long long usec_timeout) { + fd_set used_fdset=connection_set; + + /* set timeout */ + struct timeval tval; + struct timeval *timeout_ptr; + + if (usec_timeout == -1) + timeout_ptr = NULL; + else + { + timeout_ptr = &tval; + + // timeout von long long usec in int sec + int usec umrechnen + tval.tv_sec = usec_timeout / 1000000; + tval.tv_usec = usec_timeout % 1000000; + } + + int ret=select (FD_SETSIZE, &used_fdset, NULL, NULL, timeout_ptr); + + if (ret < 0) + { + if (errno == EINTR) + { + // select interrupted by signal + ret=0; + } + else + { + string err="select error: "; + err+=strerror(errno); + log(error, err); + throw t2n_server_error(err); + } + } + + if (ret > 0) + { + // we have data pending + + // check for new connection + if (FD_ISSET (sock, &used_fdset)) + { + new_connection(); + } + + // check all connections for pending data + fill_connection_buffers(); + } + return; } socket_connection::socket_connection(int _socket, int _timeout) diff --git a/src/socket_server.hxx b/src/socket_server.hxx index ca2f03c..8f1b84c 100644 --- a/src/socket_server.hxx +++ b/src/socket_server.hxx @@ -29,22 +29,25 @@ namespace libt2n class socket_server : public server { public: - enum socket_type { tcp, unix }; + enum socket_type_value { tcp_s, unix_s }; private: - int socket; + int sock; fd_set connection_set; - socket_type type; - string unix_path; + socket_type_value socket_type; + std::string unix_path; + + void set_socket_options(int sock); + void new_connection(); public: socket_server(int port, const char* ip="0.0.0.0"); - socket_server(const char* path, mode_t chmod, const char* user="", const char* group=""); + socket_server(const char* path, mode_t filemode, const char* user="", const char* group=""); ~socket_server(); - socket_type get_type() - { return type; } + socket_type_value get_type() + { return socket_type; } void fill_buffer(long long usec_timeout=-1); }; diff --git a/src/t2n_exception.hxx b/src/t2n_exception.hxx index c756b09..364a194 100644 --- a/src/t2n_exception.hxx +++ b/src/t2n_exception.hxx @@ -22,8 +22,8 @@ #include #include +#include #include -#include // serialization for std::exception namespace boost { @@ -44,7 +44,7 @@ namespace libt2n class t2n_exception : public std::exception { private: - string message; + std::string message; friend class boost::serialization::access; template @@ -55,7 +55,7 @@ class t2n_exception : public std::exception } public: - t2n_exception(const string& _message) + t2n_exception(const std::string& _message) { message=_message; } t2n_exception() @@ -87,14 +87,14 @@ class t2n_communication_error : public t2n_exception } public: - t2n_communication_error(const string& _message) + t2n_communication_error(const std::string& _message) : t2n_exception(_message) { } t2n_communication_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_communication_error(*this); } void do_throw() @@ -114,14 +114,14 @@ class t2n_connect_error : public t2n_communication_error } public: - t2n_connect_error(const string& _message) + t2n_connect_error(const std::string& _message) : t2n_communication_error(_message) { } t2n_connect_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_connect_error(*this); } void do_throw() @@ -141,14 +141,14 @@ class t2n_server_error : public t2n_communication_error } public: - t2n_server_error(const string& _message) + t2n_server_error(const std::string& _message) : t2n_communication_error(_message) { } t2n_server_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_server_error(*this); } void do_throw() @@ -168,14 +168,14 @@ class t2n_transfer_error : public t2n_communication_error } public: - t2n_transfer_error(const string& _message) + t2n_transfer_error(const std::string& _message) : t2n_communication_error(_message) { } t2n_transfer_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_transfer_error(*this); } void do_throw() @@ -195,14 +195,14 @@ class t2n_version_mismatch : public t2n_communication_error } public: - t2n_version_mismatch(const string& _message) + t2n_version_mismatch(const std::string& _message) : t2n_communication_error(_message) { } t2n_version_mismatch() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_version_mismatch(*this); } void do_throw() @@ -222,14 +222,14 @@ class t2n_command_error : public t2n_exception } public: - t2n_command_error(const string& _message) + t2n_command_error(const std::string& _message) : t2n_exception(_message) { } t2n_command_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_command_error(*this); } void do_throw() @@ -249,14 +249,14 @@ class t2n_serialization_error : public t2n_exception } public: - t2n_serialization_error(const string& _message) + t2n_serialization_error(const std::string& _message) : t2n_exception(_message) { } t2n_serialization_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_serialization_error(*this); } void do_throw() @@ -277,14 +277,14 @@ class t2n_runtime_error : public t2n_exception } public: - t2n_runtime_error(const string& _message) + t2n_runtime_error(const std::string& _message) : t2n_exception(_message) { } t2n_runtime_error() { } - ipc_exception* clone() const + t2n_exception* clone() const { return new t2n_runtime_error(*this); } void do_throw() -- 1.7.1