Skip to content

Commit da893aa

Browse files
net: Extracted Port_util from TCP to net namespace
1 parent e10a011 commit da893aa

3 files changed

Lines changed: 140 additions & 109 deletions

File tree

api/net/port_util.hpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#pragma once
19+
#ifndef NET_PORT_UTIL_HPP
20+
#define NET_PORT_UTIL_HPP
21+
22+
#include "inet_common.hpp"
23+
#include <bitset>
24+
25+
namespace net {
26+
27+
struct Port_error : public std::runtime_error {
28+
using base = std::runtime_error;
29+
using base::base;
30+
};
31+
32+
/**
33+
* @brief Class for port utility.
34+
*/
35+
class Port_util {
36+
public:
37+
/**
38+
* @brief Construct a port util with a new generated ephemeral port
39+
* and a empty port list.
40+
*/
41+
Port_util()
42+
: ports(),
43+
ephemeral_(net::new_ephemeral_port()),
44+
eph_count(0)
45+
{
46+
ports.set(port_ranges::DYNAMIC_END);
47+
}
48+
49+
/**
50+
* @brief Gets the next ephemeral port.
51+
* increment_ephemeral may throw
52+
*
53+
* @return The next ephemeral port.
54+
*/
55+
uint16_t get_next_ephemeral()
56+
{
57+
increment_ephemeral();
58+
return ephemeral_;
59+
}
60+
61+
/**
62+
* @brief Bind a port, making it reserved.
63+
*
64+
* @param[in] port The port
65+
*/
66+
void bind(const uint16_t port) noexcept
67+
{
68+
Expects(port < port_ranges::DYNAMIC_END);
69+
ports.set(port);
70+
71+
if(port_ranges::is_dynamic(port)) ++eph_count;
72+
}
73+
74+
/**
75+
* @brief Unbind a port, making it available.
76+
*
77+
* @param[in] port The port
78+
*/
79+
void unbind(const uint16_t port) noexcept
80+
{
81+
Expects(port < port_ranges::DYNAMIC_END);
82+
ports.reset(port);
83+
84+
if(port_ranges::is_dynamic(port)) --eph_count;
85+
}
86+
87+
/**
88+
* @brief Determines if the port is bound.
89+
*
90+
* @param[in] port The port
91+
*
92+
* @return True if bound, False otherwise.
93+
*/
94+
bool is_bound(const uint16_t port) const noexcept
95+
{
96+
Expects(port < port_ranges::DYNAMIC_END);
97+
return ports[port];
98+
}
99+
100+
/**
101+
* @brief Determines if it has any free ephemeral ports.
102+
*
103+
* @return True if has free ephemeral, False otherwise.
104+
*/
105+
bool has_free_ephemeral() const noexcept
106+
{ return eph_count < (port_ranges::DYNAMIC_END - port_ranges::DYNAMIC_START); }
107+
108+
private:
109+
std::bitset<65536> ports;
110+
uint16_t ephemeral_;
111+
uint16_t eph_count;
112+
113+
/**
114+
* @brief Increment the ephemeral port by one.
115+
* Throws if there are no more free ephemeral ports available.
116+
*/
117+
void increment_ephemeral()
118+
{
119+
if(UNLIKELY( not has_free_ephemeral() ))
120+
throw Port_error{"All ephemeral ports are taken"};
121+
122+
ephemeral_++;
123+
124+
// wrap around to dynamic start if end
125+
if(UNLIKELY(ephemeral_ == port_ranges::DYNAMIC_END))
126+
ephemeral_ = port_ranges::DYNAMIC_START;
127+
128+
// TODO: Avoid wrap around, increment ephemeral to next free port.
129+
// while(is_bound(ephemeral_)) ++ephemeral_; // worst case is like 16k iterations :D
130+
// need a solution that checks each word of the subset (the dynamic range)
131+
// FIXME: this may happen...
132+
if(UNLIKELY( is_bound(ephemeral_) ))
133+
throw Port_error{"Generated ephemeral port is already bound. Please fix me!"};
134+
}
135+
}; // < class Port_util
136+
137+
} // < namespace net
138+
139+
#endif

api/net/tcp/tcp.hpp

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include <queue> // writeq
3030
#include <net/inet.hpp>
3131
#include <net/socket.hpp>
32-
#include <bitset>
32+
#include <net/port_util.hpp>
3333

3434
namespace net {
3535

@@ -54,89 +54,6 @@ namespace net {
5454
private:
5555
using Listeners = std::map<Socket, std::unique_ptr<tcp::Listener>>;
5656
using Connections = std::map<tcp::Connection::Tuple, tcp::Connection_ptr>;
57-
58-
/**
59-
* @brief Class for port utility.
60-
*/
61-
class Port_util {
62-
public:
63-
/**
64-
* @brief Construct a port util with a new generated ephemeral port
65-
* and a empty port list.
66-
*/
67-
Port_util();
68-
69-
/**
70-
* @brief Gets the next ephemeral port.
71-
* increment_ephemeral may throw
72-
*
73-
* @return The next ephemeral port.
74-
*/
75-
uint16_t get_next_ephemeral()
76-
{
77-
increment_ephemeral();
78-
return ephemeral_;
79-
}
80-
81-
/**
82-
* @brief Bind a port, making it reserved.
83-
*
84-
* @param[in] port The port
85-
*/
86-
void bind(const uint16_t port) noexcept
87-
{
88-
Expects(port < port_ranges::DYNAMIC_END);
89-
ports.set(port);
90-
91-
if(port_ranges::is_dynamic(port)) ++eph_count;
92-
}
93-
94-
/**
95-
* @brief Unbind a port, making it available.
96-
*
97-
* @param[in] port The port
98-
*/
99-
void unbind(const uint16_t port) noexcept
100-
{
101-
Expects(port < port_ranges::DYNAMIC_END);
102-
ports.reset(port);
103-
104-
if(port_ranges::is_dynamic(port)) --eph_count;
105-
}
106-
107-
/**
108-
* @brief Determines if the port is bound.
109-
*
110-
* @param[in] port The port
111-
*
112-
* @return True if bound, False otherwise.
113-
*/
114-
bool is_bound(const uint16_t port) const noexcept
115-
{
116-
Expects(port < port_ranges::DYNAMIC_END);
117-
return ports[port];
118-
}
119-
120-
/**
121-
* @brief Determines if it has any free ephemeral ports.
122-
*
123-
* @return True if has free ephemeral, False otherwise.
124-
*/
125-
bool has_free_ephemeral() const noexcept
126-
{ return eph_count < (port_ranges::DYNAMIC_END - port_ranges::DYNAMIC_START); }
127-
128-
private:
129-
std::bitset<65536> ports;
130-
uint16_t ephemeral_;
131-
uint16_t eph_count;
132-
133-
/**
134-
* @brief Increment the ephemeral port by one.
135-
* Throws if there are no more free ephemeral ports available.
136-
*/
137-
void increment_ephemeral();
138-
139-
}; // < class Port_util
14057
using Port_lists = std::map<tcp::Address, Port_util>;
14158

14259
public:

src/net/tcp/tcp.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,31 +79,6 @@ void TCP::smp_process_writeq(size_t packets)
7979
SMP::signal(this->cpu_id);
8080
}
8181

82-
TCP::Port_util::Port_util()
83-
: ports{},
84-
ephemeral_(new_ephemeral_port()),
85-
eph_count(0)
86-
{
87-
ports.set(port_ranges::DYNAMIC_END);
88-
}
89-
90-
void TCP::Port_util::increment_ephemeral()
91-
{
92-
if(UNLIKELY(! has_free_ephemeral() ))
93-
throw TCP_error{"All ephemeral ports are taken"};
94-
95-
ephemeral_++;
96-
97-
if(UNLIKELY(ephemeral_ == port_ranges::DYNAMIC_END))
98-
ephemeral_ = port_ranges::DYNAMIC_START;
99-
100-
// TODO: Avoid wrap around, increment ephemeral to next free port.
101-
// while(is_bound(ephemeral_)) ++ephemeral_; // worst case is like 16k iterations :D
102-
// need a solution that checks each word of the subset (the dynamic range)
103-
// FIXME: this may happen...
104-
Ensures(is_bound(ephemeral_) == false && "Hoped I wouldn't see the day...");
105-
}
106-
10782
/*
10883
Note: There is different approaches to how to handle listeners & connections.
10984
Need to discuss and decide for the best one.

0 commit comments

Comments
 (0)