pep.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #define _GNU_SOURCE
  2. #include <sys/timerfd.h>
  3. #include <sys/epoll.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netdb.h>
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <errno.h>
  11. #include <inttypes.h>
  12. #include <linux/tcp.h>
  13. enum event_id {
  14. TIMER,
  15. DATA_IN,
  16. };
  17. const int loop_period_ns = 100 * 1000;
  18. #define MAX_EPOLL_EVENTS 2
  19. int server(struct addrinfo *result) {
  20. int ret, msg_len, lfd, fd, one = 1, tfd, efd, n;
  21. struct addrinfo *rp;
  22. struct sockaddr addr = { 0 };
  23. socklen_t addrlen = sizeof(addr);
  24. struct timespec ts = { 0 };
  25. struct itimerspec timer = {
  26. .it_interval = { .tv_nsec = loop_period_ns },
  27. .it_value = { },
  28. };
  29. struct epoll_event events[MAX_EPOLL_EVENTS] = { { 0 } };
  30. int i, j;
  31. char msg[512];
  32. uint64_t timer_buf;
  33. struct tcp_info tcp_info = { 0 };
  34. socklen_t tcp_info_len = sizeof(tcp_info);
  35. for (rp = result; rp != NULL; rp = rp->ai_next) {
  36. lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  37. if (lfd != -1) {
  38. if (bind(lfd, rp->ai_addr, rp->ai_addrlen) != 0) {
  39. fprintf(stderr, "bind() failed: %m.\n");
  40. close(lfd);
  41. }
  42. else {
  43. break;
  44. }
  45. }
  46. else {
  47. fprintf(stderr, "socket() failed: %m.\n");
  48. }
  49. }
  50. if (rp == NULL) {
  51. fprintf(stderr, "Could not establish server.\n");
  52. return -1;
  53. }
  54. freeaddrinfo(result);
  55. ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  56. if (ret == -1) {
  57. fprintf(stderr, "Could not setsockopt(SO_REUSEADDR): %m.\n");
  58. return -1;
  59. }
  60. ret = listen(lfd, 0);
  61. if (ret == -1) {
  62. fprintf(stderr, "Could not listen(): %m.\n");
  63. return -1;
  64. }
  65. fd = accept4(lfd, &addr, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
  66. if (fd == -1) {
  67. fprintf(stderr, "Could not accept(): %m.\n");
  68. return -1;
  69. }
  70. tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
  71. if (ret == -1) {
  72. fprintf(stderr, "Could not timerfd_create(): %m.\n");
  73. return -1;
  74. }
  75. ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  76. if (ret == -1) {
  77. fprintf(stderr, "Could not clock_gettime(): %m.\n");
  78. return -1;
  79. }
  80. timer.it_value.tv_sec = ts.tv_sec + 1;
  81. ret = timerfd_settime(tfd, TFD_TIMER_ABSTIME, &timer, NULL);
  82. if (ret == -1) {
  83. fprintf(stderr, "Could not timerfd_settime(): %m.\n");
  84. return -1;
  85. }
  86. efd = epoll_create1(EPOLL_CLOEXEC);
  87. if (efd == -1) {
  88. fprintf(stderr, "Could not epoll_create1(): %m.\n");
  89. return -1;
  90. }
  91. events[0].events = EPOLLIN | EPOLLRDHUP;
  92. events[0].data.u32 = TIMER;
  93. ret = epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &(events[0]));
  94. if (ret == -1) {
  95. fprintf(stderr, "Could not epoll_ctl(EPOLL_CTL_ADD, tfd): %m.\n");
  96. return -1;
  97. }
  98. events[0].events = EPOLLIN | EPOLLRDHUP;
  99. events[0].data.u32 = DATA_IN;
  100. ret = epoll_ctl(efd, EPOLL_CTL_ADD, fd, &(events[0]));
  101. if (ret == -1) {
  102. fprintf(stderr, "Could not epoll_ctl(EPOLL_CTL_ADD, tfd): %m.\n");
  103. return -1;
  104. }
  105. uint64_t bytes_acked = 0;
  106. int data_received = 0;
  107. int received_data, received_ack;
  108. j = 0;
  109. /* TODO: handle ERR, HUP and RDHUP for all file descriptor kinds. */
  110. while ((n = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1))) {
  111. ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  112. if (ret == -1) {
  113. fprintf(stderr, "Could not clock_gettime(): %m.\n");
  114. return -1;
  115. }
  116. received_data = 0;
  117. received_ack = 0;
  118. for (i = 0; i < n; i++) {
  119. switch (events[i].data.u32) {
  120. case TIMER:
  121. j++;
  122. ret = read(tfd, &timer_buf, sizeof(timer_buf));
  123. if (ret == -1) {
  124. fprintf(stderr, "Could not read timer infos: %m.\n");
  125. return -1;
  126. }
  127. ret = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &tcp_info_len);
  128. if (ret == -1) {
  129. fprintf(stderr, "Could not get struct tcp_info: %m.\n");
  130. return -1;
  131. }
  132. if (tcp_info.tcpi_bytes_acked != bytes_acked) {
  133. bytes_acked = tcp_info.tcpi_bytes_acked;
  134. received_ack = 1;
  135. }
  136. if ((j % (1000 * 1000 * 1000 / loop_period_ns)) == 0) {
  137. j = 0;
  138. ret = snprintf(msg, sizeof(msg),
  139. "%" PRIu64 ".%09ld: %03d\n",
  140. ts.tv_sec, ts.tv_nsec, j);
  141. if ((ret < 0) || ((size_t) ret >= sizeof(msg))) {
  142. fprintf(stderr,
  143. "Could not write message in full: needed %d bytes.",
  144. ret);
  145. return -1;
  146. }
  147. msg_len = ret;
  148. fprintf(stdout, "Sending message: %s", msg);
  149. fflush(stdout);
  150. errno = 0;
  151. ret = send(fd, msg, msg_len, 0);
  152. if (ret != msg_len) {
  153. fprintf(stderr, "Could not send message in full: %m.\n");
  154. }
  155. }
  156. break;
  157. case DATA_IN:
  158. ret = read(fd, &msg, sizeof(msg));
  159. if (ret == -1) {
  160. fprintf(stderr, "Could not read data: %m.\n");
  161. return -1;
  162. }
  163. data_received += ret;
  164. received_data = 1;
  165. j++;
  166. ret = read(tfd, &timer_buf, sizeof(timer_buf));
  167. if (ret == -1) {
  168. fprintf(stderr, "Could not read timer infos: %m.\n");
  169. return -1;
  170. }
  171. ret = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcp_info, &tcp_info_len);
  172. if (ret == -1) {
  173. fprintf(stderr, "Could not get struct tcp_info: %m.\n");
  174. return -1;
  175. }
  176. if (tcp_info.tcpi_bytes_acked != bytes_acked) {
  177. bytes_acked = tcp_info.tcpi_bytes_acked;
  178. received_ack = 1;
  179. }
  180. goto next_events;
  181. break;
  182. default:
  183. fprintf(stderr, "Unknown event kind %d, skipping.\n",
  184. events[i].data.u32);
  185. break;
  186. }
  187. }
  188. next_events:
  189. if (received_ack || received_data) {
  190. fprintf(stdout,
  191. "%" PRIu64 ".%09ld %06" PRIu64 " %06d %s%s\n",
  192. ts.tv_sec, ts.tv_nsec,
  193. bytes_acked,
  194. data_received,
  195. (received_ack ? "X" : "_"),
  196. (received_data ? "X" : "_")
  197. );
  198. fflush(stdout);
  199. }
  200. }
  201. return 0;
  202. }
  203. int client(struct addrinfo *result) {
  204. int ret, ret2, fd;
  205. struct addrinfo *rp;
  206. char msg[512];
  207. for (rp = result; rp != NULL; rp = rp->ai_next) {
  208. fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  209. if (fd != -1) {
  210. if (connect(fd, rp->ai_addr, rp->ai_addrlen) != 0) {
  211. fprintf(stderr, "connect() failed: %m.\n");
  212. close(fd);
  213. }
  214. else {
  215. break;
  216. }
  217. }
  218. else {
  219. fprintf(stderr, "socket() failed: %m.\n");
  220. }
  221. }
  222. if (rp == NULL) {
  223. fprintf(stderr, "Could not establish client.\n");
  224. return -1;
  225. }
  226. freeaddrinfo(result);
  227. while (1) {
  228. ret = read(fd, msg, sizeof(msg));
  229. if (ret == -1) {
  230. fprintf(stderr, "Could not read data: %m.\n");
  231. return -1;
  232. }
  233. errno = 0;
  234. ret2 = write(fd, msg, ret);
  235. if (ret2 != ret) {
  236. fprintf(stderr, "Could not echo data: %m [%d, %d].\n", ret, ret2);
  237. return -1;
  238. }
  239. }
  240. return 0;
  241. }
  242. int main(int argc, char *argv[]) {
  243. int ret;
  244. struct addrinfo *result;
  245. struct addrinfo settings = {
  246. .ai_family = AF_UNSPEC,
  247. .ai_socktype = SOCK_STREAM,
  248. .ai_flags = AI_PASSIVE,
  249. };
  250. if ((argc != 4)
  251. || (strcmp(argv[1], "server") != 0 && (strcmp(argv[1], "client") != 0)))
  252. {
  253. fprintf(stderr, "Usage: %s <client|server> <IP> <port>.\n", argv[0]);
  254. return -1;
  255. }
  256. ret = getaddrinfo(argv[2], argv[3], &settings, &result);
  257. if (ret != 0) {
  258. fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
  259. return -1;
  260. }
  261. switch(argv[1][0]) {
  262. case 's':
  263. return server(result);
  264. case 'c':
  265. return client(result);
  266. }
  267. }