Skip to content

Commit

Permalink
Added requested changes from PR #119 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
fysch authored Jul 29, 2023
1 parent c817964 commit 9fc0a87
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 48 deletions.
16 changes: 16 additions & 0 deletions docs/tools/socktap.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ You can choose via the `--link-layer` argument which implementation to use:
- *ethernet* runs on Linux raw packet sockets
- *cohda* employs Cohda's LLC API (optional)
- *udp* runs GeoNetworking on top of IP/UDP multicast sockets
- *tcp* runs GeoNetworking on top of IP/TCP sockets


### Ethernet

The *ethernet* variant has been initially *socktap*'s only available link-layer implementation.
In this mode, *socktap* will send and receiver Ethernet frames on the specified network interface (see `--interface` argument).

Expand All @@ -29,17 +32,30 @@ You can do this via `sudo setcap cap_net_raw+ep bin/socktap`.
When `CAP_NET_RAW` is attached to the *socktap* binary you can run it as an ordinary user.


### Cohda

If you have access to V2X hardware from Cohda Wireless, you can also run *socktap* on their units.
In the *cohda* mode, *socktap* uses Cohda's LLC API for sending and receiving data frames.
This mode is similar to *ethernet* but depends on the Cohda SDK.
Please refer to our [Cohda SDK building recipe](/recipes/cohda-sdk-build) for details.


### UDP

A relatively new addition is the *udp* mode, which allows running *socktap* without any privileges.
GeoNetworking packets are wrapped into UDP datagrams and sent to the IP multicast group **239.118.122.97** on UDP port **8947**.
Further *socktap* instances within the same IP multicast network exchange GeoNetworking packets then.
You can consider this as "GeoNetworking over IP/UDP".


### TCP

The TCP implementation is similiar to the UDP one.
However, TCP adds the arguments `--tcp-accept` and `--tcp-connect`, which allow the user to accept incoming TCP connections or connect to open TCP sockets, respectively.
Both arguments expect a comma separated list of `ip:port`.
Outgoing GeoNetworking packets will then be sent to all active TCP connections.


## Positioning

Many components of an ITS-G5 system depend on positioning data.
Expand Down
51 changes: 39 additions & 12 deletions tools/socktap/link_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,41 @@
#include "udp_link.hpp"
#include <vanetza/access/ethertype.hpp>
#include <boost/asio/generic/raw_protocol.hpp>
#include <iostream>

#ifdef SOCKTAP_WITH_COHDA_LLC
# include "cohda_link.hpp"
#endif

boost::optional<std::pair<boost::asio::ip::address, unsigned short>> parse_ip_port(const std::string& ip_port)
{
using opt_ip_port = boost::optional<std::pair<boost::asio::ip::address, unsigned short>>;

std::size_t ip_len = ip_port.find_last_of(":");
if (ip_len == std::string::npos) {
// error: port not found
std::cerr << "[" << ip_port << "] Missing port." << std::endl;
return opt_ip_port();
}

std::size_t port = std::strtoul(ip_port.substr(ip_len + 1).c_str(), NULL, 10);
if (port < 1 || port > 65535) {
// error: port out of range
std::cerr << "[" << ip_port << "] Port " << port << " out of range (1-65535)." << std::endl;
return opt_ip_port();
}

boost::system::error_code ec;
boost::asio::ip::address ip = boost::asio::ip::address::from_string(ip_port.substr(0, ip_len), ec);
if (ec) {
// error: IP-address invalid
std::cerr << "[" << ip_port << "] Invalid IP-address: " << ec.message() << std::endl;
return opt_ip_port();
}

return opt_ip_port({ip, port});
}

std::unique_ptr<LinkLayer>
create_link_layer(boost::asio::io_service& io_service, const EthernetDevice& device, const std::string& name, const boost::program_options::variables_map& vm)
{
Expand All @@ -30,29 +60,26 @@ create_link_layer(boost::asio::io_service& io_service, const EthernetDevice& dev
namespace ip = boost::asio::ip;
ip::udp::endpoint multicast(ip::address::from_string("239.118.122.97"), 8947);
link_layer.reset(new UdpLink { io_service, multicast });
} else if (name.substr(0, 3) == "tcp") {
} else if (name == "tcp") {
namespace ip = boost::asio::ip;

TcpLink* tcp = new TcpLink { io_service };

std::string tcp_ip;
unsigned short tcp_port, tcp_ip_len;

if (vm.count("tcp-connect")) {
for (const std::string& ip_port : vm["tcp-connect"].as<std::vector<std::string>>()) {
tcp_ip_len = ip_port.find(":");
tcp_ip = ip_port.substr(0, tcp_ip_len);
tcp_port = std::stoi(ip_port.substr(tcp_ip_len + 1));
tcp->connect({ip::address::from_string(tcp_ip), tcp_port});
auto ip_port_pair = parse_ip_port(ip_port);
if (ip_port_pair.has_value()) {
tcp->connect(ip::tcp::endpoint(ip_port_pair.value().first, ip_port_pair.value().second));
}
}
}

if (vm.count("tcp-accept")) {
for (const std::string& ip_port : vm["tcp-accept"].as<std::vector<std::string>>()) {
tcp_ip_len = ip_port.find(":");
tcp_ip = ip_port.substr(0, tcp_ip_len);
tcp_port = std::stoi(ip_port.substr(tcp_ip_len + 1));
tcp->accept({ip::address::from_string(tcp_ip), tcp_port});
auto ip_port_pair = parse_ip_port(ip_port);
if (ip_port_pair.has_value()) {
tcp->accept(ip::tcp::endpoint(ip_port_pair.value().first, ip_port_pair.value().second));
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions tools/socktap/link_layer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vanetza/net/cohesive_packet.hpp>
#include <vanetza/net/ethernet_header.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <memory>
Expand All @@ -24,6 +25,8 @@ class LinkLayer : public vanetza::access::Interface, public LinkLayerIndication
{
};

boost::optional<std::pair<boost::asio::ip::address, unsigned short>> parse_ip_port(const std::string& ip_port);

std::unique_ptr<LinkLayer>
create_link_layer(boost::asio::io_service&, const EthernetDevice&, const std::string& name, const boost::program_options::variables_map& vm);

Expand Down
51 changes: 20 additions & 31 deletions tools/socktap/tcp_link.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include "tcp_link.hpp"
#include <vanetza/access/data_request.hpp>
#include <vanetza/net/ethernet_header.hpp>
#include <boost/asio/ip/multicast.hpp>
#include <boost/bind.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>

namespace ip = boost::asio::ip;
Expand All @@ -14,16 +13,6 @@ TcpLink::TcpLink(boost::asio::io_service& io_service) :

}

TcpLink::~TcpLink()
{
for (auto &ts : sockets_) {
delete ts;
}
for (auto &acceptor : acceptors_) {
delete acceptor.second;
}
}

void TcpLink::indicate(IndicationCallback cb)
{
callback_ = cb;
Expand All @@ -40,11 +29,11 @@ void TcpLink::request(const access::DataRequest& request, std::unique_ptr<ChunkP
const_buffers[index] = boost::asio::buffer(tx_buffers_[index]);
}

std::list<TcpSocket*>::iterator i = sockets_.begin();
std::list<TcpSocket>::iterator i = sockets_.begin();

while (i != sockets_.end()) {
if ((*i)->connected()) {
(*i)->request(const_buffers);
if ((*i).connected()) {
(*i).request(const_buffers);
i++;
} else {
sockets_.erase(i++);
Expand All @@ -55,38 +44,40 @@ void TcpLink::request(const access::DataRequest& request, std::unique_ptr<ChunkP

void TcpLink::connect(ip::tcp::endpoint ep)
{
TcpSocket* ts = new TcpSocket(*io_service_, callback_);
ts->connect(ep);
sockets_.push_back(ts);
TcpSocket ts(*io_service_, callback_);
ts.connect(ep);
sockets_.push_back(std::move(ts));
}

void TcpLink::accept(ip::tcp::endpoint ep)
{
if (!acceptors_[ep]) {
acceptors_[ep] = new ip::tcp::acceptor(*io_service_, ep);

if (acceptors_.count(ep) == 0) {
acceptors_.find(ep)->second = ip::tcp::acceptor(*io_service_, ep);
}

TcpSocket* ts = new TcpSocket(*io_service_, callback_);
TcpSocket ts(*io_service_, callback_);
boost::system::error_code ec;
std::cout << "Accept connetions at " << ep.address().to_string() << ":" << ep.port() << std::endl;

acceptors_[ep]->async_accept(
ts->socket(),
acceptors_.find(ep)->second.async_accept(
ts.socket(),
boost::bind(
&TcpLink::accept_handler,
this,
ec,
ts,
boost::ref(ts),
ep
)
);

}

void TcpLink::accept_handler(boost::system::error_code& ec, TcpSocket* ts, ip::tcp::endpoint ep)
void TcpLink::accept_handler(boost::system::error_code& ec, TcpSocket& ts, ip::tcp::endpoint ep)
{
sockets_.push_back(ts);
ts->do_receive();
ts->connected(true);
sockets_.push_back(std::move(ts));
ts.do_receive();
ts.connected(true);
accept(ep);
}

Expand Down Expand Up @@ -138,7 +129,7 @@ void TcpSocket::do_receive()
packet.set_boundary(OsiLayer::Link, EthernetHeader::length_bytes);
auto link_range = packet[OsiLayer::Link];
EthernetHeader eth = decode_ethernet_header(link_range.begin(), link_range.end());
if (callback_) {
if (*callback_) {
(*callback_)(std::move(packet), eth);
}
}
Expand All @@ -165,5 +156,3 @@ void TcpSocket::connected(bool b)
is_connected_ = b;
}



11 changes: 6 additions & 5 deletions tools/socktap/tcp_link.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include "link_layer.hpp"
#include <vanetza/common/byte_buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <array>
#include <list>

Expand All @@ -29,6 +29,7 @@ class TcpSocket
private:

bool is_connected_;
bool err_ = false;
boost::asio::io_service* io_service_;
boost::asio::ip::tcp::endpoint endpoint_;
boost::asio::ip::tcp::socket socket_;
Expand All @@ -42,17 +43,17 @@ class TcpLink : public LinkLayer
{
public:
TcpLink(boost::asio::io_service&);
~TcpLink();

void indicate(IndicationCallback) override;
void request(const vanetza::access::DataRequest&, std::unique_ptr<vanetza::ChunkPacket>) override;
void connect(boost::asio::ip::tcp::endpoint);
void accept(boost::asio::ip::tcp::endpoint);
void accept_handler(boost::system::error_code& ec, TcpSocket* ts, boost::asio::ip::tcp::endpoint ep);
void accept_handler(boost::system::error_code& ec, TcpSocket& ts, boost::asio::ip::tcp::endpoint ep);

private:
std::list<TcpSocket*> sockets_;
std::map<boost::asio::ip::tcp::endpoint, boost::asio::ip::tcp::acceptor*> acceptors_;
std::list<TcpSocket> sockets_;
// std::map<boost::asio::ip::tcp::endpoint, boost::asio::ip::tcp::acceptor*> acceptors_;
std::map<boost::asio::ip::tcp::endpoint, boost::asio::ip::tcp::acceptor> acceptors_;
IndicationCallback callback_;
boost::asio::io_service* io_service_;
std::array<vanetza::ByteBuffer, layers_> tx_buffers_;
Expand Down

0 comments on commit 9fc0a87

Please sign in to comment.