blob: 4b75a0e17a3f0ea819b9cfdd31fdef4a9b1c1ec1 [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
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000020 DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010021 const shared_ptr<typename protocol::socket>& socket,
22 bool isPermanent);
Giulio Grassi624f6c62014-02-18 19:42:14 +010023
24 virtual
25 ~DatagramFace();
26
27 // from Face
28 virtual void
29 sendInterest(const Interest& interest);
30
31 virtual void
32 sendData(const Data& data);
33
34 virtual void
35 close();
36
37 void
38 handleSend(const boost::system::error_code& error,
39 const Block& wire);
40
41 void
42 handleReceive(const boost::system::error_code& error,
43 size_t nBytesReceived);
44
Giulio Grassi69871f02014-03-09 16:14:44 +010045 void
46 setPermanent(bool isPermanent);
47
48 bool
49 isPermanent() const;
50
51 /**
52 * \brief Set m_hasBeenUsedRecently to false
53 */
54 void
55 resetRecentUsage();
56
57 bool
58 hasBeenUsedRecently() const;
59
Giulio Grassi624f6c62014-02-18 19:42:14 +010060protected:
61
62 void
63 receiveDatagram(const uint8_t* buffer,
64 size_t nBytesReceived,
65 const boost::system::error_code& error);
66
67 void
68 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
69
70 void
71 closeSocket();
72
73protected:
74 shared_ptr<typename protocol::socket> m_socket;
75 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
76
Giulio Grassi69871f02014-03-09 16:14:44 +010077 /**
78 * If false, the face can be closed after it remains unused for a certain
79 * amount of time
80 */
81 bool m_isPermanent;
82
83 bool m_hasBeenUsedRecently;
84
Giulio Grassi624f6c62014-02-18 19:42:14 +010085 NFD_LOG_INCLASS_DECLARE();
86
87};
88
89template <class T>
90inline
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000091DatagramFace<T>::DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010092 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
93 bool isPermanent)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000094 : Face(uri)
95 , m_socket(socket)
Giulio Grassi69871f02014-03-09 16:14:44 +010096 , m_isPermanent(isPermanent)
Giulio Grassi624f6c62014-02-18 19:42:14 +010097{
98 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
99 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
100}
101
102template <class T>
103inline
104DatagramFace<T>::~DatagramFace()
105{
106}
107
108template <class T>
109inline void
110DatagramFace<T>::sendInterest(const Interest& interest)
111{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000112 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100113 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
114 interest.wireEncode().size()),
115 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
116
117 // anything else should be done here?
118}
119
120template <class T>
121inline void
122DatagramFace<T>::sendData(const Data& data)
123{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000124 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100125 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
126 data.wireEncode().size()),
127 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
128
129 // anything else should be done here?
130}
131
132template <class T>
133inline void
134DatagramFace<T>::handleSend(const boost::system::error_code& error,
135 const Block& wire)
136{
137 if (error != 0) {
138 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
139 return;
140
141 if (!m_socket->is_open())
142 {
143 onFail("Tunnel closed");
144 return;
145 }
146
147 NFD_LOG_WARN("[id:" << this->getId()
148 << ",endpoint:" << m_socket->local_endpoint()
149 << "] Send operation failed, closing socket: "
150 << error.category().message(error.value()));
151
152 closeSocket();
153
154 if (error == boost::asio::error::eof)
155 {
156 onFail("Tunnel closed");
157 }
158 else
159 {
160 onFail("Send operation failed, closing socket: " +
161 error.category().message(error.value()));
162 }
163 return;
164 }
165
166 NFD_LOG_TRACE("[id:" << this->getId()
167 << ",endpoint:" << m_socket->local_endpoint()
168 << "] Successfully sent: " << wire.size() << " bytes");
169 // do nothing (needed to retain validity of wire memory block
170}
171
172template <class T>
173inline void
174DatagramFace<T>::close()
175{
176 if (!m_socket->is_open())
177 return;
178
179 NFD_LOG_INFO("[id:" << this->getId()
180 << ",endpoint:" << m_socket->local_endpoint()
181 << "] Close tunnel");
182
183 closeSocket();
184 onFail("Close tunnel");
185}
186
187template <class T>
188inline void
189DatagramFace<T>::handleReceive(const boost::system::error_code& error,
190 size_t nBytesReceived)
191{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000192 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100193 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100194 if (m_socket->is_open())
195 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
196 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100197}
198
199template <class T>
200inline void
201DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
202 size_t nBytesReceived,
203 const boost::system::error_code& error)
204{
205 if (error != 0 || nBytesReceived == 0) {
206 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
207 return;
208
209 // this should be unnecessary, but just in case
210 if (!m_socket->is_open())
211 {
212 onFail("Tunnel closed");
213 return;
214 }
215
216 NFD_LOG_WARN("[id:" << this->getId()
217 << ",endpoint:" << m_socket->local_endpoint()
218 << "] Receive operation failed: "
219 << error.category().message(error.value()));
220
221 closeSocket();
222
223 if (error == boost::asio::error::eof)
224 {
225 onFail("Tunnel closed");
226 }
227 else
228 {
229 onFail("Receive operation failed, closing socket: " +
230 error.category().message(error.value()));
231 }
232 return;
233 }
234
235 NFD_LOG_TRACE("[id:" << this->getId()
236 << ",endpoint:" << m_socket->local_endpoint()
237 << "] Received: " << nBytesReceived << " bytes");
238
239 /// @todo Eliminate reliance on exceptions in this path
240 try {
241 Block element(buffer, nBytesReceived);
242
243 if (element.size() != nBytesReceived)
244 {
245 NFD_LOG_WARN("[id:" << this->getId()
246 << ",endpoint:" << m_socket->local_endpoint()
247 << "] Received datagram size and decoded "
248 << "element size don't match");
Giulio Grassi69871f02014-03-09 16:14:44 +0100249 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100250 return;
251 }
252 if (!this->decodeAndDispatchInput(element))
253 {
254 NFD_LOG_WARN("[id:" << this->getId()
255 << ",endpoint:" << m_socket->local_endpoint()
256 << "] Received unrecognized block of type ["
257 << element.type() << "]");
258 // ignore unknown packet and proceed
Giulio Grassi69871f02014-03-09 16:14:44 +0100259 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100260 return;
261 }
262 }
263 catch(const tlv::Error& e) {
264 NFD_LOG_WARN("[id:" << this->getId()
265 << ",endpoint:" << m_socket->local_endpoint()
266 << "] Received input is invalid");
Giulio Grassi69871f02014-03-09 16:14:44 +0100267 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100268 return;
269 }
Giulio Grassi69871f02014-03-09 16:14:44 +0100270 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100271}
272
273
274template <class T>
275inline void
276DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
277{
278}
279
280template <class T>
281inline void
282DatagramFace<T>::closeSocket()
283{
Giulio Grassi69871f02014-03-09 16:14:44 +0100284 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100285 boost::asio::io_service& io = m_socket->get_io_service();
286
287 // use the non-throwing variants and ignore errors, if any
288 boost::system::error_code error;
289 m_socket->shutdown(protocol::socket::shutdown_both, error);
290 m_socket->close(error);
291 // after this, handlers will be called with an error code
292
293 // ensure that the Face object is alive at least until all pending
294 // handlers are dispatched
295 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
296 this, this->shared_from_this()));
297}
298
Giulio Grassi69871f02014-03-09 16:14:44 +0100299template <class T>
300inline void
301DatagramFace<T>::setPermanent(bool isPermanent)
302{
303 m_isPermanent = isPermanent;
304}
305
306template <class T>
307inline bool
308DatagramFace<T>::isPermanent() const
309{
310 return m_isPermanent;
311}
312
313template <class T>
314inline void
315DatagramFace<T>::resetRecentUsage()
316{
317 m_hasBeenUsedRecently = false;
318}
319
320template <class T>
321inline bool
322DatagramFace<T>::hasBeenUsedRecently() const
323{
324 return m_hasBeenUsedRecently;
325}
326
Giulio Grassi624f6c62014-02-18 19:42:14 +0100327} // namespace nfd
328
329#endif // NFD_FACE_DATAGRAM_FACE_HPP