blob: f59374f2795bd8583c3de744bb713a2780a1e1ba [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 *
23 * \param uri FaceUri for the face
24 * \param socket Protocol-specific socket for the created face
25 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010026 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070027 */
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000028 DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010029 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070030 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010031
32 virtual
33 ~DatagramFace();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060034
Giulio Grassi624f6c62014-02-18 19:42:14 +010035 // from Face
36 virtual void
37 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060038
Giulio Grassi624f6c62014-02-18 19:42:14 +010039 virtual void
40 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060041
Giulio Grassi624f6c62014-02-18 19:42:14 +010042 virtual void
43 close();
44
45 void
46 handleSend(const boost::system::error_code& error,
47 const Block& wire);
48
49 void
50 handleReceive(const boost::system::error_code& error,
51 size_t nBytesReceived);
52
Giulio Grassi69871f02014-03-09 16:14:44 +010053 /**
54 * \brief Set m_hasBeenUsedRecently to false
55 */
56 void
57 resetRecentUsage();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060058
Giulio Grassi69871f02014-03-09 16:14:44 +010059 bool
60 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070061
62 void
63 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060064
Giulio Grassi624f6c62014-02-18 19:42:14 +010065protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010066 void
67 receiveDatagram(const uint8_t* buffer,
68 size_t nBytesReceived,
69 const boost::system::error_code& error);
70
71 void
72 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060073
Giulio Grassi624f6c62014-02-18 19:42:14 +010074 void
75 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060076
Giulio Grassi624f6c62014-02-18 19:42:14 +010077protected:
78 shared_ptr<typename protocol::socket> m_socket;
79 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
80
Giulio Grassi69871f02014-03-09 16:14:44 +010081 bool m_hasBeenUsedRecently;
82
Giulio Grassi624f6c62014-02-18 19:42:14 +010083 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +010084};
85
86template <class T>
87inline
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000088DatagramFace<T>::DatagramFace(const FaceUri& uri,
Giulio Grassi69871f02014-03-09 16:14:44 +010089 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070090 bool isOnDemand)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000091 : Face(uri)
92 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +010093{
Alexander Afanasyev355c0662014-03-20 18:08:17 -070094 setOnDemand(isOnDemand);
95
Giulio Grassi624f6c62014-02-18 19:42:14 +010096 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
97 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
98}
99
100template <class T>
101inline
102DatagramFace<T>::~DatagramFace()
103{
104}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600105
Giulio Grassi624f6c62014-02-18 19:42:14 +0100106template <class T>
107inline void
108DatagramFace<T>::sendInterest(const Interest& interest)
109{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000110 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100111 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
112 interest.wireEncode().size()),
113 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600114
Giulio Grassi624f6c62014-02-18 19:42:14 +0100115 // anything else should be done here?
116}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600117
Giulio Grassi624f6c62014-02-18 19:42:14 +0100118template <class T>
119inline void
120DatagramFace<T>::sendData(const Data& data)
121{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000122 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100123 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
124 data.wireEncode().size()),
125 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600126
Giulio Grassi624f6c62014-02-18 19:42:14 +0100127 // anything else should be done here?
128}
129
130template <class T>
131inline void
132DatagramFace<T>::handleSend(const boost::system::error_code& error,
133 const Block& wire)
134{
135 if (error != 0) {
136 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
137 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600138
Giulio Grassi624f6c62014-02-18 19:42:14 +0100139 if (!m_socket->is_open())
140 {
141 onFail("Tunnel closed");
142 return;
143 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600144
Giulio Grassi624f6c62014-02-18 19:42:14 +0100145 NFD_LOG_WARN("[id:" << this->getId()
146 << ",endpoint:" << m_socket->local_endpoint()
147 << "] Send operation failed, closing socket: "
148 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600149
Giulio Grassi624f6c62014-02-18 19:42:14 +0100150 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600151
Giulio Grassi624f6c62014-02-18 19:42:14 +0100152 if (error == boost::asio::error::eof)
153 {
154 onFail("Tunnel closed");
155 }
156 else
157 {
158 onFail("Send operation failed, closing socket: " +
159 error.category().message(error.value()));
160 }
161 return;
162 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600163
Giulio Grassi624f6c62014-02-18 19:42:14 +0100164 NFD_LOG_TRACE("[id:" << this->getId()
165 << ",endpoint:" << m_socket->local_endpoint()
166 << "] Successfully sent: " << wire.size() << " bytes");
167 // do nothing (needed to retain validity of wire memory block
168}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600169
Giulio Grassi624f6c62014-02-18 19:42:14 +0100170template <class T>
171inline void
172DatagramFace<T>::close()
173{
174 if (!m_socket->is_open())
175 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600176
Giulio Grassi624f6c62014-02-18 19:42:14 +0100177 NFD_LOG_INFO("[id:" << this->getId()
178 << ",endpoint:" << m_socket->local_endpoint()
179 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600180
Giulio Grassi624f6c62014-02-18 19:42:14 +0100181 closeSocket();
182 onFail("Close tunnel");
183}
184
185template <class T>
186inline void
187DatagramFace<T>::handleReceive(const boost::system::error_code& error,
188 size_t nBytesReceived)
189{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000190 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100191 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100192 if (m_socket->is_open())
193 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
194 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100195}
196
197template <class T>
198inline void
199DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
200 size_t nBytesReceived,
201 const boost::system::error_code& error)
202{
203 if (error != 0 || nBytesReceived == 0) {
204 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
205 return;
206
207 // this should be unnecessary, but just in case
208 if (!m_socket->is_open())
209 {
210 onFail("Tunnel closed");
211 return;
212 }
213
214 NFD_LOG_WARN("[id:" << this->getId()
215 << ",endpoint:" << m_socket->local_endpoint()
216 << "] Receive operation failed: "
217 << error.category().message(error.value()));
218
219 closeSocket();
220
221 if (error == boost::asio::error::eof)
222 {
223 onFail("Tunnel closed");
224 }
225 else
226 {
227 onFail("Receive operation failed, closing socket: " +
228 error.category().message(error.value()));
229 }
230 return;
231 }
232
233 NFD_LOG_TRACE("[id:" << this->getId()
234 << ",endpoint:" << m_socket->local_endpoint()
235 << "] Received: " << nBytesReceived << " bytes");
236
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700237 Block element;
238 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
239 if (!isOk)
240 {
241 NFD_LOG_WARN("[id:" << this->getId()
242 << ",endpoint:" << m_socket->local_endpoint()
243 << "] Failed to parse incoming packet");
244 // This message won't extend the face lifetime
245 return;
246 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100247
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700248 if (element.size() != nBytesReceived)
249 {
250 NFD_LOG_WARN("[id:" << this->getId()
251 << ",endpoint:" << m_socket->local_endpoint()
252 << "] Received datagram size and decoded "
253 << "element size don't match");
254 // This message won't extend the face lifetime
255 return;
256 }
257
258 if (!this->decodeAndDispatchInput(element))
259 {
260 NFD_LOG_WARN("[id:" << this->getId()
261 << ",endpoint:" << m_socket->local_endpoint()
262 << "] Received unrecognized block of type ["
263 << element.type() << "]");
264 // This message won't extend the face lifetime
265 return;
266 }
267
Giulio Grassi69871f02014-03-09 16:14:44 +0100268 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100269}
270
271
272template <class T>
273inline void
274DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
275{
276}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600277
Giulio Grassi624f6c62014-02-18 19:42:14 +0100278template <class T>
279inline void
280DatagramFace<T>::closeSocket()
281{
Giulio Grassi69871f02014-03-09 16:14:44 +0100282 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100283 boost::asio::io_service& io = m_socket->get_io_service();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600284
Giulio Grassi624f6c62014-02-18 19:42:14 +0100285 // use the non-throwing variants and ignore errors, if any
286 boost::system::error_code error;
287 m_socket->shutdown(protocol::socket::shutdown_both, error);
288 m_socket->close(error);
289 // after this, handlers will be called with an error code
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600290
Giulio Grassi624f6c62014-02-18 19:42:14 +0100291 // ensure that the Face object is alive at least until all pending
292 // handlers are dispatched
293 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
294 this, this->shared_from_this()));
295}
296
Giulio Grassi69871f02014-03-09 16:14:44 +0100297template <class T>
298inline void
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700299DatagramFace<T>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100300{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700301 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100302}
303
304template <class T>
305inline void
306DatagramFace<T>::resetRecentUsage()
307{
308 m_hasBeenUsedRecently = false;
309}
310
311template <class T>
312inline bool
313DatagramFace<T>::hasBeenUsedRecently() const
314{
315 return m_hasBeenUsedRecently;
316}
317
Giulio Grassi624f6c62014-02-18 19:42:14 +0100318} // namespace nfd
319
320#endif // NFD_FACE_DATAGRAM_FACE_HPP