genode/repos/os/src/server/nic_router/link.cc

238 lines
5.5 KiB
C++

/*
* \brief State tracking for UDP/TCP connections
* \author Martin Stein
* \date 2016-08-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <net/tcp.h>
/* local includes */
#include <link.h>
#include <interface.h>
#include <configuration.h>
#include <protocol_name.h>
using namespace Net;
using namespace Genode;
/******************
** Link_side_id **
******************/
constexpr size_t Link_side_id::data_size()
{
return sizeof(src_ip) + sizeof(src_port) +
sizeof(dst_ip) + sizeof(dst_port);
}
bool Link_side_id::operator == (Link_side_id const &id) const
{
return memcmp(id.data, data, data_size()) == 0;
}
bool Link_side_id::operator > (Link_side_id const &id) const
{
return memcmp(id.data, data, data_size()) > 0;
}
/***************
** Link_side **
***************/
Link_side::Link_side(Interface &interface,
Link_side_id const &id,
Link &link)
:
_interface(interface), _id(id), _link(link)
{ }
Link_side const &Link_side::find_by_id(Link_side_id const &id) const
{
if (id == _id) {
return *this; }
bool const side = id > _id;
Link_side *const link_side = Avl_node<Link_side>::child(side);
if (!link_side) {
throw Link_side_tree::No_match(); }
return link_side->find_by_id(id);
}
void Link_side::print(Output &output) const
{
Genode::print(output, "src ", src_ip(), ":", src_port(),
" dst ", dst_ip(), ":", dst_port());
}
bool Link_side::is_client() const
{
return this == &_link.client();
}
/********************
** Link_side_tree **
********************/
Link_side const &Link_side_tree::find_by_id(Link_side_id const &id) const
{
Link_side *const link_side = first();
if (!link_side) {
throw No_match(); }
return link_side->find_by_id(id);
}
/**********
** Link **
**********/
void Link::print(Output &output) const
{
Genode::print(output, "CLN ", _client, " SRV ", _server);
}
Link::Link(Interface &cln_interface,
Link_side_id const &cln_id,
Pointer<Port_allocator_guard> const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
Genode::Timer &timer,
Configuration &config,
uint8_t const protocol)
:
_config(config),
_client(cln_interface, cln_id, *this),
_server_port_alloc(srv_port_alloc),
_server(srv_interface, srv_id, *this),
_close_timeout(timer, *this, &Link::_handle_close_timeout),
_close_timeout_us(_config.rtt_sec() * 2 * 1000 * 1000),
_protocol(protocol)
{
_close_timeout.start(_close_timeout_us);
}
void Link::_handle_close_timeout(Genode::Timer::Microseconds)
{
dissolve();
_client._interface.link_closed(*this, _protocol);
}
void Link::dissolve()
{
_client._interface.dissolve_link(_client, _protocol);
_server._interface.dissolve_link(_server, _protocol);
if (_config.verbose()) {
log("Dissolve ", protocol_name(_protocol), " link: ", *this); }
try {
_server_port_alloc.deref().free(_server.dst_port());
if (_config.verbose()) {
log("Free ", protocol_name(_protocol),
" port ", _server.dst_port(),
" at ", _server.interface(),
" that was used by ", _client.interface());
}
}
catch (Pointer<Port_allocator_guard>::Invalid) { }
}
/**************
** Tcp_link **
**************/
Tcp_link::Tcp_link(Interface &cln_interface,
Link_side_id const &cln_id,
Pointer<Port_allocator_guard> const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
Genode::Timer &timer,
Configuration &config,
uint8_t const protocol)
:
Link(cln_interface, cln_id, srv_port_alloc, srv_interface, srv_id, timer,
config, protocol)
{ }
void Tcp_link::_fin_acked()
{
if (_server_fin_acked && _client_fin_acked) {
_close_timeout.start(_close_timeout_us);
_closed = true;
}
}
void Tcp_link::server_packet(Tcp_packet &tcp)
{
if (_closed) {
return; }
if (tcp.fin()) {
_server_fin = true; }
if (tcp.ack() && _client_fin) {
_client_fin_acked = true;
_fin_acked();
}
if (!_closed) {
_packet(); }
}
void Tcp_link::client_packet(Tcp_packet &tcp)
{
if (_closed) {
return; }
if (tcp.fin()) {
_client_fin = true; }
if (tcp.ack() && _server_fin) {
_server_fin_acked = true;
_fin_acked();
}
if (!_closed) {
_packet(); }
}
/**************
** Udp_link **
**************/
Udp_link::Udp_link(Interface &cln_interface,
Link_side_id const &cln_id,
Pointer<Port_allocator_guard> const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
Genode::Timer &timer,
Configuration &config,
uint8_t const protocol)
:
Link(cln_interface, cln_id, srv_port_alloc, srv_interface, srv_id, timer,
config, protocol)
{ }