Skip to content

Commit

Permalink
Implement DNS query support
Browse files Browse the repository at this point in the history
Implement support for dns request / response with the goal of allowing a asyncronous host -> ip resolution mechanism.

* Created a example tool for dns query:
```
$ bin/toolbox-dns -s 8.8.8.8 www.reactivemarkets.com
```
* Added an additional hex_dump debug facility

Close #57
  • Loading branch information
rfernandes committed Nov 11, 2019
1 parent 40784cc commit dbbc63b
Show file tree
Hide file tree
Showing 15 changed files with 686 additions and 10 deletions.
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
-DCMAKE_BUILD_TYPE=DEBUG \
-DCMAKE_C_COMPILER=clang-7 \
-DCMAKE_CXX_COMPILER=clang++-7
VERBOSE=1 make -j2 all test
CTEST_OUTPUT_ON_FAILURE=1 VERBOSE=1 make -j2 all test
test_clang_release:
docker:
- image: registry.gitlab.com/reactivemarkets/public-registry/toolchain-cpp:debian
Expand All @@ -52,7 +52,7 @@ jobs:
-DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_C_COMPILER=clang-7 \
-DCMAKE_CXX_COMPILER=clang++-7
VERBOSE=1 make -j2 all test
CTEST_OUTPUT_ON_FAILURE=1 VERBOSE=1 make -j2 all test
test_gcc_debug:
docker:
- image: registry.gitlab.com/reactivemarkets/public-registry/toolchain-cpp:debian
Expand All @@ -69,7 +69,7 @@ jobs:
-DCMAKE_BUILD_TYPE=DEBUG \
-DCMAKE_C_COMPILER=gcc-8 \
-DCMAKE_CXX_COMPILER=g++-8
VERBOSE=1 make -j2 all test
CTEST_OUTPUT_ON_FAILURE=1 VERBOSE=1 make -j2 all test
test_gcc_release:
docker:
- image: registry.gitlab.com/reactivemarkets/public-registry/toolchain-cpp:debian
Expand All @@ -86,7 +86,7 @@ jobs:
-DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_C_COMPILER=gcc-8 \
-DCMAKE_CXX_COMPILER=g++-8
VERBOSE=1 make -j2 all test
CTEST_OUTPUT_ON_FAILURE=1 VERBOSE=1 make -j2 all test
build_doc:
docker:
- image: registry.gitlab.com/reactivemarkets/public-registry/toolchain-cpp:debian
Expand Down
3 changes: 3 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ target_link_libraries(toolbox-echo-serv ${toolbox_LIBRARY})

add_executable(toolbox-http-serv HttpServ.cpp)
target_link_libraries(toolbox-http-serv ${toolbox_LIBRARY})

add_executable(toolbox-dns Dns.cpp)
target_link_libraries(toolbox-dns ${toolbox_LIBRARY})
134 changes: 134 additions & 0 deletions example/Dns.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// The Reactive C++ Toolbox.
// Copyright (C) 2019 Reactive Markets Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <toolbox/io.hpp>
#include <toolbox/net.hpp>
#include <toolbox/sys.hpp>
#include <toolbox/util.hpp>

#include <fstream>
#include <iostream>

using namespace std;
using namespace toolbox;
using namespace toolbox::net;

class DnsRequestHandler {
public:
DnsRequestHandler(Reactor& reactor, IoSock& sock, const std::string& nameserver)
: reactor_{reactor}
, sock_{sock}
, handle_{reactor.subscribe(*sock_, EventIn, bind<&DnsRequestHandler::on_request>(this))}
, ep_{UdpProtocol::v4(), 63}
, nameserver_{nameserver}
{
}

void on_request(CyclTime now, int fd, unsigned events)
{
// TODO: Replace with protocol or allow bind to wrapped message types (MutableBuffer?)
char size{0};
os::recv(fd, &size, 1, 0);
char hostname_buffer[64];
os::recv(fd, hostname_buffer, size, 0);
string_view hostname{hostname_buffer, static_cast<size_t>(size)};
TOOLBOX_INFO << "Requesting " << hostname;
auto udp_fd = send_dns_request(nameserver_, string{hostname}, DnsRequest::A);
TOOLBOX_INFO << "Subscribing to response";
response_
= reactor_.subscribe(udp_fd, EventIn, bind<&DnsRequestHandler::on_response>(this));
}

void on_response(CyclTime now, int fd, unsigned events)
{
TOOLBOX_INFO << "Processing response";
std::cout << get_dns_request(fd, ep_) << '\n';
kill(getpid(), SIGTERM);
}

private:
Reactor& reactor_;
IoSock& sock_;
Reactor::Handle handle_;
Reactor::Handle response_;
UdpEndpoint ep_;
const std::string& nameserver_;
};

int main(int argc, char* argv[])
{
std::ios::sync_with_stdio(false);
int ret = 1;

try {
std::string nameserver;
std::string hostname;

Options opts{"Unit Test options [OPTIONS] [COMMAND]"};
// clang-format off
opts('s', Value{nameserver}, "ShortOption Description")
('h', "help", Help{}, "Help")
(Value{hostname}.required(), "Hostname")
;
// clang-format on

opts.parse(argc, argv);

if (nameserver.empty()) {
std::ifstream resolv_conf{"/etc/resolv.conf"};
DnsServers dns_servers{resolv_conf};
nameserver = dns_servers.server();
}

EpollReactor reactor{1024};
Resolver resolver;
// Start service threads.
pthread_setname_np(pthread_self(), "main");

auto socks = socketpair(UnixStreamProtocol{});
DnsRequestHandler h{reactor, socks.second, nameserver};

ReactorRunner reactor_runner{reactor, "reactor"s};

char request_buf[40];
request_buf[0] = hostname.size();
memcpy(&request_buf[1], hostname.data(), hostname.size());
socks.first.send(request_buf, hostname.size() + 1, 0);

// Wait for termination.
SigWait sig_wait;
for (;;) {
switch (const auto sig = sig_wait()) {
case SIGHUP:
TOOLBOX_INFO << "received SIGHUP";
continue;
case SIGINT:
TOOLBOX_INFO << "received SIGINT";
break;
case SIGTERM:
TOOLBOX_INFO << "received SIGTERM";
break;
default:
TOOLBOX_INFO << "received signal: " << sig;
continue;
}
break;
}
ret = 0;
} catch (const std::exception& e) {
TOOLBOX_ERROR << "exception: " << e.what();
}
return ret;
}
6 changes: 2 additions & 4 deletions example/EchoClnt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ class EchoConn {
using AutoUnlinkOption = boost::intrusive::link_mode<boost::intrusive::auto_unlink>;

public:
EchoConn(CyclTime now, Reactor& r, IoSock&& sock, const StreamEndpoint& ep)
EchoConn(CyclTime now, Reactor& r, IoSock&& sock)
: sock_{move(sock)}
, ep_{ep}
{
sub_ = r.subscribe(sock_.get(), EventIn, bind<&EchoConn::on_input>(this));
tmr_ = r.timer(now.mono_time(), PingInterval, Priority::Low,
Expand Down Expand Up @@ -91,7 +90,6 @@ class EchoConn {
}
}
IoSock sock_;
const StreamEndpoint ep_;
Reactor::Handle sub_;
Buffer buf_;
Timer tmr_;
Expand Down Expand Up @@ -137,7 +135,7 @@ class EchoClnt : public StreamConnector<EchoClnt> {
inprogress_ = false;

// High performance TCP servers could use a custom allocator.
auto* const conn = new EchoConn{now, reactor_, move(sock), ep};
auto* const conn = new EchoConn{now, reactor_, move(sock)};
conn_list_.push_back(*conn);
}
void on_sock_connect_error(CyclTime now, const std::exception& e)
Expand Down
2 changes: 2 additions & 0 deletions toolbox/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ set(lib_SOURCES
net/McastSock.cpp
net/Protocol.cpp
net/Resolver.cpp
net/Resolver2.cpp
net/Runner.cpp
net/Socket.cpp
net/StreamAcceptor.cpp
Expand Down Expand Up @@ -218,6 +219,7 @@ set(test_SOURCES
net/Endpoint.ut.cpp
net/IoSock.ut.cpp
net/Resolver.ut.cpp
net/Resolver2.ut.cpp
net/Runner.ut.cpp
net/Socket.ut.cpp
sys/Date.ut.cpp
Expand Down
1 change: 1 addition & 0 deletions toolbox/net.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "net/McastSock.hpp"
#include "net/Protocol.hpp"
#include "net/Resolver.hpp"
#include "net/Resolver2.hpp"
#include "net/Runner.hpp"
#include "net/Socket.hpp"
#include "net/StreamAcceptor.hpp"
Expand Down
6 changes: 4 additions & 2 deletions toolbox/net/Error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
#ifndef TOOLBOX_NET_ERROR_HPP
#define TOOLBOX_NET_ERROR_HPP

#include <toolbox/Config.h>

#include <system_error>

namespace toolbox {
inline namespace net {

const std::error_category& gai_error_category() noexcept;
std::error_code make_gai_error_code(int err) noexcept;
TOOLBOX_API const std::error_category& gai_error_category() noexcept;
TOOLBOX_API std::error_code make_gai_error_code(int err) noexcept;

} // namespace net
} // namespace toolbox
Expand Down
Loading

0 comments on commit dbbc63b

Please sign in to comment.