blob: 8050164f6950bf96ae30fa1b61b04da4d016748d [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
Davide Pesaventod8d4d982014-03-21 18:47:58 +010014template <class Protocol>
Giulio Grassi624f6c62014-02-18 19:42:14 +010015class DatagramFace : public Face
16{
17public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010018 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070019
20 /** \brief Construct datagram face
21 *
22 * \param uri FaceUri for the face
23 * \param socket Protocol-specific socket for the created face
24 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010025 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070026 */
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000027 DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010028 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070029 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010030
31 virtual
32 ~DatagramFace();
33
34 // from Face
35 virtual void
36 sendInterest(const Interest& interest);
37
38 virtual void
39 sendData(const Data& data);
40
41 virtual void
42 close();
43
44 void
45 handleSend(const boost::system::error_code& error,
46 const Block& wire);
47
48 void
49 handleReceive(const boost::system::error_code& error,
50 size_t nBytesReceived);
51
Giulio Grassi69871f02014-03-09 16:14:44 +010052 /**
53 * \brief Set m_hasBeenUsedRecently to false
54 */
55 void
56 resetRecentUsage();
57
58 bool
59 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070060
61 void
62 setOnDemand(bool isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +010063
Giulio Grassi624f6c62014-02-18 19:42:14 +010064protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010065 void
66 receiveDatagram(const uint8_t* buffer,
67 size_t nBytesReceived,
68 const boost::system::error_code& error);
69
70 void
71 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
72
73 void
74 closeSocket();
75
76protected:
77 shared_ptr<typename protocol::socket> m_socket;
78 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
79
Giulio Grassi69871f02014-03-09 16:14:44 +010080 bool m_hasBeenUsedRecently;
81
Giulio Grassi624f6c62014-02-18 19:42:14 +010082 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +010083};
84
85template <class T>
86inline
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000087DatagramFace<T>::DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010088 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070089 bool isOnDemand)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000090 : Face(uri)
91 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +010092{
Alexander Afanasyev355c0662014-03-20 18:08:17 -070093 setOnDemand(isOnDemand);
94
Giulio Grassi624f6c62014-02-18 19:42:14 +010095 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
96 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
97}
98
99template <class T>
100inline
101DatagramFace<T>::~DatagramFace()
102{
103}
104
105template <class T>
106inline void
107DatagramFace<T>::sendInterest(const Interest& interest)
108{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000109 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100110 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
111 interest.wireEncode().size()),
112 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
113
114 // anything else should be done here?
115}
116
117template <class T>
118inline void
119DatagramFace<T>::sendData(const Data& data)
120{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000121 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100122 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
123 data.wireEncode().size()),
124 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
125
126 // anything else should be done here?
127}
128
129template <class T>
130inline void
131DatagramFace<T>::handleSend(const boost::system::error_code& error,
132 const Block& wire)
133{
134 if (error != 0) {
135 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
136 return;
137
138 if (!m_socket->is_open())
139 {
140 onFail("Tunnel closed");
141 return;
142 }
143
144 NFD_LOG_WARN("[id:" << this->getId()
145 << ",endpoint:" << m_socket->local_endpoint()
146 << "] Send operation failed, closing socket: "
147 << error.category().message(error.value()));
148
149 closeSocket();
150
151 if (error == boost::asio::error::eof)
152 {
153 onFail("Tunnel closed");
154 }
155 else
156 {
157 onFail("Send operation failed, closing socket: " +
158 error.category().message(error.value()));
159 }
160 return;
161 }
162
163 NFD_LOG_TRACE("[id:" << this->getId()
164 << ",endpoint:" << m_socket->local_endpoint()
165 << "] Successfully sent: " << wire.size() << " bytes");
166 // do nothing (needed to retain validity of wire memory block
167}
168
169template <class T>
170inline void
171DatagramFace<T>::close()
172{
173 if (!m_socket->is_open())
174 return;
175
176 NFD_LOG_INFO("[id:" << this->getId()
177 << ",endpoint:" << m_socket->local_endpoint()
178 << "] Close tunnel");
179
180 closeSocket();
181 onFail("Close tunnel");
182}
183
184template <class T>
185inline void
186DatagramFace<T>::handleReceive(const boost::system::error_code& error,
187 size_t nBytesReceived)
188{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000189 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100190 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100191 if (m_socket->is_open())
192 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
193 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100194}
195
196template <class T>
197inline void
198DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
199 size_t nBytesReceived,
200 const boost::system::error_code& error)
201{
202 if (error != 0 || nBytesReceived == 0) {
203 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
204 return;
205
206 // this should be unnecessary, but just in case
207 if (!m_socket->is_open())
208 {
209 onFail("Tunnel closed");
210 return;
211 }
212
213 NFD_LOG_WARN("[id:" << this->getId()
214 << ",endpoint:" << m_socket->local_endpoint()
215 << "] Receive operation failed: "
216 << error.category().message(error.value()));
217
218 closeSocket();
219
220 if (error == boost::asio::error::eof)
221 {
222 onFail("Tunnel closed");
223 }
224 else
225 {
226 onFail("Receive operation failed, closing socket: " +
227 error.category().message(error.value()));
228 }
229 return;
230 }
231
232 NFD_LOG_TRACE("[id:" << this->getId()
233 << ",endpoint:" << m_socket->local_endpoint()
234 << "] Received: " << nBytesReceived << " bytes");
235
236 /// @todo Eliminate reliance on exceptions in this path
237 try {
238 Block element(buffer, nBytesReceived);
239
240 if (element.size() != nBytesReceived)
241 {
242 NFD_LOG_WARN("[id:" << this->getId()
243 << ",endpoint:" << m_socket->local_endpoint()
244 << "] Received datagram size and decoded "
245 << "element size don't match");
Giulio Grassi69871f02014-03-09 16:14:44 +0100246 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100247 return;
248 }
249 if (!this->decodeAndDispatchInput(element))
250 {
251 NFD_LOG_WARN("[id:" << this->getId()
252 << ",endpoint:" << m_socket->local_endpoint()
253 << "] Received unrecognized block of type ["
254 << element.type() << "]");
255 // ignore unknown packet and proceed
Giulio Grassi69871f02014-03-09 16:14:44 +0100256 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100257 return;
258 }
259 }
260 catch(const tlv::Error& e) {
261 NFD_LOG_WARN("[id:" << this->getId()
262 << ",endpoint:" << m_socket->local_endpoint()
263 << "] Received input is invalid");
Giulio Grassi69871f02014-03-09 16:14:44 +0100264 // This message won't extend the face lifetime
Giulio Grassi624f6c62014-02-18 19:42:14 +0100265 return;
266 }
Giulio Grassi69871f02014-03-09 16:14:44 +0100267 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100268}
269
270
271template <class T>
272inline void
273DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
274{
275}
276
277template <class T>
278inline void
279DatagramFace<T>::closeSocket()
280{
Giulio Grassi69871f02014-03-09 16:14:44 +0100281 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100282 boost::asio::io_service& io = m_socket->get_io_service();
283
284 // use the non-throwing variants and ignore errors, if any
285 boost::system::error_code error;
286 m_socket->shutdown(protocol::socket::shutdown_both, error);
287 m_socket->close(error);
288 // after this, handlers will be called with an error code
289
290 // ensure that the Face object is alive at least until all pending
291 // handlers are dispatched
292 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
293 this, this->shared_from_this()));
294}
295
Giulio Grassi69871f02014-03-09 16:14:44 +0100296template <class T>
297inline void
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700298DatagramFace<T>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100299{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700300 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100301}
302
303template <class T>
304inline void
305DatagramFace<T>::resetRecentUsage()
306{
307 m_hasBeenUsedRecently = false;
308}
309
310template <class T>
311inline bool
312DatagramFace<T>::hasBeenUsedRecently() const
313{
314 return m_hasBeenUsedRecently;
315}
316
Giulio Grassi624f6c62014-02-18 19:42:14 +0100317} // namespace nfd
318
319#endif // NFD_FACE_DATAGRAM_FACE_HPP