|
#include <chrono>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <string.h>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <endian.hpp>
|
|
#include <network.hpp>
|
|
#include <array>
|
|
#include <thread>
|
|
#include <algorithm>
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
int main(int, char** argv){
|
|
int64_t offset=0;
|
|
std::array<int64_t, 4096> offsets;
|
|
std::array<int64_t, 4096> offsets_smooth;
|
|
std::array<int64_t, 4096> offset_variations;
|
|
size_t pos = 0;
|
|
int64_t max_offset_variation;
|
|
int64_t max_oscillation = 0;
|
|
int64_t min_ever = std::numeric_limits<int64_t>::max();
|
|
int64_t max_ever = 0;
|
|
|
|
std::stringstream ip_stream{argv[1]};
|
|
std::array<uint8_t, 4> ip;
|
|
std::string token;
|
|
std::getline(ip_stream, token, '.');
|
|
ip[0] = std::stoi(token);
|
|
std::getline(ip_stream, token, '.');
|
|
ip[1] = std::stoi(token);
|
|
std::getline(ip_stream, token, '.');
|
|
ip[2] = std::stoi(token);
|
|
std::getline(ip_stream, token, '.');
|
|
ip[3] = std::stoi(token);
|
|
|
|
uint16_t port = std::stoi(argv[2]);
|
|
|
|
|
|
auto soc = socket(AF_INET, SOCK_DGRAM, 0);
|
|
struct sockaddr_in server;
|
|
server.sin_family = AF_INET;
|
|
server.sin_addr.s_addr = *(in_addr_t*)ip.data();
|
|
server.sin_port = htons(port);
|
|
|
|
|
|
struct timeval tv;
|
|
tv.tv_sec = 5;
|
|
tv.tv_usec = 0;
|
|
setsockopt(soc, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
|
|
std::cerr << "Connecting..." <<std::endl;
|
|
connect(soc, (struct sockaddr*)&server, sizeof(server));
|
|
|
|
|
|
req_rep buffer;
|
|
|
|
uint64_t cnt = 0;
|
|
uint64_t old_time = 0;
|
|
|
|
while(true)
|
|
{
|
|
uint64_t tmp;
|
|
buffer.id = 16;
|
|
|
|
buffer.client_ts = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
|
send(soc, (void*)&buffer, (socklen_t)sizeof(req_rep), 0);
|
|
recv(soc, (void*)&buffer, (socklen_t)sizeof(req_rep), 0);
|
|
if(buffer.server_ts != old_time)
|
|
{
|
|
tmp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() - buffer.client_ts;
|
|
int64_t n_offset = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() - buffer.server_ts;
|
|
n_offset /= 2;
|
|
offset_variations[pos] = ((long long)(offset-n_offset));
|
|
if(cnt != 0)
|
|
{
|
|
offsets[pos] = n_offset;
|
|
} else {
|
|
offsets.fill(n_offset);
|
|
offsets_smooth.fill(n_offset);
|
|
}
|
|
max_offset_variation = std::max(*std::max_element(offset_variations.begin(), offset_variations.end()), std::abs((int64_t)*std::min_element(offset_variations.begin(), offset_variations.end())));
|
|
offset = (
|
|
7 * (std::accumulate(offsets_smooth.begin(), offsets_smooth.end(), 0)/offsets_smooth.size())
|
|
+ std::accumulate(offsets.begin(), offsets.end(), 0)/offsets.size()
|
|
) / 8;
|
|
offsets_smooth[pos] = offset;
|
|
pos=(pos+1)%offset_variations.size();
|
|
if(cnt > offsets.size()*2)
|
|
{
|
|
for(auto i : offsets_smooth)
|
|
for(auto j : offsets_smooth)
|
|
{
|
|
max_oscillation = std::max(
|
|
std::abs(i-j),
|
|
max_oscillation
|
|
);
|
|
}
|
|
min_ever = std::min(min_ever, offset);
|
|
max_ever = std::max(max_ever, offset);
|
|
}
|
|
else if (cnt < offsets.size()) {
|
|
offsets_smooth[pos] = n_offset;
|
|
}
|
|
old_time = buffer.server_ts;
|
|
std::cout << cnt << "\t"<< min_ever << "\t" << offset << "\t" << max_ever << "\t" << max_oscillation << "\t" << offset-n_offset << "\t" << max_offset_variation <<std::endl;
|
|
}
|
|
cnt++;
|
|
//std::this_thread::sleep_for(6ms);
|
|
}
|
|
}
|