libt2n: (gerd) some refactoring, documentation improvement
[libt2n] / src / connection.cpp
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>
22 #include <iostream>
23
24 #include <netinet/in.h>
25
26 #include "connection.hxx"
27
28 namespace libt2n
29 {
30
31 connection::~connection()
32 {
33     // we want the connection_closed callbacks to be called before
34     close();
35
36     do_callbacks(connection_deleted);
37 }
38
39 void connection::close()
40 {
41     if (!is_closed())
42     {
43         closed=true;
44         do_callbacks(connection_closed);
45     }
46 }
47
48 connection::packet_size_indicator connection::bytes_available()
49 {
50     // no size information -> no packet
51     if (buffer.size() < sizeof(packet_size_indicator))
52         return 0;
53
54     packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
55
56     // enough data for one packet in buffer?
57     if (buffer.size() < sizeof(packet_size_indicator)+psize)
58         return 0;
59
60     // ok, full packet there
61     return psize;
62 }
63
64 /** @brief read a complete data packet from the buffer. The packet is removed from the
65             connection buffer.
66     @param[out] data the data package
67     @retval true if packet found
68 */
69 bool connection::get_packet(std::string& data)
70 {
71     packet_size_indicator psize;
72
73     if ((psize=bytes_available()))
74     {
75         data.assign(buffer,sizeof(packet_size_indicator),psize);
76         buffer.erase(0,sizeof(packet_size_indicator)+psize);
77         return true;
78     }
79     else
80         return false;
81 }
82
83 /** @brief get (maybe incomplete) data of the next packet from the buffer. Does not remove the data
84             from the connection buffer.
85     @param[out] data the data package
86     @retval full size of the packet when it will be complete
87 */
88 unsigned int connection::peek_packet(std::string& data)
89 {
90     // no size information -> no packet
91     if (buffer.size() < sizeof(packet_size_indicator))
92         return 0;
93
94     packet_size_indicator psize=ntohl(*((packet_size_indicator*)(buffer.data())));
95
96     // not the full data available?
97     packet_size_indicator currsize=psize;
98     if (buffer.size() < currsize+sizeof(packet_size_indicator))
99         currsize=buffer.size()-sizeof(packet_size_indicator);
100
101     data.assign(buffer,sizeof(packet_size_indicator),currsize);
102
103     return psize;
104 }
105
106 /// send a blob to the peer
107 void connection::write(const std::string& data)
108 {
109     // prepend packet size to data
110     packet_size_indicator psize=htonl(data.size());
111     std::string send_data(data);
112     send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
113
114     real_write(send_data);
115 }
116
117 /** @brief add a callback
118
119     @param event event the function will be called at
120     @param func functor (see boost function) that will be called
121
122     @note use boost::bind to bind to member functions and parameters like this:
123         17 is a fixed parameter that is always added to the call
124         c.add_callback(connection_closed,bind(&my_class::func_to_call_back, boost::ref(*this), 17));
125 */
126 void connection::add_callback(callback_event_type event, const boost::function<void ()>& func)
127 {
128     if (event == new_connection)
129         throw std::logic_error("new_connection callback not allowed for server_connections");
130
131     callbacks[event].push_back(func);
132 }
133
134 /** @brief an event has occured, execute the callbacks that are registered for this event
135
136     @param event event type that has occured
137 */
138 void connection::do_callbacks(callback_event_type event)
139 {
140     std::list<boost::function<void ()> >::iterator i,ie=callbacks[event].end();
141     for (i=callbacks[event].begin(); i != ie; i++)
142         (*i)();
143 }
144
145 /** @brief get the callbacks in place for one event
146
147     @param event event the callbacks should be registered for
148     @return std::list of functors (boost::function) with the callbacks
149
150     @note if you want to get the callbacks for all events, loop from 0 to __events_end 
151 */
152 std::list<boost::function<void ()> > connection::get_callback_list(callback_event_type event)
153 {
154     return callbacks[event];
155 }
156
157
158 }