{
socket_server::socket_server(int port, const char* ip)
- : server()
+ : server(), socket_handler(0,tcp_s)
{
- socket_type=tcp_s;
-
+ // TODO
}
socket_server::socket_server(const char* path, mode_t filemode, const char* user, const char* group)
- : server()
+ : server(), socket_handler(0,unix_s)
{
- socket_type=unix_s;
unix_path=path;
/* Create the socket. */
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);
- }
-
- /* 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(sock);
-
- if (socket_type==unix_s)
+ if (get_type()==unix_s)
unlink(unix_path.c_str());
}
FD_SET (newsock, &connection_set);
- int i=1;
-
- /* keepalive enable */
- if (setsockopt(newsock,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(newsock,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(newsock,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(newsock,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(newsock,F_SETFL,flflags) < 0)
- {
- string err="fcntl error on socket: ";
- err+=strerror(errno);
- log(error, err);
- throw t2n_server_error(err);
- }
+ socket_server_connection *nc=new socket_server_connection(newsock, get_type(), get_default_timeout());
+ nc->set_socket_options(newsock);
- add_connection(new socket_connection(newsock, get_default_timeout()));
+ add_connection(nc);
return;
}
void socket_server::fill_connection_buffers()
{
- std::map<unsigned int, connection*>::iterator ie=connections.end();
- for(std::map<unsigned int, connection*>::iterator i=connections.begin(); i != ie; i++)
+ std::map<unsigned int, server_connection*>::iterator ie=connections.end();
+ for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
if (!i->second->is_closed())
- {
- socket_connection* cp=dynamic_cast<socket_connection*>(i->second);
- cp->fill_buffer(connection_set);
- }
+ i->second->fill_buffer();
}
-socket_connection::socket_connection(int _sock, int _timeout)
- : connection(_timeout)
+void socket_server::remove_connection_socket(int sock)
{
- sock=_sock;
+ FD_CLR(sock, &connection_set);
}
-void socket_connection::close()
+void socket_server_connection::close()
{
-
-}
-
-void socket_connection::fill_buffer(fd_set &cur_fdset)
-{
- bool try_again=false;
-
- if (is_closed() || !FD_ISSET (sock, &cur_fdset))
- return; // no data pending or connection closed
-
- // data pending -> go and get it
- char socket_buffer[recv_buffer_size];
-
- int nbytes = read (sock, socket_buffer, recv_buffer_size);
- if (nbytes < 0)
+ if (!is_closed())
{
- if (errno == EAGAIN)
- {
- if (my_server)
- my_server->log(server::error,"read error: no data (EAGAIN) for connection "+get_id_string());
- return;
- }
- else if (errno == EINTR)
- {
- // interrupted, try again
- try_again=true;
- }
- else
- {
- if (my_server)
- my_server->log(server::error,"error reading from socket of connection "+get_id_string()+": "+strerror(errno));
- return;
- }
+ socket_handler::close();
+ server_connection::close();
}
- // End-of-file
- if (nbytes == 0 && !try_again)
+ if (my_server)
{
- close();
- return;
+ dynamic_cast<socket_server*>(my_server)->remove_connection_socket(sock);
}
-
- // Data read -> store it
- if (nbytes > 0)
- buffer.assign(socket_buffer,nbytes);
-
- // more data waiting?
- fd_set active_fd_set;
- struct timeval tval;
-
- FD_ZERO (&active_fd_set);
- FD_SET (sock, &active_fd_set);
-
- /* no waiting */
- tval.tv_sec=0;
- tval.tv_usec=0;
-
- if (select (FD_SETSIZE, &active_fd_set, NULL, NULL, &tval) >0)
- {
- /* more data waiting -> recurse */
- fill_buffer(active_fd_set);
- }
-
- reset_timeout();
-
- return;
-}
-
-void socket_connection::write(const std::string& data)
-{
- static const unsigned int write_block_size=4096;
-
- if (is_closed())
- return;
-
- // prepend packet size to data
- packet_size_indicator psize=data.size();
- string send_data(data);
- send_data.insert(0,(char*)psize,sizeof(packet_size_indicator));
-
- int offset = 0;
- while (offset < send_data.size())
- {
- unsigned int write_size=write_block_size;
-
- if (offset+write_size > send_data.size())
- write_size = send_data.size()-offset;
-
- int rtn;
- while ((rtn=::write(sock, send_data.data()+offset, write_size)) &&
- rtn == -1 && (errno == EAGAIN || errno == EINTR))
- {
- usleep (80000);
- if (my_server)
- my_server->log(server::debug,"resuming write() call after EAGAIN or EINTR for connection "+get_id_string());
- }
-
- if (rtn == -1)
- {
- if (my_server)
- my_server->log(server::error,"write() error on connection "+get_id_string()+": "+strerror(errno));
- }
- else if (rtn != write_size)
- {
- if (my_server)
- {
- ostringstream msg;
- msg << "write() error on connection " << get_id()
- << ": wrote " << rtn << " bytes, should have been "
- << write_size << " (complete: " << send_data.size() << ")";
-
- my_server->log(server::error,msg.str());
- }
- }
-
- offset += write_size;
- }
-
- reset_timeout();
-
- return;
}
}