libshevek
|
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