2 Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
10 As a special exception, if other files instantiate templates or use macros
11 or inline functions from this file, or you compile this file and link it
12 with other works to produce a work based on this file, this file
13 does not by itself cause the resulting work to be covered
14 by the GNU General Public License.
16 However the source code for this file must still be made available
17 in accordance with section (3) of the GNU General Public License.
19 This exception does not invalidate any other reasons why a work based
20 on this file might be covered by the GNU General Public License.
27 #include <boost/bind.hpp>
31 #include "monotonic_clock.hxx"
36 server_connection::server_connection(int _timeout)
41 set_timeout(_timeout);
48 server_connection::~server_connection()
52 /// get pointer to logging stream, returns NULL if no logging needed
53 std::ostream* server_connection::get_logstream(log_level_values level)
55 if (my_server != NULL)
57 std::ostream* ostr=my_server->get_logstream(level);
59 (*ostr) << "connection " << get_id() << ": ";
66 /// check if timeout is expired, close connection if so
67 void server_connection::check_timeout()
69 if (timeout != -1 && last_action_time+timeout < monotonic_clock_gettime_sec())
71 LOGSTREAM(debug,"timeout on connection " << connection_id << ", closing");
76 /// reset the timeout, e.g. if something is received
77 void server_connection::reset_timeout()
79 last_action_time=monotonic_clock_gettime_sec();
82 /** @brief add a callback to one connection
84 @param event event the function will be called at
85 @param func functor (see boost::function) that will be called
87 void server_connection::add_callback(callback_event_type event, const boost::function<void ()>& func)
89 if (event == new_connection)
90 throw std::logic_error("new_connection callback not allowed for server_connections");
92 connection::add_callback(event,func);
96 : callbacks(__events_end)
98 set_default_timeout(30);
99 set_logging(NULL,none);
105 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
106 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
113 * Close all open connections
117 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
118 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; ++i)
122 /** @brief add a callback
124 @param event event the function will be called at
125 @param func functor (see boost::function) that will be called
127 @note use boost::bind to bind to member functions like this:
128 s.add_callback(new_connection,boost::bind(&my_class::func_to_call_back, boost::ref(*this), _1));
130 void server::add_callback(callback_event_type event, const boost::function<void (unsigned int)>& func)
132 callbacks[event].push_back(func);
134 // add callback to all existing connections
135 if (event != new_connection)
137 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
138 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
139 i->second->add_callback(event,boost::bind(func, i->first));
144 /** @brief an event occurred, call all server-side callbacks
146 @param event event that occurred
147 @param conn_id connection-id parameter that will be given to the callback-function
149 void server::do_callbacks(callback_event_type event, unsigned int conn_id)
151 std::list<boost::function<void (unsigned int)> >::iterator i,ie=callbacks[event].end();
152 for (i=callbacks[event].begin(); i != ie; i++)
156 /// add a new connection to the server
157 unsigned int server::add_connection(server_connection* newconn)
159 unsigned int cid=next_id++;
160 newconn->set_id(cid);
161 newconn->set_server(this);
162 connections[cid]=newconn;
164 // add all callbacks except new_connection
165 for(int e=connection_closed; e != __events_end; e++)
167 std::list<boost::function<void (unsigned int)> >::iterator i,ie=callbacks[e].end();
168 for (i=callbacks[e].begin(); i != ie; i++)
169 newconn->add_callback(static_cast<callback_event_type>(e),bind(*i,cid));
172 LOGSTREAM(debug,"new connection accepted, id: " << cid);
174 do_callbacks(new_connection,cid);
179 /// activate logging to the given stream. everything above the given level is logged.
180 void server::set_logging(std::ostream *_logstream, log_level_values _log_level)
182 log_level=_log_level;
183 logstream=_logstream;
187 @brief Gets a connection by id
189 @param conn_id Connection ID
191 @retval Pointer to connection object
193 server_connection* server::get_connection(unsigned int conn_id)
195 std::map<unsigned int, server_connection*>::iterator p=connections.find(conn_id);
196 if (p==connections.end())
202 /// check for timeouts, remove closed connections. don't forget to call this from time to time.
203 void server::cleanup()
205 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
206 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
207 i->second->check_timeout();
209 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie;)
211 if (i->second->is_closed() && !i->second->packet_available())
213 // closed and no usable data in buffer -> remove
214 LOGSTREAM(debug,"removing connection " << i->first << " because it is closed and no more data waiting");
217 connections.erase(i);
218 i=connections.begin();
219 ie=connections.end();
226 /** @brief get a complete data packet from any client. The packet is removed from the
228 @param[out] data the data package
229 @param[out] conn_id the connection id we got this packet from
230 @retval true if packet found
232 bool server::get_packet(std::string& data, unsigned int& conn_id)
234 // todo: this is somehow unfair: the first connections in the map get checked more
235 // often than the others and can thus block them out
237 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
238 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
239 if (i->second->get_packet(data))
241 LOGSTREAM(debug,"got packet (" << data.size() << " bytes) from connection " << i->first);
250 /// get pointer to logging stream, returns NULL if no logging needed
251 std::ostream* server::get_logstream(log_level_values level)
253 if (logstream && log_level >= level)