blob: 5b1b3d9513ecc36f63af18a1463211123254577f [file] [log] [blame]
Giulio Grassi624f6c62014-02-18 19:42:14 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi08d07a72014-06-09 23:17:57 -07003 * Copyright (c) 2014, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyevcd591e12014-06-18 16:35:16 -070024 */
Giulio Grassi624f6c62014-02-18 19:42:14 +010025
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070026#ifndef NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
27#define NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
Giulio Grassi624f6c62014-02-18 19:42:14 +010028
29#include "face.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060030#include "core/logger.hpp"
Giulio Grassi624f6c62014-02-18 19:42:14 +010031
32namespace nfd {
33
Alexander Afanasyevcd591e12014-06-18 16:35:16 -070034class Unicast {};
35class Multicast {};
36
37template<class Protocol, class Type = Unicast>
Giulio Grassi624f6c62014-02-18 19:42:14 +010038class DatagramFace : public Face
39{
40public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010041 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070042
43 /** \brief Construct datagram face
44 *
Alexander Afanasyev355c0662014-03-20 18:08:17 -070045 * \param socket Protocol-specific socket for the created face
46 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010047 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070048 */
Junxiao Shi79494162014-04-02 18:25:11 -070049 DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +010050 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070051 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010052
53 virtual
54 ~DatagramFace();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060055
Giulio Grassi624f6c62014-02-18 19:42:14 +010056 // from Face
57 virtual void
58 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060059
Giulio Grassi624f6c62014-02-18 19:42:14 +010060 virtual void
61 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060062
Giulio Grassi624f6c62014-02-18 19:42:14 +010063 virtual void
64 close();
65
66 void
Davide Pesaventoa7530582014-06-30 20:45:52 +020067 receiveDatagram(const uint8_t* buffer,
68 size_t nBytesReceived,
69 const boost::system::error_code& error);
Giulio Grassi624f6c62014-02-18 19:42:14 +010070
Giulio Grassi69871f02014-03-09 16:14:44 +010071 /**
72 * \brief Set m_hasBeenUsedRecently to false
73 */
74 void
75 resetRecentUsage();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060076
Giulio Grassi69871f02014-03-09 16:14:44 +010077 bool
78 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070079
80 void
81 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060082
Giulio Grassi624f6c62014-02-18 19:42:14 +010083protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010084 void
Davide Pesaventoa7530582014-06-30 20:45:52 +020085 handleSend(const boost::system::error_code& error,
Junxiao Shi5dd26c32014-07-20 23:15:14 -070086 size_t nBytesSent,
87 const Block& payload);
Davide Pesaventoa7530582014-06-30 20:45:52 +020088
89 void
90 handleReceive(const boost::system::error_code& error,
91 size_t nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +010092
93 void
94 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060095
Giulio Grassi624f6c62014-02-18 19:42:14 +010096 void
97 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060098
Giulio Grassi624f6c62014-02-18 19:42:14 +010099protected:
100 shared_ptr<typename protocol::socket> m_socket;
Junxiao Shi39cd6332014-11-06 21:53:18 -0700101 uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
Giulio Grassi69871f02014-03-09 16:14:44 +0100102 bool m_hasBeenUsedRecently;
103
Giulio Grassi624f6c62014-02-18 19:42:14 +0100104 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +0100105};
106
Davide Pesavento1bdef282014-04-08 20:59:50 +0200107
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700108template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100109inline
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700110DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
111 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
112 bool isOnDemand)
Junxiao Shi79494162014-04-02 18:25:11 -0700113 : Face(remoteUri, localUri)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +0000114 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100115{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700116 setOnDemand(isOnDemand);
117
Junxiao Shi39cd6332014-11-06 21:53:18 -0700118 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700119 bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100120}
121
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700122template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100123inline
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700124DatagramFace<T, U>::~DatagramFace()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100125{
126}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600127
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700128template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100129inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700130DatagramFace<T, U>::sendInterest(const Interest& interest)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100131{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000132 this->onSendInterest(interest);
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700133 const Block& payload = interest.wireEncode();
134 m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
135 bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600136
Giulio Grassi624f6c62014-02-18 19:42:14 +0100137 // anything else should be done here?
138}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600139
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700140template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100141inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700142DatagramFace<T, U>::sendData(const Data& data)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100143{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000144 this->onSendData(data);
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700145 const Block& payload = data.wireEncode();
146 m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
147 bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600148
Giulio Grassi624f6c62014-02-18 19:42:14 +0100149 // anything else should be done here?
150}
151
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700152template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100153inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700154DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700155 size_t nBytesSent,
156 const Block& payload)
157// 'payload' is unused; it's needed to retain the underlying Buffer
Giulio Grassi624f6c62014-02-18 19:42:14 +0100158{
159 if (error != 0) {
160 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
161 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600162
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700163 if (!m_socket->is_open()) {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700164 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100165 return;
166 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600167
Giulio Grassi624f6c62014-02-18 19:42:14 +0100168 NFD_LOG_WARN("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700169 << ",uri:" << this->getRemoteUri()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100170 << "] Send operation failed, closing socket: "
171 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600172
Giulio Grassi624f6c62014-02-18 19:42:14 +0100173 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600174
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700175 if (error == boost::asio::error::eof) {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700176 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100177 }
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700178 else {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700179 fail("Send operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100180 error.category().message(error.value()));
181 }
182 return;
183 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600184
Giulio Grassi624f6c62014-02-18 19:42:14 +0100185 NFD_LOG_TRACE("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700186 << ",uri:" << this->getRemoteUri()
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700187 << "] Successfully sent: " << nBytesSent << " bytes");
188 this->getMutableCounters().getNOutBytes() += nBytesSent;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100189}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600190
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700191template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100192inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700193DatagramFace<T, U>::close()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100194{
195 if (!m_socket->is_open())
196 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600197
Giulio Grassi624f6c62014-02-18 19:42:14 +0100198 NFD_LOG_INFO("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700199 << ",uri:" << this->getRemoteUri()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100200 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600201
Giulio Grassi624f6c62014-02-18 19:42:14 +0100202 closeSocket();
Junxiao Shi08d07a72014-06-09 23:17:57 -0700203 fail("Close tunnel");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100204}
205
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700206template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100207inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700208DatagramFace<T, U>::handleReceive(const boost::system::error_code& error,
209 size_t nBytesReceived)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100210{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000211 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100212 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100213 if (m_socket->is_open())
Junxiao Shi39cd6332014-11-06 21:53:18 -0700214 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700215 bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100216}
217
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700218template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100219inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700220DatagramFace<T, U>::receiveDatagram(const uint8_t* buffer,
221 size_t nBytesReceived,
222 const boost::system::error_code& error)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100223{
224 if (error != 0 || nBytesReceived == 0) {
225 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
226 return;
227
228 // this should be unnecessary, but just in case
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700229 if (!m_socket->is_open()) {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700230 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100231 return;
232 }
233
234 NFD_LOG_WARN("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700235 << ",uri:" << this->getRemoteUri()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100236 << "] Receive operation failed: "
237 << error.category().message(error.value()));
238
239 closeSocket();
240
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700241 if (error == boost::asio::error::eof) {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700242 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100243 }
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700244 else {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700245 fail("Receive operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100246 error.category().message(error.value()));
247 }
248 return;
249 }
250
251 NFD_LOG_TRACE("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700252 << ",uri:" << this->getRemoteUri()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100253 << "] Received: " << nBytesReceived << " bytes");
Junxiao Shi5dd26c32014-07-20 23:15:14 -0700254 this->getMutableCounters().getNInBytes() += nBytesReceived;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100255
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700256 Block element;
257 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
258 if (!isOk)
259 {
260 NFD_LOG_WARN("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700261 << ",uri:" << this->getRemoteUri()
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700262 << "] Failed to parse incoming packet");
263 // This message won't extend the face lifetime
264 return;
265 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100266
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700267 if (element.size() != nBytesReceived)
268 {
269 NFD_LOG_WARN("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700270 << ",uri:" << this->getRemoteUri()
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700271 << "] Received datagram size and decoded "
272 << "element size don't match");
273 // This message won't extend the face lifetime
274 return;
275 }
276
277 if (!this->decodeAndDispatchInput(element))
278 {
279 NFD_LOG_WARN("[id:" << this->getId()
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700280 << ",uri:" << this->getRemoteUri()
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700281 << "] Received unrecognized block of type ["
282 << element.type() << "]");
283 // This message won't extend the face lifetime
284 return;
285 }
286
Giulio Grassi69871f02014-03-09 16:14:44 +0100287 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100288}
289
290
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700291template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100292inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700293DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100294{
295}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600296
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700297template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100298inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700299DatagramFace<T, U>::closeSocket()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100300{
Alexander Afanasyev29d1fab2014-07-07 19:27:16 -0700301 NFD_LOG_DEBUG("[id:" << this->getId()
302 << ",uri:" << this->getRemoteUri()
303 << "] closeSocket");
304
Giulio Grassi624f6c62014-02-18 19:42:14 +0100305 boost::asio::io_service& io = m_socket->get_io_service();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600306
Giulio Grassi624f6c62014-02-18 19:42:14 +0100307 // use the non-throwing variants and ignore errors, if any
308 boost::system::error_code error;
309 m_socket->shutdown(protocol::socket::shutdown_both, error);
310 m_socket->close(error);
311 // after this, handlers will be called with an error code
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600312
Giulio Grassi624f6c62014-02-18 19:42:14 +0100313 // ensure that the Face object is alive at least until all pending
314 // handlers are dispatched
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700315 io.post(bind(&DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
Giulio Grassi624f6c62014-02-18 19:42:14 +0100316 this, this->shared_from_this()));
317}
318
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700319template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100320inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700321DatagramFace<T, U>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100322{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700323 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100324}
325
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700326template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100327inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700328DatagramFace<T, U>::resetRecentUsage()
Giulio Grassi69871f02014-03-09 16:14:44 +0100329{
330 m_hasBeenUsedRecently = false;
331}
332
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700333template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100334inline bool
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700335DatagramFace<T, U>::hasBeenUsedRecently() const
Giulio Grassi69871f02014-03-09 16:14:44 +0100336{
337 return m_hasBeenUsedRecently;
338}
339
Giulio Grassi624f6c62014-02-18 19:42:14 +0100340} // namespace nfd
341
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700342#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP