libshevek

- Main Page
- Classes
- Files

- File List

src/server.hh

    00001 /* server.hh - a line-protocol network server
    00002  * Copyright 2003-2005 Bas Wijnen <wijnen@debian.org>
    00003  *
    00004  * This program is free software: you can redistribute it and/or modify
    00005  * it under the terms of the GNU General Public License as published by
    00006  * the Free Software Foundation, either version 3 of the License, or
    00007  * (at your option) any later version.
    00008  *
    00009  * This program is distributed in the hope that it will be useful,
    00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00012  * GNU General Public License for more details.
    00013  *
    00014  * You should have received a copy of the GNU General Public License
    00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    00016  */
    00017
    00018 #ifndef SHEVEK_SERVER_HH
    00019 #define SHEVEK_SERVER_HH
    00020
    00021 #include "refbase.hh"
    00022 #include "telnet.hh"
    00023 #include <list>
    00024 #include <signal.h>
    00025
    00026 namespace
    00027 {
    00028   sighandler_t ignore_broken_pipes = ::signal (SIGPIPE, SIG_IGN);
    00029 }
    00030
    00031 namespace shevek
    00032 {
    00034
    00095   template <typename client, typename serverdata>
    00096   class server : virtual public shevek::refbase
    00097   {
    00098     static inline fd::read_lines_t get_connection_cb_from_friend (client *who)
    00099     { return sigc::mem_fun (who, &client::read); }
    00100   public:
    00102     typedef typename std::list <Glib::RefPtr <client> >::iterator iterator;
    00104     typedef typename std::list <Glib::RefPtr <client> >::const_iterator
    00105     const_iterator;
    00107
    00110     struct connection : virtual public refbase
    00111     {
    00113       Glib::RefPtr <shevek::fd> in;
    00115       Glib::RefPtr <shevek::fd> out;
    00117       void continue_reading ()
    00118       {
    00119         in->read_lines (server <client, serverdata>
    00120                         ::get_connection_cb_from_friend
    00121                         (dynamic_cast <client *> (this) ) );
    00122       }
    00124       ~connection () {}
    00125     protected:
    00127       connection () {}
    00129       Glib::RefPtr <server <client, serverdata> > get_server () { return m_server; }
    00131       void disconnect () { m_server->l_error (m_self); }
    00132     private:
    00133       friend class server <client, serverdata>;
    00134       Glib::RefPtr <server <client, serverdata> > m_server;
    00135       iterator m_self;
    00136     };
    00137   private:
    00138     std::list <Glib::RefPtr <client> > m_connections;
    00139     Glib::RefPtr <socket> m_listener;
    00140     serverdata m_data;
    00141     server ();
    00142     void l_read (std::string const &line, Glib::RefPtr <client> conn);
    00143     void l_connect (Glib::RefPtr <fd> in, Glib::RefPtr <fd> out,
    00144                     bool is_stdio);
    00145     void l_pickup ();
    00146     void l_delayed_disconnect (typename std::list <Glib::RefPtr <client> >::iterator conn);
    00147     void l_error (typename std::list <Glib::RefPtr <client> >::iterator conn);
    00148   public:
    00150     static Glib::RefPtr <server> create ();
    00152
    00154     void open (std::string const &port, bool use_stdio = true);
    00156     serverdata &data () { return m_data; }
    00158     serverdata const &data () const { return m_data;}
    00160     iterator begin () { return m_connections.begin (); }
    00162     iterator end () { return m_connections.end (); }
    00164     const_iterator begin () const { return m_connections.begin (); }
    00166     const_iterator end () const { return m_connections.end (); }
    00168     void shutdown ();
    00170     ~server () { shutdown (); }
    00171   };
    00172
    00173   template <typename client, typename serverdata>
    00174   void server <client, serverdata>::shutdown ()
    00175   {
    00176     if (m_listener)
    00177       {
    00178         m_listener->disconnect ();
    00179         m_listener = Glib::RefPtr <socket> ();
    00180       }
    00181     while (!m_connections.empty () )
    00182       m_connections.front ()->disconnect ();
    00183   }
    00184
    00185   template <typename client, typename serverdata>
    00186   void server <client, serverdata>::l_read (std::string const &line,
    00187                               Glib::RefPtr <client> conn)
    00188   {
    00189     conn->read (line);
    00190   }
    00191
    00192   template <typename client, typename serverdata>
    00193   void server <client, serverdata>::l_delayed_disconnect (typename std::list <Glib::RefPtr <client> >::iterator conn)
    00194   {
    00195     Glib::RefPtr <telnet> s = Glib::RefPtr <telnet>::cast_dynamic ( (*conn)->in);
    00196     if (s)
    00197       s->disconnect ();
    00198     m_connections.erase (conn);
    00199   }
    00200
    00201   template <typename client, typename serverdata>
    00202   void server <client, serverdata>::l_error (typename std::list <Glib::RefPtr <client> >::iterator conn)
    00203   {
    00204     Glib::RefPtr <telnet> s = Glib::RefPtr <telnet>::cast_dynamic ( (*conn)->in);
    00205     if (s)
    00206       {
    00207         s->signal_disconnect ().connect (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_delayed_disconnect), conn) );
    00208         s->disconnect ();
    00209       }
    00210     else
    00211       {
    00212         (*conn)->in->unread ();
    00213         m_connections.erase (conn);
    00214       }
    00215   }
    00216
    00217   template <typename client, typename serverdata>
    00218   void server <client, serverdata>::l_connect (Glib::RefPtr <fd> in,
    00219                                              Glib::RefPtr <fd> out,
    00220                                              bool is_stdio)
    00221   {
    00222     m_connections.push_back (client::create () );
    00223     m_connections.back ()->in = in;
    00224     m_connections.back ()->out = out;
    00225     m_connections.back ()->m_server = refptr_this <server <client, serverdata> > ();
    00226     m_connections.back ()->m_self = --m_connections.end ();
    00227     in->set_error (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
    00228                                --m_connections.end () ) );
    00229     in->set_eof (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
    00230                                --m_connections.end () ) );
    00231     m_connections.back ()->continue_reading ();
    00232     out->set_error (sigc::bind (sigc::mem_fun (*this, &server <client, serverdata>::l_error),
    00233                                 --m_connections.end () ) );
    00234     m_connections.back ()->pickup (is_stdio);
    00235   }
    00236
    00237   template <typename client, typename serverdata>
    00238   void server <client, serverdata>::l_pickup ()
    00239   {
    00240     Glib::RefPtr <telnet> newfd = telnet::create ();
    00241     m_listener->accept (newfd);
    00242     l_connect (newfd, newfd, false);
    00243   }
    00244
    00245   template <typename client, typename serverdata>
    00246   server <client, serverdata>::server ()
    00247   {
    00248   }
    00249
    00250   template <typename client, typename serverdata>
    00251   Glib::RefPtr <server <client, serverdata> > server <client, serverdata>::create ()
    00252   {
    00253     return Glib::RefPtr <server <client, serverdata> > (new server <client, serverdata> () );
    00254   }
    00255
    00256   template <typename client, typename serverdata>
    00257   void server <client, serverdata>::open (std::string const &port,
    00258                   bool use_stdio)
    00259   {
    00260     if (m_listener)
    00261       m_listener->disconnect ();
    00262     if (!port.empty () )
    00263       {
    00264         m_listener = socket::create ();
    00265         m_listener->listen (port, sigc::mem_fun (*this, &server <client, serverdata>::l_pickup) );
    00266       }
    00267     if (use_stdio)
    00268       {
    00269         l_connect
    00270                 (fd::create (STDIN_FILENO), fd::create (STDOUT_FILENO), true);
    00271       }
    00272   }
    00273 }
    00274
    00275 #endif