libt2n: (tomj) fix uninitialized variable "result_type" in result_container
[libt2n] / src / connection.cpp
CommitLineData
a11e19b7
GE
1/***************************************************************************
2 * Copyright (C) 2006 by Gerd v. Egidy *
3 * gve@intra2net.com *
4 * *
5 * This library is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License version *
7 * 2.1 as published by the Free Software Foundation. *
8 * *
9 * This library is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19
20#include <string>
21#include <sstream>
a7170401 22#include <iostream>
af84dfb5 23#include <stdexcept>
a11e19b7 24
8104c8f7
GE
25#include <netinet/in.h>
26
a11e19b7
GE
27#include "connection.hxx"
28
29namespace libt2n
30{
31
a64066eb
GE
32connection::~connection()
33{
34 // we want the connection_closed callbacks to be called before
238ad35f 35 // FIXME: Functios is virtual
a64066eb
GE
36 close();
37
38 do_callbacks(connection_deleted);
39}
40
41void connection::close()
42{
43 if (!is_closed())
44 {
45 closed=true;
46 do_callbacks(connection_closed);
47 }
48}
49
487afb79 50/// get the number of bytes being available as next complete packet
a11e19b7
GE
51connection::packet_size_indicator connection::bytes_available()
52{
a11e19b7 53 // no size information -> no packet
8104c8f7 54 if (buffer.size() < sizeof(packet_size_indicator))
644c4d26 55 return 0;
a11e19b7 56
8104c8f7 57 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
a11e19b7
GE
58
59 // enough data for one packet in buffer?
8104c8f7 60 if (buffer.size() < sizeof(packet_size_indicator)+psize)
644c4d26 61 return 0;
a11e19b7
GE
62
63 // ok, full packet there
644c4d26 64 return psize;
a11e19b7
GE
65}
66
94247295
GE
67/** @brief read a complete data packet from the buffer. The packet is removed from the
68 connection buffer.
69 @param[out] data the data package
70 @retval true if packet found
71*/
a11e19b7
GE
72bool connection::get_packet(std::string& data)
73{
74 packet_size_indicator psize;
75
76 if ((psize=bytes_available()))
77 {
8104c8f7
GE
78 data.assign(buffer,sizeof(packet_size_indicator),psize);
79 buffer.erase(0,sizeof(packet_size_indicator)+psize);
a11e19b7
GE
80 return true;
81 }
82 else
83 return false;
84}
85
b2ba0928
GE
86/** @brief get (maybe incomplete) data of the next packet from the buffer. Does not remove the data
87 from the connection buffer.
88 @param[out] data the data package
89 @retval full size of the packet when it will be complete
90*/
91unsigned int connection::peek_packet(std::string& data)
92{
93 // no size information -> no packet
94 if (buffer.size() < sizeof(packet_size_indicator))
95 return 0;
96
97 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
98
99 // not the full data available?
100 packet_size_indicator currsize=psize;
101 if (buffer.size() < currsize+sizeof(packet_size_indicator))
102 currsize=buffer.size()-sizeof(packet_size_indicator);
103
104 data.assign(buffer,sizeof(packet_size_indicator),currsize);
105
106 return psize;
107}
108
af84dfb5
GE
109/// remove all data from buffer that is not a complete packet
110void connection::remove_incomplete_packets()
111{
112 std::string::size_type p=0;
113 std::string::size_type end=buffer.size();
114
115 while (p < end)
116 {
117 // not enough space for size information -> no packet
118 if (p+sizeof(packet_size_indicator) > end)
119 break;
120
121 packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data()+p)));
122
123 if (p+sizeof(packet_size_indicator)+psize > end)
124 {
125 // incomplete packet
126 break;
127 }
128 else
129 {
130 // move p to where the next packet will start
131 p+=sizeof(packet_size_indicator)+psize;
132 }
133 }
134
135 if (p < end)
136 {
137 // incomplete packets there, remove them
138 buffer.erase(p);
139 }
140}
141
94247295 142/// send a blob to the peer
a11e19b7
GE
143void connection::write(const std::string& data)
144{
145 // prepend packet size to data
8104c8f7 146 packet_size_indicator psize=htonl(data.size());
a11e19b7 147 std::string send_data(data);
644c4d26 148 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
a11e19b7
GE
149
150 real_write(send_data);
151}
152
a64066eb
GE
153/** @brief add a callback
154
155 @param event event the function will be called at
156 @param func functor (see boost function) that will be called
157
158 @note use boost::bind to bind to member functions and parameters like this:
159 17 is a fixed parameter that is always added to the call
160 c.add_callback(connection_closed,bind(&my_class::func_to_call_back, boost::ref(*this), 17));
161*/
162void connection::add_callback(callback_event_type event, const boost::function<void ()>& func)
163{
a64066eb
GE
164 callbacks[event].push_back(func);
165}
166
167/** @brief an event has occured, execute the callbacks that are registered for this event
168
169 @param event event type that has occured
170*/
171void connection::do_callbacks(callback_event_type event)
172{
173 std::list<boost::function<void ()> >::iterator i,ie=callbacks[event].end();
174 for (i=callbacks[event].begin(); i != ie; i++)
175 (*i)();
176}
177
178/** @brief get the callbacks in place for one event
179
180 @param event event the callbacks should be registered for
181 @return std::list of functors (boost::function) with the callbacks
182
183 @note if you want to get the callbacks for all events, loop from 0 to __events_end
184*/
185std::list<boost::function<void ()> > connection::get_callback_list(callback_event_type event)
186{
187 return callbacks[event];
188}
189
af84dfb5
GE
190/** @brief reopen a already closed connection, removes incomplete packets from the buffer
191
192 @note Only call when the connection is closed.
193
194 @note Justs cares about the data of connection, reconnecting has to be
195 done in a derived class.
196*/
197void connection::reopen()
198{
199 if (!is_closed())
200 throw std::logic_error("connection::reopen() called with connection still open");
201
202 closed=false;
203
204 // incomplete buffer data is worthless with a new connection
205 remove_incomplete_packets();
206
207 do_callbacks(new_connection);
208}
a64066eb 209
a11e19b7 210}