X-Git-Url: http://developer.intra2net.com/git/?p=libt2n;a=blobdiff_plain;f=src%2Fsocket_server.cpp;fp=src%2Fsocket_server.cpp;h=6ef93177413fa0d5324eaf35eeaffb71002bab34;hp=f94d9598671147d6f13f02cef30b98858929fff6;hb=0cf4dc9bf7fa527751fd7dc425f882fc86888132;hpb=ac7fdc22899c0c493fda5fdb3a4cb67e77504a6b 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)