blob: f4f9a18f031f631ec3d13cd5931197ae1a29032c [file] [log] [blame]
Giulio Grassi624f6c62014-02-18 19:42:14 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#ifndef NFD_FACE_DATAGRAM_FACE_HPP
8#define NFD_FACE_DATAGRAM_FACE_HPP
9
10#include "face.hpp"
11
12namespace nfd {
13
14template <class T>
15class DatagramFace : public Face
16{
17public:
18 typedef T protocol;
19
20 explicit
21 DatagramFace(const shared_ptr<typename protocol::socket>& socket);
22
23 virtual
24 ~DatagramFace();
25
26 // from Face
27 virtual void
28 sendInterest(const Interest& interest);
29
30 virtual void
31 sendData(const Data& data);
32
33 virtual void
34 close();
35
36 void
37 handleSend(const boost::system::error_code& error,
38 const Block& wire);
39
40 void
41 handleReceive(const boost::system::error_code& error,
42 size_t nBytesReceived);
43
44protected:
45
46 void
47 receiveDatagram(const uint8_t* buffer,
48 size_t nBytesReceived,
49 const boost::system::error_code& error);
50
51 void
52 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
53
54 void
55 closeSocket();
56
57protected:
58 shared_ptr<typename protocol::socket> m_socket;
59 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
60
61 NFD_LOG_INCLASS_DECLARE();
62
63};
64
65template <class T>
66inline
67DatagramFace<T>::DatagramFace(const shared_ptr<typename DatagramFace::protocol::socket>& socket)
68 : m_socket(socket)
69{
70 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
71 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
72}
73
74template <class T>
75inline
76DatagramFace<T>::~DatagramFace()
77{
78}
79
80template <class T>
81inline void
82DatagramFace<T>::sendInterest(const Interest& interest)
83{
84 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
85 interest.wireEncode().size()),
86 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
87
88 // anything else should be done here?
89}
90
91template <class T>
92inline void
93DatagramFace<T>::sendData(const Data& data)
94{
95 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
96 data.wireEncode().size()),
97 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
98
99 // anything else should be done here?
100}
101
102template <class T>
103inline void
104DatagramFace<T>::handleSend(const boost::system::error_code& error,
105 const Block& wire)
106{
107 if (error != 0) {
108 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
109 return;
110
111 if (!m_socket->is_open())
112 {
113 onFail("Tunnel closed");
114 return;
115 }
116
117 NFD_LOG_WARN("[id:" << this->getId()
118 << ",endpoint:" << m_socket->local_endpoint()
119 << "] Send operation failed, closing socket: "
120 << error.category().message(error.value()));
121
122 closeSocket();
123
124 if (error == boost::asio::error::eof)
125 {
126 onFail("Tunnel closed");
127 }
128 else
129 {
130 onFail("Send operation failed, closing socket: " +
131 error.category().message(error.value()));
132 }
133 return;
134 }
135
136 NFD_LOG_TRACE("[id:" << this->getId()
137 << ",endpoint:" << m_socket->local_endpoint()
138 << "] Successfully sent: " << wire.size() << " bytes");
139 // do nothing (needed to retain validity of wire memory block
140}
141
142template <class T>
143inline void
144DatagramFace<T>::close()
145{
146 if (!m_socket->is_open())
147 return;
148
149 NFD_LOG_INFO("[id:" << this->getId()
150 << ",endpoint:" << m_socket->local_endpoint()
151 << "] Close tunnel");
152
153 closeSocket();
154 onFail("Close tunnel");
155}
156
157template <class T>
158inline void
159DatagramFace<T>::handleReceive(const boost::system::error_code& error,
160 size_t nBytesReceived)
161{
162 receiveDatagram(m_inputBuffer, nBytesReceived, error);
163 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
164 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
165}
166
167template <class T>
168inline void
169DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
170 size_t nBytesReceived,
171 const boost::system::error_code& error)
172{
173 if (error != 0 || nBytesReceived == 0) {
174 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
175 return;
176
177 // this should be unnecessary, but just in case
178 if (!m_socket->is_open())
179 {
180 onFail("Tunnel closed");
181 return;
182 }
183
184 NFD_LOG_WARN("[id:" << this->getId()
185 << ",endpoint:" << m_socket->local_endpoint()
186 << "] Receive operation failed: "
187 << error.category().message(error.value()));
188
189 closeSocket();
190
191 if (error == boost::asio::error::eof)
192 {
193 onFail("Tunnel closed");
194 }
195 else
196 {
197 onFail("Receive operation failed, closing socket: " +
198 error.category().message(error.value()));
199 }
200 return;
201 }
202
203 NFD_LOG_TRACE("[id:" << this->getId()
204 << ",endpoint:" << m_socket->local_endpoint()
205 << "] Received: " << nBytesReceived << " bytes");
206
207 /// @todo Eliminate reliance on exceptions in this path
208 try {
209 Block element(buffer, nBytesReceived);
210
211 if (element.size() != nBytesReceived)
212 {
213 NFD_LOG_WARN("[id:" << this->getId()
214 << ",endpoint:" << m_socket->local_endpoint()
215 << "] Received datagram size and decoded "
216 << "element size don't match");
217 /// @todo this message should not extend the face lifetime
218 return;
219 }
220 if (!this->decodeAndDispatchInput(element))
221 {
222 NFD_LOG_WARN("[id:" << this->getId()
223 << ",endpoint:" << m_socket->local_endpoint()
224 << "] Received unrecognized block of type ["
225 << element.type() << "]");
226 // ignore unknown packet and proceed
227 /// @todo this message should not extend the face lifetime
228 return;
229 }
230 }
231 catch(const tlv::Error& e) {
232 NFD_LOG_WARN("[id:" << this->getId()
233 << ",endpoint:" << m_socket->local_endpoint()
234 << "] Received input is invalid");
235 /// @todo this message should not extend the face lifetime
236 return;
237 }
238}
239
240
241template <class T>
242inline void
243DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
244{
245}
246
247template <class T>
248inline void
249DatagramFace<T>::closeSocket()
250{
251 boost::asio::io_service& io = m_socket->get_io_service();
252
253 // use the non-throwing variants and ignore errors, if any
254 boost::system::error_code error;
255 m_socket->shutdown(protocol::socket::shutdown_both, error);
256 m_socket->close(error);
257 // after this, handlers will be called with an error code
258
259 // ensure that the Face object is alive at least until all pending
260 // handlers are dispatched
261 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
262 this, this->shared_from_this()));
263}
264
265} // namespace nfd
266
267#endif // NFD_FACE_DATAGRAM_FACE_HPP