server.hh
/* server.hh - a line-protocol network server
* Copyright 2003-2005 Bas Wijnen <wijnen@debian.org>
*
* This program 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, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SHEVEK_SERVER_HH
#define SHEVEK_SERVER_HH
#include "refbase.hh"
#include "telnet.hh"
#include <list>
#include <signal.h>
namespace
{
sighandler_t ignore_broken_pipes = ::signal (SIGPIPE, SIG_IGN);
}
namespace shevek
{
template <typename client, typename serverdata>
class server : virtual public shevek::refbase
{
static inline fd::read_lines_t get_connection_cb_from_friend (client *who)
{ return sigc::mem_fun (who, &client::read); }
public:
typedef typename std::list <Glib::RefPtr <client> >::iterator iterator;
typedef typename std::list <Glib::RefPtr <client> >::const_iterator
const_iterator;
struct connection : virtual public refbase
{
Glib::RefPtr <shevek::fd> in;
Glib::RefPtr <shevek::fd> out;
void continue_reading ()
{
in->read_lines (server <client, serverdata>
::get_connection_cb_from_friend
(dynamic_cast <client *> (this) ) );
}
~connection () {}
protected:
connection () {}
Glib::RefPtr <server <client, serverdata> > get_server () { return m_server; }
void disconnect () { m_server->l_error (m_self); }
private:
friend class server <client, serverdata>;
Glib::RefPtr <server <client, serverdata> > m_server;
iterator m_self;
};
private:
std::list <Glib::RefPtr <client> > m_connections;
Glib::RefPtr <socket> m_listener;
serverdata m_data;
server ();
void l_read (std::string const &line, Glib::RefPtr <client> conn);
void l_connect (Glib::RefPtr <fd> in, Glib::RefPtr <fd> out,
bool is_stdio);
void l_pickup ();
void l_delayed_disconnect (typename std::list <Glib::RefPtr <client> >::iterator conn);
void l_error (typename std::list <Glib::RefPtr <client> >::iterator conn);
public:
static Glib::RefPtr <server> create ();
void open (std::string const &port, bool use_stdio = true);
serverdata &data () { return m_data; }
serverdata const &data () const { return m_data;}
iterator begin () { return m_connections.begin (); }
iterator end () { return m_connections.end (); }
const_iterator begin () const { return m_connections.begin (); }
const_iterator end () const { return m_connections.end (); }
void shutdown ();
~server () { shutdown (); }
};
template <typename client, typename serverdata>
void server <client, serverdata>::shutdown ()
{
if (m_listener)
{
m_listener->disconnect ();
m_listener = Glib::RefPtr <socket> ();
}
while (!m_connections.empty () )
m_connections.front ()->disconnect ();
}
template <typename client, typename serverdata>
void server <client, serverdata>::l_read (std::string const &line,
Glib::RefPtr <client> conn)
{
conn->read (line);
}
template <typename client, typename serverdata>
void server <client, serverdata>::l_delayed_disconnect (typename std::list <Glib::RefPtr <client> >::iterator conn)
{
Glib::RefPtr <telnet> s = Glib::RefPtr <telnet>::cast_dynamic ( (*conn)->in);
if (s)
s->disconnect ();
m_connections.erase (conn);
}
template <typename client, typename serverdata>
void server <client, serverdata>::l_error (typename std::list <Glib::RefPtr <client> >::iterator conn)
{
Glib::RefPtr <telnet> s = Glib::RefPtr <telnet>::cast_dynamic ( (*conn)->in);
if (s)
{
s->signal_disconnect ().connect (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_delayed_disconnect), conn) );
s->disconnect ();
}
else
{
(*conn)->in->unread ();
m_connections.erase (conn);
}
}
template <typename client, typename serverdata>
void server <client, serverdata>::l_connect (Glib::RefPtr <fd> in,
Glib::RefPtr <fd> out,
bool is_stdio)
{
m_connections.push_back (client::create () );
m_connections.back ()->in = in;
m_connections.back ()->out = out;
m_connections.back ()->m_server = refptr_this <server <client, serverdata> > ();
m_connections.back ()->m_self = --m_connections.end ();
in->set_error (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
--m_connections.end () ) );
in->set_eof (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
--m_connections.end () ) );
m_connections.back ()->continue_reading ();
out->set_error (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
--m_connections.end () ) );
m_connections.back ()->pickup (is_stdio);
}
template <typename client, typename serverdata>
void server <client, serverdata>::l_pickup ()
{
Glib::RefPtr <telnet> newfd = telnet::create ();
m_listener->accept (newfd);
l_connect (newfd, newfd, false);
}
template <typename client, typename serverdata>
server <client, serverdata>::server ()
{
}
template <typename client, typename serverdata>
Glib::RefPtr <server <client, serverdata> > server <client, serverdata>::create ()
{
return Glib::RefPtr <server <client, serverdata> > (new server <client, serverdata> () );
}
template <typename client, typename serverdata>
void server <client, serverdata>::open (std::string const &port,
bool use_stdio)
{
if (m_listener)
m_listener->disconnect ();
if (!port.empty () )
{
m_listener = socket::create ();
m_listener->listen (port, sigc::mem_fun (*this, &server <client, serverdata>::l_pickup) );
}
if (use_stdio)
{
l_connect
(fd::create (STDIN_FILENO), fd::create (STDOUT_FILENO), true);
}
}
}
#endif
shevek::server::end
iterator end()
Loop over all current connections.
Definition: server.hh:162
shevek::refbase
Base class for classes which want reference counting through Glib::RefPtr.
Definition: refbase.hh:27
shevek::server::connection::in
Glib::RefPtr< shevek::fd > in
The input socket. The client can stop reading from this connection by calling in->unread ()...
Definition: server.hh:113
shevek::server::shutdown
void shutdown()
Stop running this server, closing all current connections.
Definition: server.hh:174
shevek::server::create
static Glib::RefPtr< server > create()
Create a new server object.
Definition: server.hh:251
shevek::fd::read_lines_t
sigc::slot1< void, std::string const & > read_lines_t
Function pointer to call when a complete line has arrived.
Definition: fd.hh:38
shevek::server::connection::disconnect
void disconnect()
This can be called by the client object to close this connection.
Definition: server.hh:131
shevek
Definition: args.hh:52
shevek::fd::create
static Glib::RefPtr< fd > create(int value=-1, Glib::RefPtr< Glib::MainContext > main=Glib::MainContext::get_default())
Create a new fd.
shevek::server::connection::continue_reading
void continue_reading()
This is called after in->unread (), to resume accepting data from this connection.
Definition: server.hh:117
shevek::server::connection::out
Glib::RefPtr< shevek::fd > out
The output socket. This is used to send data to the connection.
Definition: server.hh:115
shevek::server::const_iterator
std::list< Glib::RefPtr< client > >::const_iterator const_iterator
Iterator for looping over all current connections.
Definition: server.hh:105
shevek::server::begin
const_iterator begin() const
Loop over all current connections.
Definition: server.hh:164
shevek::server::connection
Base of the client class which is implemented by the calling program.
Definition: server.hh:110
shevek::server::connection::connection
connection()
The client class can construct this object with its create function.
Definition: server.hh:127
shevek::server::~server
~server()
The destructor shuts down the server.
Definition: server.hh:170
shevek::server::end
const_iterator end() const
Loop over all current connections.
Definition: server.hh:166
shevek::socket::create
static Glib::RefPtr< socket > create(Glib::RefPtr< Glib::MainContext > main=Glib::MainContext::get_default())
Create a new socket.
shevek::server::connection::get_server
Glib::RefPtr< server< client, serverdata > > get_server()
Access to the server object which hosts this client.
Definition: server.hh:129
shevek::server::connection::~connection
~connection()
Destructor.
Definition: server.hh:124
shevek::telnet::create
static Glib::RefPtr< telnet > create(Glib::RefPtr< Glib::MainContext > main=Glib::MainContext::get_default())
Create a new telnet socket.
shevek::server
Set up a network server using shevek::telnet.
Definition: server.hh:96
shevek::server::begin
iterator begin()
Loop over all current connections.
Definition: server.hh:160
shevek::server::iterator
std::list< Glib::RefPtr< client > >::iterator iterator
Iterator for looping over all current connections.
Definition: server.hh:102
shevek::server::open
void open(std::string const &port, bool use_stdio=true)
Open a port and start running.
Definition: server.hh:257
shevek::server::data
serverdata & data()
Get the corresponding serverdata structure.
Definition: server.hh:156
shevek::server::data
serverdata const & data() const
Get the corresponding serverdata structure.
Definition: server.hh:158