1#include "InetAddress.h"
2#include "Socket.h"
3
4#include <thread>
5
6#include <stdio.h>
7#include <string.h>
8#include <sys/time.h>
9#include <unistd.h>
10
11const int g_port = 3123;
12
13struct Message
14{
15  int64_t request;
16  int64_t response;
17} __attribute__ ((__packed__));
18
19static_assert(sizeof(Message) == 16, "Message size should be 16 bytes");
20
21int64_t now()
22{
23  struct timeval tv = { 0, 0 };
24  gettimeofday(&tv, NULL);
25  return tv.tv_sec * int64_t(1000000) + tv.tv_usec;
26}
27
28void runServer(bool ipv6)
29{
30  Socket sock(Socket::createUDP(ipv6 ? AF_INET6 : AF_INET));
31  sock.bindOrDie(InetAddress(g_port, ipv6));
32
33  while (true)
34  {
35    Message message = { 0, 0 };
36
37    struct sockaddr_storage peerAddr;
38    bzero(&peerAddr, sizeof peerAddr);
39    socklen_t addrLen = sizeof peerAddr;
40    struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&peerAddr);
41
42    ssize_t nr = ::recvfrom(sock.fd(), &message, sizeof message, 0, addr, &addrLen);
43    if (nr == sizeof message)
44    {
45      message.response = now();
46      ssize_t nw = ::sendto(sock.fd(), &message, sizeof message, 0, addr, addrLen);
47      if (nw < 0)
48      {
49        perror("send Message");
50      }
51      else if (nw != sizeof message)
52      {
53        printf("sent message of %zd bytes, expect %zd bytes.\n", nw, sizeof message);
54      }
55    }
56    else if (nr < 0)
57    {
58      perror("recv Message");
59    }
60    else
61    {
62      printf("received message of %zd bytes, expect %zd bytes.\n", nr, sizeof message);
63    }
64  }
65}
66
67void runClient(const char* server_hostname)
68{
69  InetAddress serverAddr;
70  if (!InetAddress::resolve(server_hostname, g_port, &serverAddr))
71  {
72    printf("Unable to resolve %s\n", server_hostname);
73    return;
74  }
75
76  Socket sock(Socket::createUDP(serverAddr.family()));
77
78  if (sock.connect(serverAddr) != 0)
79  {
80    perror("connect to server");
81    return;
82  }
83
84  std::thread thr([&sock] () {
85    while (true)
86    {
87      Message message = { 0, 0 };
88      message.request = now();
89      int nw = sock.send(&message, sizeof message);
90      if (nw < 0)
91      {
92        perror("send Message");
93      }
94      else if (nw != sizeof message)
95      {
96        printf("sent message of %d bytes, expect %zd bytes.\n", nw, sizeof message);
97      }
98
99      ::usleep(200*1000);
100    }
101  });
102
103  while (true)
104  {
105    Message message = { 0, 0 };
106    int nr = sock.recv(&message, sizeof message);
107    if (nr == sizeof message)
108    {
109      int64_t back = now();
110      int64_t mine = (back + message.request) / 2;
111      printf("now %jd, round trip time %jd us, clock error %jd us\n",
112             back, back - message.request, message.response - mine);
113    }
114    else if (nr < 0)
115    {
116      perror("recv Message");
117    }
118    else
119    {
120      printf("received message of %d bytes, expect %zd bytes.\n", nr, sizeof message);
121    }
122  }
123}
124
125int main(int argc, const char* argv[])
126{
127  if (argc < 2)
128  {
129    printf("Usage:\nServer: %s -s [-6]\nClient: %s server_hostname\n", argv[0], argv[0]);
130    return 0;
131  }
132
133  if (strcmp(argv[1], "-s") == 0)
134  {
135    bool ipv6 = argc > 2 ? strcmp(argv[2], "-6") == 0 : false;
136    runServer(ipv6);
137  }
138  else
139  {
140    runClient(argv[1]);
141  }
142}
143