-
Notifications
You must be signed in to change notification settings - Fork 0
/
measurement_client.h
137 lines (106 loc) · 4.43 KB
/
measurement_client.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#ifndef MEASUREMENT_CLIENT_H
#define MEASUREMENT_CLIENT_H
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <endian.h>
#include "common.h"
#include "get_time_usec.h"
#include "mdns_client.h"
#include "telnet_server.h"
#include "server.h"
#include "mdns_message.h"
/* ze strony http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/examples/cpp03_examples.html */
#include "ipv4_header.hpp"
#include "icmp_header.hpp"
using boost::asio::ip::udp;
using boost::asio::ip::tcp;
using boost::asio::ip::icmp;
/* Centralna klasa pomiarów opóźnień. Zawiera klienta mDNS i serwer telnetu.
* Jest odowiedzialna za odbieranie pakietów UDP i ICMP oraz delegowanie
* ich do odpowiednich instancji klasy Server w mapie 'servers'. */
class MeasurementClient {
public:
MeasurementClient(boost::asio::io_service& io_service, int udp_port, int ui_port,
int measurement_interval, int mdns_interval, float ui_refresh_interval) :
timer(io_service, boost::posix_time::seconds(0)),
recv_buffer(),
recv_stream(&recv_buffer),
udp_socket(new udp::socket(io_service, udp::v4())),
icmp_socket(new icmp::socket(io_service, icmp::v4())),
servers(new servers_map),
mdns_client(io_service, servers, udp_socket, icmp_socket, mdns_interval),
telnet_server(io_service, servers, ui_port, ui_refresh_interval) {
start_udp_receiving();
start_icmp_receiving();
init_measurements();
}
private:
/* Inicjuje wysłanie pakietów rozpoczynających pomiar do wszystkich serwerów. */
void init_measurements() {
for (auto it = servers->begin(); it != servers->end(); ++it) {
it->second.send_queries();
}
reset_timer(MEASUREMENT_INTERVAL_DEFAULT);
}
/* słuchanie na wspólnym porcie UDP. */
void start_udp_receiving() {
udp_socket->async_receive_from(boost::asio::buffer(time_buffer), remote_udp_endpoint,
boost::bind(&MeasurementClient::handle_udp_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_udp_receive(boost::system::error_code const& error,
std::size_t bytes_transferred) {
if (!error && bytes_transferred >= sizeof(uint64_t)) {
time_type end_time = get_time_usec();
auto it = servers->find(remote_udp_endpoint.address());
if (it != servers->end()) { // else ignoruj pakiet
it->second.receive_udp_query(be64toh(time_buffer[0]), end_time);
}
}
start_udp_receiving();
}
/* słuchanie na wspólnym porcie ICMP. */
void start_icmp_receiving() {
recv_buffer.consume(recv_buffer.size());
icmp_socket->async_receive(recv_buffer.prepare(BUFFER_SIZE),
boost::bind(&MeasurementClient::handle_icmp_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_icmp_receive(boost::system::error_code const& error,
std::size_t bytes_transferred) {
if (!error) {
time_type end_time = get_time_usec();
recv_buffer.commit(bytes_transferred);
ipv4_header ipv4_hdr;
icmp_header icmp_hdr;
recv_stream >> ipv4_hdr >> icmp_hdr;
if (recv_stream && icmp_hdr.type() == icmp_header::echo_reply
&& icmp_hdr.identifier() == 0) {
int seq_num = icmp_hdr.sequence_number(); // numer sekwencyjny jako id pakietu
auto it = servers->find(ipv4_hdr.source_address());
if (it != servers->end()) { // else ignoruj pakiet
it->second.receive_icmp_query(seq_num, end_time);
}
}
}
start_icmp_receiving();
}
/* Ustawia timer na czas późiejszy o 'seconds' sekund względem poprzedniego czasu. */
void reset_timer(int seconds) {
timer.expires_at(timer.expires_at() + boost::posix_time::seconds(seconds));
timer.async_wait(boost::bind(&MeasurementClient::init_measurements, this));
}
boost::asio::deadline_timer timer;
boost::array<uint64_t, 1> time_buffer; // bufor do obierania czasu
boost::asio::streambuf recv_buffer; // bufor do odbierania
std::istream recv_stream; // strumień do odbierania
std::shared_ptr<udp::socket> udp_socket; // gniazdo używane do wszystkich pakietów UDP
std::shared_ptr<icmp::socket> icmp_socket; // gniazdo używane do wszystkich pakietów ICMP
udp::endpoint remote_udp_endpoint;
servers_ptr servers;
MdnsClient mdns_client;
TelnetServer telnet_server;
};
#endif // MEASUREMENT_CLIENT_H