blob: 0da339cac036eb5fbb49e7c996360b748b140537 [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"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060011#include "core/logger.hpp"
Giulio Grassi624f6c62014-02-18 19:42:14 +010012
13namespace nfd {
14
Davide Pesaventod8d4d982014-03-21 18:47:58 +010015template <class Protocol>
Giulio Grassi624f6c62014-02-18 19:42:14 +010016class DatagramFace : public Face
17{
18public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010019 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070020
21 /** \brief Construct datagram face
22 *
Alexander Afanasyev355c0662014-03-20 18:08:17 -070023 * \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 */
Junxiao Shi79494162014-04-02 18:25:11 -070027 DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
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();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060033
Giulio Grassi624f6c62014-02-18 19:42:14 +010034 // from Face
35 virtual void
36 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060037
Giulio Grassi624f6c62014-02-18 19:42:14 +010038 virtual void
39 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060040
Giulio Grassi624f6c62014-02-18 19:42:14 +010041 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();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060057
Giulio Grassi69871f02014-03-09 16:14:44 +010058 bool
59 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070060
61 void
62 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060063
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);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060072
Giulio Grassi624f6c62014-02-18 19:42:14 +010073 void
74 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060075
Giulio Grassi624f6c62014-02-18 19:42:14 +010076protected:
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
Junxiao Shi79494162014-04-02 18:25:11 -070087DatagramFace<T>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
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)
Junxiao Shi79494162014-04-02 18:25:11 -070090 : Face(remoteUri, localUri)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000091 , 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}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600104
Giulio Grassi624f6c62014-02-18 19:42:14 +0100105template <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()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600113
Giulio Grassi624f6c62014-02-18 19:42:14 +0100114 // anything else should be done here?
115}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600116
Giulio Grassi624f6c62014-02-18 19:42:14 +0100117template <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()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600125
Giulio Grassi624f6c62014-02-18 19:42:14 +0100126 // 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;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600137
Giulio Grassi624f6c62014-02-18 19:42:14 +0100138 if (!m_socket->is_open())
139 {
140 onFail("Tunnel closed");
141 return;
142 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600143
Giulio Grassi624f6c62014-02-18 19:42:14 +0100144 NFD_LOG_WARN("[id:" << this->getId()
145 << ",endpoint:" << m_socket->local_endpoint()
146 << "] Send operation failed, closing socket: "
147 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600148
Giulio Grassi624f6c62014-02-18 19:42:14 +0100149 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600150
Giulio Grassi624f6c62014-02-18 19:42:14 +0100151 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 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600162
Giulio Grassi624f6c62014-02-18 19:42:14 +0100163 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}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600168
Giulio Grassi624f6c62014-02-18 19:42:14 +0100169template <class T>
170inline void
171DatagramFace<T>::close()
172{
173 if (!m_socket->is_open())
174 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600175
Giulio Grassi624f6c62014-02-18 19:42:14 +0100176 NFD_LOG_INFO("[id:" << this->getId()
177 << ",endpoint:" << m_socket->local_endpoint()
178 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600179
Giulio Grassi624f6c62014-02-18 19:42:14 +0100180 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
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700236 Block element;
237 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
238 if (!isOk)
239 {
240 NFD_LOG_WARN("[id:" << this->getId()
241 << ",endpoint:" << m_socket->local_endpoint()
242 << "] Failed to parse incoming packet");
243 // This message won't extend the face lifetime
244 return;
245 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100246
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700247 if (element.size() != nBytesReceived)
248 {
249 NFD_LOG_WARN("[id:" << this->getId()
250 << ",endpoint:" << m_socket->local_endpoint()
251 << "] Received datagram size and decoded "
252 << "element size don't match");
253 // This message won't extend the face lifetime
254 return;
255 }
256
257 if (!this->decodeAndDispatchInput(element))
258 {
259 NFD_LOG_WARN("[id:" << this->getId()
260 << ",endpoint:" << m_socket->local_endpoint()
261 << "] Received unrecognized block of type ["
262 << element.type() << "]");
263 // This message won't extend the face lifetime
264 return;
265 }
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}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600276
Giulio Grassi624f6c62014-02-18 19:42:14 +0100277template <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();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600283
Giulio Grassi624f6c62014-02-18 19:42:14 +0100284 // 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
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600289
Giulio Grassi624f6c62014-02-18 19:42:14 +0100290 // 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