Files
NFD/daemon/main.cpp
T
Alexander Afanasyev 0eb70659f7 face: Rename all ChannelFactories to protocol Factories
Base class is ProtocolFactory and implementations are TcpFactory,
UnixStreamFactory, EthernetFactory.

Since Factories are doing more than just creating channels (some can
create faces directly), more general name is more appropriate.

Change-Id: I3d6c2460a1b29e244f8462453720f4e7785893ca
2014-02-28 12:54:16 -08:00

259 lines
6.5 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (C) 2014 Named Data Networking Project
* See COPYING for copyright and distribution information.
*/
#include <getopt.h>
#include "core/logger.hpp"
#include "fw/forwarder.hpp"
#include "mgmt/internal-face.hpp"
#include "mgmt/fib-manager.hpp"
#include "mgmt/local-control-header-manager.hpp"
#include "face/tcp-factory.hpp"
#ifdef HAVE_UNIX_SOCKETS
#include "face/unix-stream-factory.hpp"
#endif
namespace nfd {
NFD_LOG_INIT("Main");
struct ProgramOptions
{
struct TcpOutgoing
{
TcpOutgoing(std::pair<std::string, std::string> endpoint)
: m_endpoint(endpoint)
{
}
std::pair<std::string, std::string> m_endpoint;
std::vector<Name> m_prefixes;
};
bool m_showUsage;
std::pair<std::string, std::string> m_tcpListen;
std::vector<TcpOutgoing> m_tcpOutgoings;
std::string m_unixListen;
};
static ProgramOptions g_options;
static Forwarder* g_forwarder;
static FibManager* g_fibManager;
static LocalControlHeaderManager* g_localControlHeaderManager;
static TcpFactory* g_tcpFactory;
static shared_ptr<TcpChannel> g_tcpChannel;
static shared_ptr<InternalFace> g_internalFace;
#ifdef HAVE_UNIX_SOCKETS
static UnixStreamFactory* g_unixFactory;
static shared_ptr<UnixStreamChannel> g_unixChannel;
#endif
void
usage(char* programName)
{
printf(
"%s --help\n\tshow this help and exit\n"
"%s [--tcp-listen \"0.0.0.0:6363\"] "
#ifdef HAVE_UNIX_SOCKETS
"[--unix-listen \"/var/run/nfd.sock\"] "
#endif
"[--tcp-connect \"192.0.2.1:6363\" "
"[--prefix </example>]]\n"
"\trun forwarding daemon\n"
"\t--tcp-listen <ip:port>: listen on IP and port\n"
#ifdef HAVE_UNIX_SOCKETS
"\t--unix-listen <unix-socket-path>: listen on Unix socket\n"
#endif
"\t--tcp-connect <ip:port>: connect to IP and port (can occur multiple times)\n"
"\t--prefix <NDN name>: add this face as nexthop to FIB entry "
"(must appear after --tcp-connect, can occur multiple times)\n"
"\n",
programName, programName
);
}
inline std::pair<std::string, std::string>
parseIpPortPair(const std::string& s)
{
size_t pos = s.rfind(":");
if (pos == std::string::npos) {
throw std::invalid_argument("ip:port");
}
return std::make_pair(s.substr(0, pos), s.substr(pos+1));
}
bool
parseCommandLine(int argc, char** argv)
{
g_options.m_showUsage = false;
g_options.m_tcpListen = std::make_pair("0.0.0.0", "6363");
g_options.m_unixListen = "/var/run/nfd.sock";
g_options.m_tcpOutgoings.clear();
while (1) {
int option_index = 0;
static ::option long_options[] = {
{ "help" , no_argument , 0, 0 },
{ "tcp-listen" , required_argument, 0, 0 },
{ "tcp-connect" , required_argument, 0, 0 },
{ "prefix" , required_argument, 0, 0 },
{ "unix-listen" , required_argument, 0, 0 },
{ 0 , 0 , 0, 0 }
};
int c = getopt_long_only(argc, argv, "", long_options, &option_index);
if (c == -1) break;
switch (c) {
case 0:
switch (option_index) {
case 0://help
g_options.m_showUsage = true;
break;
case 1://tcp-listen
g_options.m_tcpListen = parseIpPortPair(::optarg);
break;
case 2://tcp-connect
g_options.m_tcpOutgoings.push_back(parseIpPortPair(::optarg));
break;
case 3://prefix
if (g_options.m_tcpOutgoings.empty()) {
return false;
}
g_options.m_tcpOutgoings.back().m_prefixes.push_back(Name(::optarg));
break;
case 4://unix-listen
g_options.m_unixListen = ::optarg;
break;
}
break;
}
}
return true;
}
void
onFaceFail(shared_ptr<Face> face, const std::string& reason)
{
g_forwarder->removeFace(face);
}
void
onFaceEstablish(shared_ptr<Face> newFace, std::vector<Name>* prefixes)
{
g_forwarder->addFace(newFace);
newFace->onFail += bind(&onFaceFail, newFace, _1);
// add nexthop on prefixes
if (prefixes != 0) {
Fib& fib = g_forwarder->getFib();
for (std::vector<Name>::iterator it = prefixes->begin();
it != prefixes->end(); ++it) {
std::pair<shared_ptr<fib::Entry>, bool> fibInsertResult =
fib.insert(*it);
shared_ptr<fib::Entry> fibEntry = fibInsertResult.first;
fibEntry->addNextHop(newFace, 0);
}
}
}
void
onFaceError(const std::string& reason)
{
throw std::runtime_error(reason);
}
void
initializeTcp()
{
g_tcpFactory = new TcpFactory();
g_tcpChannel = g_tcpFactory->create(g_options.m_tcpListen.first,
g_options.m_tcpListen.second);
g_tcpChannel->listen(
bind(&onFaceEstablish, _1, static_cast<std::vector<Name>*>(0)),
&onFaceError);
for (std::vector<ProgramOptions::TcpOutgoing>::iterator it =
g_options.m_tcpOutgoings.begin();
it != g_options.m_tcpOutgoings.end(); ++it) {
g_tcpChannel->connect(it->m_endpoint.first, it->m_endpoint.second,
bind(&onFaceEstablish, _1, &(it->m_prefixes)), &onFaceError);
}
}
#ifdef HAVE_UNIX_SOCKETS
void
initializeUnix()
{
g_unixFactory = new UnixStreamFactory();
g_unixChannel = g_unixFactory->create(g_options.m_unixListen);
g_unixChannel->listen(
bind(&onFaceEstablish, _1, static_cast<std::vector<Name>*>(0)),
&onFaceError);
}
#endif
void
initializeMgmt()
{
g_internalFace = make_shared<InternalFace>();
g_forwarder->addFace(g_internalFace);
g_fibManager = new FibManager(g_forwarder->getFib(),
bind(&Forwarder::getFace, g_forwarder, _1),
g_internalFace);
g_localControlHeaderManager =
new LocalControlHeaderManager(bind(&Forwarder::getFace, g_forwarder, _1),
g_internalFace);
shared_ptr<fib::Entry> entry = g_forwarder->getFib().insert("/localhost/nfd").first;
entry->addNextHop(g_internalFace, 0);
}
int
main(int argc, char** argv)
{
bool isCommandLineValid = parseCommandLine(argc, argv);
if (!isCommandLineValid) {
usage(argv[0]);
return 1;
}
if (g_options.m_showUsage) {
usage(argv[0]);
return 0;
}
g_forwarder = new Forwarder();
initializeTcp();
#ifdef HAVE_UNIX_SOCKETS
initializeUnix();
#endif
initializeMgmt();
/// \todo Add signal processing to gracefully terminate the app
try {
getGlobalIoService().run();
} catch(std::exception& ex) {
NFD_LOG_ERROR(ex.what());
return 1;
}
return 0;
}
} // namespace nfd
int
main(int argc, char** argv)
{
return nfd::main(argc, argv);
}