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>
35 server_connection::server_connection(int _timeout)
40 set_timeout(_timeout);
47 server_connection::~server_connection()
51 /// get pointer to logging stream, returns NULL if no logging needed
52 std::ostream* server_connection::get_logstream(log_level_values level)
54 if (my_server != NULL)
56 std::ostream* ostr=my_server->get_logstream(level);
58 (*ostr) << "connection " << get_id() << ": ";
65 /// check if timeout is expired, close connection if so
66 void server_connection::check_timeout()
68 if (timeout != -1 && last_action_time+timeout < time(NULL))
70 LOGSTREAM(debug,"timeout on connection " << connection_id << ", closing");
75 /// reset the timeout, e.g. if something is received
76 void server_connection::reset_timeout()
78 last_action_time=time(NULL);
81 /** @brief add a callback to one connection
83 @param event event the function will be called at
84 @param func functor (see boost::function) that will be called
86 void server_connection::add_callback(callback_event_type event, const boost::function<void ()>& func)
88 if (event == new_connection)
89 throw std::logic_error("new_connection callback not allowed for server_connections");
91 connection::add_callback(event,func);
95 : callbacks(__events_end)
97 set_default_timeout(30);
98 set_logging(NULL,none);
104 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
105 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
112 * Close all open connections
116 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
117 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; ++i)
121 /** @brief add a callback
123 @param event event the function will be called at
124 @param func functor (see boost::function) that will be called
126 @note use boost::bind to bind to member functions like this:
127 s.add_callback(new_connection,boost::bind(&my_class::func_to_call_back, boost::ref(*this), _1));
129 void server::add_callback(callback_event_type event, const boost::function<void (unsigned int)>& func)
131 callbacks[event].push_back(func);
133 // add callback to all existing connections
134 if (event != new_connection)
136 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
137 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
138 i->second->add_callback(event,boost::bind(func, i->first));
143 /** @brief an event occurred, call all server-side callbacks
145 @param event event that occurred
146 @param conn_id connection-id parameter that will be given to the callback-function
148 void server::do_callbacks(callback_event_type event, unsigned int conn_id)
150 std::list<boost::function<void (unsigned int)> >::iterator i,ie=callbacks[event].end();
151 for (i=callbacks[event].begin(); i != ie; i++)
155 /// add a new connection to the server
156 unsigned int server::add_connection(server_connection* newconn)
158 unsigned int cid=next_id++;
159 newconn->set_id(cid);
160 newconn->set_server(this);
161 connections[cid]=newconn;
163 // add all callbacks except new_connection
164 for(int e=connection_closed; e != __events_end; e++)
166 std::list<boost::function<void (unsigned int)> >::iterator i,ie=callbacks[e].end();
167 for (i=callbacks[e].begin(); i != ie; i++)
168 newconn->add_callback(static_cast<callback_event_type>(e),bind(*i,cid));
171 LOGSTREAM(debug,"new connection accepted, id: " << cid);
173 do_callbacks(new_connection,cid);
178 /// activate logging to the given stream. everything above the given level is logged.
179 void server::set_logging(std::ostream *_logstream, log_level_values _log_level)
181 log_level=_log_level;
182 logstream=_logstream;
186 @brief Gets a connection by id
188 @param conn_id Connection ID
190 @retval Pointer to connection object
192 server_connection* server::get_connection(unsigned int conn_id)
194 std::map<unsigned int, server_connection*>::iterator p=connections.find(conn_id);
195 if (p==connections.end())
201 /// check for timeouts, remove closed connections. don't forget to call this from time to time.
202 void server::cleanup()
204 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
205 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
206 i->second->check_timeout();
208 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie;)
210 if (i->second->is_closed() && !i->second->packet_available())
212 // closed and no usable data in buffer -> remove
213 LOGSTREAM(debug,"removing connection " << i->first << " because it is closed and no more data waiting");
216 connections.erase(i);
217 i=connections.begin();
218 ie=connections.end();
225 /** @brief get a complete data packet from any client. The packet is removed from the
227 @param[out] data the data package
228 @param[out] conn_id the connection id we got this packet from
229 @retval true if packet found
231 bool server::get_packet(std::string& data, unsigned int& conn_id)
233 // todo: this is somehow unfair: the first connections in the map get checked more
234 // often than the others and can thus block them out
236 std::map<unsigned int, server_connection*>::iterator ie=connections.end();
237 for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
238 if (i->second->get_packet(data))
240 LOGSTREAM(debug,"got packet (" << data.size() << " bytes) from connection " << i->first);
249 /// get pointer to logging stream, returns NULL if no logging needed
250 std::ostream* server::get_logstream(log_level_values level)
252 if (logstream && log_level >= level)