blob: 8fd39a12389fdfb6baf6dcf64864bfbcecae64e1 [file] [log] [blame]
Alexander Afanasyeva9034b02014-01-26 18:32:02 -08001/* -*- 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_STREAM_FACE_HPP
8#define NFD_FACE_STREAM_FACE_HPP
9
10#include "face.hpp"
11
12namespace ndn {
13
14template <class T>
15class StreamFace : public Face
16{
17public:
18 typedef T protocol;
19
Alexander Afanasyevd32cb962014-01-28 12:43:47 -080020 StreamFace(FaceId id,
21 const shared_ptr<typename protocol::socket>& socket);
22
23protected:
24 void
25 handleSend(const boost::system::error_code& error,
26 const Block& wire);
27
28 void
29 handleReceive(const boost::system::error_code& error,
30 std::size_t bytes_recvd);
31
32protected:
33 shared_ptr<typename protocol::socket> m_socket;
34
35private:
36 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
37 std::size_t m_inputBufferSize;
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080038};
39
Alexander Afanasyevd32cb962014-01-28 12:43:47 -080040template <class T>
41inline
42StreamFace<T>::StreamFace(FaceId id,
43 const shared_ptr<typename StreamFace::protocol::socket>& socket)
44 : Face(id)
45 , m_socket(socket)
46{
47 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
48 bind(&StreamFace<T>::handleReceive, this, _1, _2));
49}
50
51
52template <class T>
53inline void
54StreamFace<T>::handleSend(const boost::system::error_code& error,
55 const Block& wire)
56{
57 if (error) {
58 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
59 return;
60
61 onFail("Send operation failed: " + error.category().message(error.value()));
62 m_socket->close();
63 return;
64 }
65
66 // do nothing (needed to retain validity of wire memory block
67}
68
69template <class T>
70inline void
71StreamFace<T>::handleReceive(const boost::system::error_code& error,
72 std::size_t bytes_recvd)
73{
74 if (error || bytes_recvd == 0) {
75 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
76 return;
77
78 onFail("Receive operation failed: " + error.category().message(error.value()));
79 m_socket->close();
80 return;
81 }
82
83 m_inputBufferSize += bytes_recvd;
84 // do magic
85
86 std::size_t offset = 0;
87 /// @todo Eliminate reliance on exceptions in this path
88 try {
89 Block element(m_inputBuffer + offset, m_inputBufferSize - offset);
90 offset += element.size();
91
92 /// @todo Ensure lazy field decoding process
93 if (element.type() == Tlv::Interest)
94 {
95 shared_ptr<Interest> i = make_shared<Interest>();
96 i->wireDecode(element);
97 onReceiveInterest(*i);
98 }
99 else if (element.type() == Tlv::Data)
100 {
101 shared_ptr<Data> d = make_shared<Data>();
102 d->wireDecode(element);
103 onReceiveData(*d);
104 }
105 // @todo Add local header support
106 // else if (element.type() == Tlv::LocalHeader)
107 // {
108 // shared_ptr<Interest> i = make_shared<Interest>();
109 // i->wireDecode(element);
110 // }
111 else
112 {
113 /// @todo Add loggin
114
115 // ignore unknown packet and proceed
116 }
117 }
118 catch(const Tlv::Error&) {
119 if (m_inputBufferSize == MAX_NDN_PACKET_SIZE && offset == 0)
120 {
121 onFail("Received input is invalid or too large to process, closing down the face");
122 m_socket->close();
123 return;
124 }
125 }
126
127 if (offset > 0)
128 {
129 if (offset != m_inputBufferSize)
130 {
131 std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize,
132 m_inputBuffer);
133 m_inputBufferSize -= offset;
134 }
135 else
136 {
137 m_inputBufferSize = 0;
138 }
139 }
140
141 m_socket->async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
142 MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
143 bind(&StreamFace<T>::handleReceive, this, _1, _2));
144}
145
146
Alexander Afanasyeva9034b02014-01-26 18:32:02 -0800147} // namespace ndn
148
149#endif // NFD_FACE_STREAM_FACE_HPP