blob: d64f3333b2735b7cbd8c20f232108e2ed9629eb6 [file] [log] [blame]
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010024
25#include "unix-stream-channel.hpp"
Junxiao Shi61e3cc52014-03-03 20:40:28 -070026#include "core/global-io.hpp"
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010027
28#include <boost/filesystem.hpp>
Davide Pesavento9cec8ee2014-02-19 11:21:59 +010029#include <sys/stat.h> // for chmod()
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010030
31namespace nfd {
32
33NFD_LOG_INIT("UnixStreamChannel");
34
35using namespace boost::asio::local;
36
Junxiao Shi61e3cc52014-03-03 20:40:28 -070037UnixStreamChannel::UnixStreamChannel(const unix_stream::Endpoint& endpoint)
38 : m_endpoint(endpoint)
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020039 , m_isListening(false)
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010040{
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020041 setUri(FaceUri(endpoint));
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010042}
43
44UnixStreamChannel::~UnixStreamChannel()
45{
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020046 if (m_isListening)
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010047 {
48 // use the non-throwing variants during destruction
49 // and ignore any errors
50 boost::system::error_code error;
51 m_acceptor->close(error);
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020052 NFD_LOG_TRACE("[" << m_endpoint << "] Removing socket file");
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010053 boost::filesystem::remove(m_endpoint.path(), error);
54 }
55}
56
57void
58UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
59 const ConnectFailedCallback& onAcceptFailed,
60 int backlog/* = acceptor::max_connections*/)
61{
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020062 if (m_isListening) {
63 NFD_LOG_WARN("[" << m_endpoint << "] Already listening");
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010064 return;
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020065 }
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010066
67 namespace fs = boost::filesystem;
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020068
69 fs::path socketPath(m_endpoint.path());
70 fs::file_type type = fs::symlink_status(socketPath).type();
71
72 if (type == fs::socket_file)
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010073 {
Davide Pesaventoe22d8c82014-04-14 04:01:52 +020074 boost::system::error_code error;
75 stream_protocol::socket socket(getGlobalIoService());
76 socket.connect(m_endpoint, error);
77 NFD_LOG_TRACE("[" << m_endpoint << "] connect() on existing socket file returned: "
78 + error.message());
79 if (!error)
80 {
81 // someone answered, leave the socket alone
82 throw Error("Socket file at " + m_endpoint.path()
83 + " belongs to another NFD process");
84 }
85 else if (error == boost::system::errc::connection_refused ||
86 error == boost::system::errc::timed_out)
87 {
88 // no one is listening on the remote side,
89 // we can safely remove the socket file
90 NFD_LOG_INFO("[" << m_endpoint << "] Removing stale socket file");
91 fs::remove(socketPath);
92 }
93 }
94 else if (type != fs::file_not_found)
95 {
96 throw Error(m_endpoint.path() + " already exists and is not a socket file");
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010097 }
98
Alexander Afanasyevf6980282014-05-13 18:28:40 -070099 m_acceptor = make_shared<stream_protocol::acceptor>(ref(getGlobalIoService()));
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200100 m_acceptor->open();
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100101 m_acceptor->bind(m_endpoint);
102 m_acceptor->listen(backlog);
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200103 m_isListening = true;
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100104
Davide Pesavento9cec8ee2014-02-19 11:21:59 +0100105 if (::chmod(m_endpoint.path().c_str(), 0666) < 0)
106 {
107 throw Error("Failed to chmod() socket file at " + m_endpoint.path());
108 }
109
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100110 shared_ptr<stream_protocol::socket> clientSocket =
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700111 make_shared<stream_protocol::socket>(ref(getGlobalIoService()));
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100112
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200113 m_acceptor->async_accept(*clientSocket,
114 bind(&UnixStreamChannel::handleSuccessfulAccept, this,
115 boost::asio::placeholders::error, clientSocket,
116 onFaceCreated, onAcceptFailed));
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100117}
118
119void
120UnixStreamChannel::handleSuccessfulAccept(const boost::system::error_code& error,
121 const shared_ptr<stream_protocol::socket>& socket,
122 const FaceCreatedCallback& onFaceCreated,
123 const ConnectFailedCallback& onAcceptFailed)
124{
125 if (error) {
126 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
127 return;
128
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200129 NFD_LOG_DEBUG("[" << m_endpoint << "] Connection failed: " << error.message());
130 onAcceptFailed("Connection failed: " + error.message());
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100131 return;
132 }
133
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200134 NFD_LOG_DEBUG("[" << m_endpoint << "] << Incoming connection");
135
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100136 shared_ptr<stream_protocol::socket> clientSocket =
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700137 make_shared<stream_protocol::socket>(ref(getGlobalIoService()));
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100138
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200139 // prepare accepting the next connection
140 m_acceptor->async_accept(*clientSocket,
141 bind(&UnixStreamChannel::handleSuccessfulAccept, this,
142 boost::asio::placeholders::error, clientSocket,
143 onFaceCreated, onAcceptFailed));
144
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700145 shared_ptr<UnixStreamFace> face = make_shared<UnixStreamFace>(socket);
Davide Pesaventoe22d8c82014-04-14 04:01:52 +0200146 onFaceCreated(face);
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100147}
148
149} // namespace nfd