blob: 3e0194358807470c697f5dc72111e7b25f080fdf [file] [log] [blame]
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
8#include <stdexcept>
9#include <stdlib.h>
10
11#include <ndn-cpp/face.hpp>
12#include <ndn-cpp/transport/unix-transport.hpp>
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080013#include <ndn-cpp/c/util/ndn_memory.h>
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080014
15#include <boost/asio.hpp>
16#include <boost/bind.hpp>
17
18using namespace std;
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080019typedef boost::asio::local::stream_protocol protocol;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080020
21namespace ndn {
22
23const size_t MAX_LENGTH = 9000;
24
25class UnixTransport::Impl
26{
27public:
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080028 Impl(UnixTransport &transport)
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080029 : transport_(transport)
30 , socket_(*transport_.ioService_)
31 , partialDataSize_(0)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080032 {
33 }
34
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080035 void
36 connect()
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080037 {
38 socket_.open();
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080039 socket_.connect(protocol::endpoint(transport_.unixSocket_));
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080040 // socket_.async_connect(protocol::endpoint(unixSocket));
41
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080042 partialDataSize_ = 0;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080043 socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
44 boost::bind(&Impl::handle_async_receive, this, _1, _2));
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080045 }
46
47 void
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080048 close()
49 {
50 socket_.close();
51 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080052
53 void
54 send(const Block &wire)
55 {
56 socket_.async_send(boost::asio::buffer(wire.wire(), wire.size()),
57 boost::bind(&Impl::handle_async_send, this, _1, wire));
58 }
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080059
60 inline void
61 processAll(uint8_t *buffer, size_t &offset, size_t availableSize)
62 {
63 while(offset < availableSize)
64 {
65 Block element(buffer + offset, availableSize - offset);
66 transport_.receive(element);
67
68 offset += element.size();
69 }
70 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080071
72 void
73 handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
74 {
75 /// @todo The socket is not datagram, so need to have internal buffer to handle partial data reception
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080076
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080077 if (!error && bytes_recvd > 0)
78 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080079 try
80 {
81 // inputBuffer_ has bytes_recvd received bytes of data
82 if (partialDataSize_ > 0)
83 {
84 size_t newDataSize = std::min(bytes_recvd, MAX_LENGTH-partialDataSize_);
85 ndn_memcpy(partialData_ + partialDataSize_, inputBuffer_, newDataSize);
86 partialDataSize_ += newDataSize;
87
88 size_t offset = 0;
89 try
90 {
91 processAll(partialData_, offset, partialDataSize_);
92
93 // no exceptions => processed the whole thing
94 if (bytes_recvd - newDataSize > 0)
95 {
96 // there is a little bit more data available
97
98 offset = 0;
99 partialDataSize_ = bytes_recvd - newDataSize;
100 ndn_memcpy(partialData_, inputBuffer_ + newDataSize, partialDataSize_);
101
102 processAll(partialData_, offset, partialDataSize_);
103
104 // no exceptions => processed the whole thing
105 partialDataSize_ = 0;
106 }
107 else
108 {
109 // done processing
110 partialDataSize_ = 0;
111 }
112 }
113 catch(Block::Error &)
114 {
115 if (offset > 0)
116 {
117 partialDataSize_ -= offset;
118 ndn_memcpy(partialData_, partialData_ + offset, partialDataSize_);
119 }
120 else if (offset == 0 && partialDataSize_ == MAX_LENGTH)
121 {
122 // very bad... should close connection
123 /// @todo Notify somebody
124 socket_.close();
125 }
126 }
127 }
128 else
129 {
130 size_t offset = 0;
131 try
132 {
133 processAll(inputBuffer_, offset, bytes_recvd);
134 }
135 catch(Block::Error &error)
136 {
137 if (offset > 0)
138 {
139 partialDataSize_ = bytes_recvd - offset;
140 ndn_memcpy(partialData_, inputBuffer_ + offset, partialDataSize_);
141 }
142 }
143 }
144 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800145 catch(Tlv::Error &error)
146 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800147 std::cerr << "[[handle_async_receive]] Tlv::Error: " << error.what() << std::endl;
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800148 // pass
149 }
150 }
151
152 socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
153 boost::bind(&Impl::handle_async_receive, this, _1, _2));
154 }
155
156 void
157 handle_async_send(const boost::system::error_code& error, const Block &wire)
158 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800159 // pass (needed to keep data block alive during the send)
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800160 }
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800161
162private:
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800163 UnixTransport &transport_;
164
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800165 protocol::socket socket_;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800166 uint8_t inputBuffer_[MAX_LENGTH];
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800167
168 uint8_t partialData_[MAX_LENGTH];
169 size_t partialDataSize_;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800170};
171
172UnixTransport::UnixTransport(const std::string &unixSocket/* = "/tmp/.ndnd.sock"*/)
173 : unixSocket_(unixSocket)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800174{
175}
176
177UnixTransport::~UnixTransport()
178{
179}
180
181void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800182UnixTransport::connect(boost::asio::io_service &ioService, const ReceiveCallback &receiveCallback)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800183{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800184 Transport::connect(ioService, receiveCallback);
185
186 impl_ = std::auto_ptr<UnixTransport::Impl> (new UnixTransport::Impl(*this));
187 impl_->connect();
188
189 isConnected_ = true;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800190}
191
192void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800193UnixTransport::send(const Block &wire)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800194{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800195 impl_->send(wire);
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800196}
197
198void
199UnixTransport::close()
200{
201 impl_->close();
202}
203
204}