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.
28 #include <netinet/in.h>
30 #include "connection.hxx"
35 connection::~connection()
37 // Run close() manually since it's a virtual function
38 // and we are in the destructor.
42 do_callbacks(connection_closed);
45 do_callbacks(connection_deleted);
48 void connection::close()
53 do_callbacks(connection_closed);
57 /// get the number of bytes being available as next complete packet
58 connection::packet_size_indicator connection::bytes_available()
60 // no size information -> no packet
61 if (buffer.size() < sizeof(packet_size_indicator))
64 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
66 // enough data for one packet in buffer?
67 if (buffer.size() < sizeof(packet_size_indicator)+psize)
70 // ok, full packet there
74 /** @brief read a complete data packet from the buffer. The packet is removed from the
76 @param[out] data the data package
77 @retval true if packet found
79 bool connection::get_packet(std::string& data)
81 packet_size_indicator psize;
83 if ((psize=bytes_available()))
85 data.assign(buffer,sizeof(packet_size_indicator),psize);
86 buffer.erase(0,sizeof(packet_size_indicator)+psize);
93 /** @brief get (maybe incomplete) data of the next packet from the buffer. Does not remove the data
94 from the connection buffer.
95 @param[out] data the data package
96 @retval full size of the packet when it will be complete
98 unsigned int connection::peek_packet(std::string& data)
100 // no size information -> no packet
101 if (buffer.size() < sizeof(packet_size_indicator))
104 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
106 // not the full data available?
107 packet_size_indicator currsize=psize;
108 if (buffer.size() < currsize+sizeof(packet_size_indicator))
109 currsize=buffer.size()-sizeof(packet_size_indicator);
111 data.assign(buffer,sizeof(packet_size_indicator),currsize);
116 /// remove all data from buffer that is not a complete packet
117 void connection::remove_incomplete_packets()
119 std::string::size_type p=0;
120 std::string::size_type end=buffer.size();
124 // not enough space for size information -> no packet
125 if (p+sizeof(packet_size_indicator) > end)
128 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data()+p)));
130 if (p+sizeof(packet_size_indicator)+psize > end)
137 // move p to where the next packet will start
138 p+=sizeof(packet_size_indicator)+psize;
144 // incomplete packets there, remove them
149 /// send a blob to the peer
150 void connection::write(const std::string& data)
152 // prepend packet size to data
153 packet_size_indicator psize=htonl(data.size());
154 std::string send_data(data);
155 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
157 real_write(send_data);
160 /** @brief add a callback
162 @param event event the function will be called at
163 @param func functor (see boost function) that will be called
165 @note use boost::bind to bind to member functions and parameters like this:
166 17 is a fixed parameter that is always added to the call
167 c.add_callback(connection_closed,bind(&my_class::func_to_call_back, boost::ref(*this), 17));
169 void connection::add_callback(callback_event_type event, const boost::function<void ()>& func)
171 callbacks[event].push_back(func);
174 /** @brief an event has occured, execute the callbacks that are registered for this event
176 @param event event type that has occured
178 void connection::do_callbacks(callback_event_type event)
180 std::list<boost::function<void ()> >::iterator i,ie=callbacks[event].end();
181 for (i=callbacks[event].begin(); i != ie; i++)
185 /** @brief get the callbacks in place for one event
187 @param event event the callbacks should be registered for
188 @return std::list of functors (boost::function) with the callbacks
190 @note if you want to get the callbacks for all events, loop from 0 to __events_end
192 std::list<boost::function<void ()> > connection::get_callback_list(callback_event_type event)
194 return callbacks[event];
197 /** @brief reopen a already closed connection, removes incomplete packets from the buffer
199 @note Only call when the connection is closed.
201 @note Justs cares about the data of connection, reconnecting has to be
202 done in a derived class.
204 void connection::reopen()
207 throw std::logic_error("connection::reopen() called with connection still open");
211 // incomplete buffer data is worthless with a new connection
212 remove_incomplete_packets();
214 do_callbacks(new_connection);