blob: 8da8012f28b3c5138d6e5f5e22d5fc0393ccfbd7 [file] [log] [blame]
Alexander Afanasyev2aa39622014-01-22 11:51:11 -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
Junxiao Shi09bf7c42014-01-31 11:10:25 -07007#include <getopt.h>
8#include "core/logger.hpp"
9#include "fw/forwarder.hpp"
10#include "mgmt/internal-face.hpp"
Steve DiBenedetto214563c2014-02-03 19:20:36 -070011#include "mgmt/fib-manager.hpp"
Junxiao Shi09bf7c42014-01-31 11:10:25 -070012#include "face/tcp-channel-factory.hpp"
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080013#include "face/unix-stream-channel-factory.hpp"
Junxiao Shi09bf7c42014-01-31 11:10:25 -070014
15namespace nfd {
16
17NFD_LOG_INIT("Main");
18
19struct ProgramOptions
Alexander Afanasyev2aa39622014-01-22 11:51:11 -080020{
Junxiao Shi09bf7c42014-01-31 11:10:25 -070021 struct TcpOutgoing
22 {
23 TcpOutgoing(std::pair<std::string, std::string> endpoint)
24 : m_endpoint(endpoint)
25 {
26 }
27
28 std::pair<std::string, std::string> m_endpoint;
29 std::vector<Name> m_prefixes;
30 };
31
32 bool m_showUsage;
33 std::pair<std::string, std::string> m_tcpListen;
34 std::vector<TcpOutgoing> m_tcpOutgoings;
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080035 std::string m_unixListen;
Junxiao Shi09bf7c42014-01-31 11:10:25 -070036};
37
38static boost::asio::io_service g_ioService;
39static ProgramOptions g_options;
40static Forwarder* g_forwarder;
Steve DiBenedetto214563c2014-02-03 19:20:36 -070041static FibManager* g_fibManager;
Junxiao Shi09bf7c42014-01-31 11:10:25 -070042static TcpChannelFactory* g_tcpFactory;
43static shared_ptr<TcpChannel> g_tcpChannel;
44static shared_ptr<InternalFace> g_internalFace;
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080045static UnixStreamChannelFactory* g_unixFactory;
46static shared_ptr<UnixStreamChannel> g_unixChannel;
Junxiao Shi09bf7c42014-01-31 11:10:25 -070047
48void
49usage(char* programName)
50{
51 printf(
52 "%s --help\n\tshow this help and exit\n"
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080053 "%s [--tcp-listen \"0.0.0.0:6363\"] "
54 "[--unix-listen \"/var/run/nfd.sock\"] "
55 "[--tcp-connect \"192.0.2.1:6363\" "
56 "[--prefix </example>]]\n"
Junxiao Shi09bf7c42014-01-31 11:10:25 -070057 "\trun forwarding daemon\n"
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080058 "\t--tcp-listen <ip:port>: listen on IP and port\n"
59 "\t--unix-listen <unix-socket-path>: listen on Unix socket\n"
60 "\t--tcp-connect <ip:port>: connect to IP and port (can occur multiple times)\n"
61 "\t--prefix <NDN name>: add this face as nexthop to FIB entry "
Junxiao Shi09bf7c42014-01-31 11:10:25 -070062 "(must appear after --tcp-connect, can occur multiple times)\n"
63 "\n",
64 programName, programName
65 );
66}
67
68inline std::pair<std::string, std::string>
69parseIpPortPair(const std::string& s)
70{
71 size_t pos = s.rfind(":");
72 if (pos == std::string::npos) {
73 throw std::invalid_argument("ip:port");
74 }
75
76 return std::make_pair(s.substr(0, pos), s.substr(pos+1));
77}
78
79bool
80parseCommandLine(int argc, char** argv)
81{
82 g_options.m_showUsage = false;
83 g_options.m_tcpListen = std::make_pair("0.0.0.0", "6363");
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080084 g_options.m_unixListen = "/var/run/nfd.sock";
Junxiao Shi09bf7c42014-01-31 11:10:25 -070085 g_options.m_tcpOutgoings.clear();
86
87 while (1) {
88 int option_index = 0;
89 static ::option long_options[] = {
90 { "help" , no_argument , 0, 0 },
91 { "tcp-listen" , required_argument, 0, 0 },
92 { "tcp-connect" , required_argument, 0, 0 },
93 { "prefix" , required_argument, 0, 0 },
Alexander Afanasyev062dfb42014-02-16 22:10:53 -080094 { "unix-listen" , required_argument, 0, 0 },
Junxiao Shi09bf7c42014-01-31 11:10:25 -070095 { 0 , 0 , 0, 0 }
96 };
97 int c = getopt_long_only(argc, argv, "", long_options, &option_index);
98 if (c == -1) break;
99
100 switch (c) {
101 case 0:
102 switch (option_index) {
103 case 0://help
104 g_options.m_showUsage = true;
105 break;
106 case 1://tcp-listen
107 g_options.m_tcpListen = parseIpPortPair(::optarg);
108 break;
109 case 2://tcp-connect
110 g_options.m_tcpOutgoings.push_back(parseIpPortPair(::optarg));
111 break;
112 case 3://prefix
113 if (g_options.m_tcpOutgoings.empty()) {
114 return false;
115 }
116 g_options.m_tcpOutgoings.back().m_prefixes.push_back(Name(::optarg));
Alexander Afanasyev062dfb42014-02-16 22:10:53 -0800117 break;
118 case 4://unix-listen
119 g_options.m_unixListen = ::optarg;
120 break;
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700121 }
122 break;
123 }
124 }
125 return true;
126}
127
128void
129onFaceFail(shared_ptr<Face> face, const std::string& reason)
130{
131 g_forwarder->removeFace(face);
132}
133
134void
135onFaceEstablish(shared_ptr<Face> newFace, std::vector<Name>* prefixes)
136{
137 g_forwarder->addFace(newFace);
138 newFace->onFail += bind(&onFaceFail, newFace, _1);
139
140 // add nexthop on prefixes
141 if (prefixes != 0) {
142 Fib& fib = g_forwarder->getFib();
143 for (std::vector<Name>::iterator it = prefixes->begin();
144 it != prefixes->end(); ++it) {
145 std::pair<shared_ptr<fib::Entry>, bool> fibInsertResult =
146 fib.insert(*it);
147 shared_ptr<fib::Entry> fibEntry = fibInsertResult.first;
148 fibEntry->addNextHop(newFace, 0);
149 }
150 }
151}
152
153void
154onFaceError(const std::string& reason)
155{
156 throw std::runtime_error(reason);
157}
158
159void
160initializeTcp()
161{
162 g_tcpFactory = new TcpChannelFactory(g_ioService);
163 g_tcpChannel = g_tcpFactory->create(g_options.m_tcpListen.first,
164 g_options.m_tcpListen.second);
165 g_tcpChannel->listen(
166 bind(&onFaceEstablish, _1, static_cast<std::vector<Name>*>(0)),
167 &onFaceError);
168
169 for (std::vector<ProgramOptions::TcpOutgoing>::iterator it =
170 g_options.m_tcpOutgoings.begin();
171 it != g_options.m_tcpOutgoings.end(); ++it) {
172 g_tcpChannel->connect(it->m_endpoint.first, it->m_endpoint.second,
173 bind(&onFaceEstablish, _1, &(it->m_prefixes)), &onFaceError);
174 }
175}
176
177void
Alexander Afanasyev062dfb42014-02-16 22:10:53 -0800178initializeUnix()
179{
180 g_unixFactory = new UnixStreamChannelFactory(g_ioService);
181 g_unixChannel = g_unixFactory->create(g_options.m_unixListen);
182
183 g_unixChannel->listen(
184 bind(&onFaceEstablish, _1, static_cast<std::vector<Name>*>(0)),
185 &onFaceError);
186}
187
188void
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700189initializeMgmt()
190{
191 g_internalFace = make_shared<InternalFace>();
192 g_forwarder->addFace(g_internalFace);
Steve DiBenedetto214563c2014-02-03 19:20:36 -0700193
194 g_fibManager = new FibManager(g_forwarder->getFib(),
195 bind(&Forwarder::getFace, g_forwarder, _1),
196 g_internalFace);
197
198 shared_ptr<fib::Entry> entry = g_forwarder->getFib().insert("/localhost/nfd/fib").first;
199 entry->addNextHop(g_internalFace, 0);
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700200}
201
202int
203main(int argc, char** argv)
204{
205 bool isCommandLineValid = parseCommandLine(argc, argv);
206 if (!isCommandLineValid) {
207 usage(argv[0]);
208 return 1;
209 }
210 if (g_options.m_showUsage) {
211 usage(argv[0]);
212 return 0;
213 }
214
215 g_forwarder = new Forwarder(g_ioService);
216 initializeTcp();
Alexander Afanasyev062dfb42014-02-16 22:10:53 -0800217 initializeUnix();
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700218 initializeMgmt();
Alexander Afanasyev062dfb42014-02-16 22:10:53 -0800219
220 /// \todo Add signal processing to gracefully terminate the app
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700221
222 try {
223 g_ioService.run();
224 } catch(std::exception& ex) {
225 NFD_LOG_ERROR(ex.what());
226 return 1;
227 }
228
Alexander Afanasyev2aa39622014-01-22 11:51:11 -0800229 return 0;
230}
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700231
232} // namespace nfd
233
234int
235main(int argc, char** argv)
236{
237 return nfd::main(argc, argv);
238}