socket_opts.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <arpa/inet.h>
  6. #include <errno.h>
  7. #include <netinet/tcp.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/socket.h>
  12. #include <sys/time.h>
  13. #include <unistd.h>
  14. #ifdef __wasi__
  15. #include <wasi_socket_ext.h>
  16. #endif
  17. #define MULTICAST_ADDR 16777440
  18. #define OPTION_ASSERT(A, B, OPTION) \
  19. if (A == B) { \
  20. printf("%s is expected\n", OPTION); \
  21. } \
  22. else { \
  23. printf("%s is unexpected\n", OPTION); \
  24. perror("assertion failed"); \
  25. return EXIT_FAILURE; \
  26. }
  27. static struct timeval
  28. to_timeval(time_t tv_sec, suseconds_t tv_usec)
  29. {
  30. struct timeval tv = { tv_sec, tv_usec };
  31. return tv;
  32. }
  33. static int
  34. set_and_get_bool_opt(int socket_fd, int level, int optname, int val)
  35. {
  36. int bool_opt = val;
  37. int ret = -1;
  38. socklen_t opt_len = sizeof(bool_opt);
  39. ret = setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt));
  40. if (ret != 0)
  41. return !val;
  42. bool_opt = !bool_opt;
  43. ret = getsockopt(socket_fd, level, optname, &bool_opt, &opt_len);
  44. if (ret != 0)
  45. return !val;
  46. return bool_opt;
  47. }
  48. int
  49. main(int argc, char *argv[])
  50. {
  51. int tcp_socket_fd = 0;
  52. int udp_socket_fd = 0;
  53. int udp_ipv6_socket_fd = 0;
  54. struct timeval tv;
  55. socklen_t opt_len;
  56. int buf_len;
  57. int result;
  58. struct linger linger_opt;
  59. uint32_t time_s;
  60. int ttl;
  61. printf("[Client] Create TCP socket\n");
  62. tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  63. if (tcp_socket_fd == -1) {
  64. perror("Create socket failed");
  65. return EXIT_FAILURE;
  66. }
  67. printf("[Client] Create UDP socket\n");
  68. udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  69. if (udp_socket_fd == -1) {
  70. perror("Create socket failed");
  71. return EXIT_FAILURE;
  72. }
  73. printf("[Client] Create UDP IPv6 socket\n");
  74. udp_ipv6_socket_fd = socket(AF_INET6, SOCK_DGRAM, 0);
  75. if (udp_ipv6_socket_fd == -1) {
  76. perror("Create socket failed");
  77. return EXIT_FAILURE;
  78. }
  79. // SO_RCVTIMEO
  80. tv = to_timeval(123, 1000);
  81. result =
  82. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
  83. OPTION_ASSERT(result, 0, "setsockopt SO_RCVTIMEO result")
  84. tv = to_timeval(0, 0);
  85. opt_len = sizeof(tv);
  86. result = getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len);
  87. OPTION_ASSERT(result, 0, "getsockopt SO_RCVTIMEO result")
  88. OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec");
  89. // OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec");
  90. // SO_SNDTIMEO
  91. tv = to_timeval(456, 2000);
  92. result =
  93. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
  94. OPTION_ASSERT(result, 0, "setsockopt SO_SNDTIMEO result")
  95. tv = to_timeval(0, 0);
  96. opt_len = sizeof(tv);
  97. result = getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len);
  98. OPTION_ASSERT(result, 0, "getsockopt SO_SNDTIMEO result")
  99. OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec");
  100. // OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec");
  101. // SO_SNDBUF
  102. buf_len = 8192;
  103. result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len,
  104. sizeof(buf_len));
  105. OPTION_ASSERT(result, 0, "setsockopt SO_SNDBUF result")
  106. buf_len = 0;
  107. opt_len = sizeof(buf_len);
  108. result =
  109. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len);
  110. OPTION_ASSERT(result, 0, "getsockopt SO_SNDBUF result")
  111. OPTION_ASSERT((buf_len == 16384 || buf_len == 8192), 1,
  112. "SO_SNDBUF buf_len");
  113. // SO_RCVBUF
  114. buf_len = 4096;
  115. result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len,
  116. sizeof(buf_len));
  117. OPTION_ASSERT(result, 0, "setsockopt SO_RCVBUF result")
  118. buf_len = 0;
  119. opt_len = sizeof(buf_len);
  120. result =
  121. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len);
  122. OPTION_ASSERT(result, 0, "getsockopt SO_RCVBUF result")
  123. OPTION_ASSERT((buf_len == 8192 || buf_len == 4096), 1, "SO_SNDBUF buf_len");
  124. // SO_KEEPALIVE
  125. OPTION_ASSERT(
  126. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 1), 1,
  127. "SO_KEEPALIVE enabled");
  128. OPTION_ASSERT(
  129. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 0), 0,
  130. "SO_KEEPALIVE disabled");
  131. // SO_REUSEADDR
  132. OPTION_ASSERT(
  133. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 1), 1,
  134. "SO_REUSEADDR enabled");
  135. OPTION_ASSERT(
  136. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 0), 0,
  137. "SO_REUSEADDR disabled");
  138. // SO_REUSEPORT
  139. OPTION_ASSERT(
  140. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 1), 1,
  141. "SO_REUSEPORT enabled");
  142. OPTION_ASSERT(
  143. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 0), 0,
  144. "SO_REUSEPORT disabled");
  145. // SO_LINGER
  146. linger_opt.l_onoff = 1;
  147. linger_opt.l_linger = 10;
  148. result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt,
  149. sizeof(linger_opt));
  150. OPTION_ASSERT(result, 0, "setsockopt SO_LINGER result")
  151. linger_opt.l_onoff = 0;
  152. linger_opt.l_linger = 0;
  153. opt_len = sizeof(linger_opt);
  154. result =
  155. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len);
  156. OPTION_ASSERT(result, 0, "getsockopt SO_LINGER result")
  157. OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff");
  158. OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger");
  159. // SO_BROADCAST
  160. OPTION_ASSERT(
  161. set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 1), 1,
  162. "SO_BROADCAST enabled");
  163. OPTION_ASSERT(
  164. set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 0), 0,
  165. "SO_BROADCAST disabled");
  166. // TCP_KEEPIDLE
  167. #ifdef TCP_KEEPIDLE
  168. time_s = 16;
  169. result = setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s,
  170. sizeof(time_s));
  171. OPTION_ASSERT(result, 0, "setsockopt TCP_KEEPIDLE result")
  172. time_s = 0;
  173. opt_len = sizeof(time_s);
  174. result =
  175. getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len);
  176. OPTION_ASSERT(result, 0, "getsockopt TCP_KEEPIDLE result")
  177. OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE");
  178. #endif
  179. // TCP_KEEPINTVL
  180. time_s = 8;
  181. result = setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s,
  182. sizeof(time_s));
  183. OPTION_ASSERT(result, 0, "setsockopt TCP_KEEPINTVL result")
  184. time_s = 0;
  185. opt_len = sizeof(time_s);
  186. result = getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s,
  187. &opt_len);
  188. OPTION_ASSERT(result, 0, "getsockopt TCP_KEEPINTVL result")
  189. OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL");
  190. // TCP_FASTOPEN_CONNECT
  191. #ifdef TCP_FASTOPEN_CONNECT
  192. OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
  193. TCP_FASTOPEN_CONNECT, 1),
  194. 1, "TCP_FASTOPEN_CONNECT enabled");
  195. OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
  196. TCP_FASTOPEN_CONNECT, 0),
  197. 0, "TCP_FASTOPEN_CONNECT disabled");
  198. #endif
  199. // TCP_NODELAY
  200. OPTION_ASSERT(
  201. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 1), 1,
  202. "TCP_NODELAY enabled");
  203. OPTION_ASSERT(
  204. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 0), 0,
  205. "TCP_NODELAY disabled");
  206. // TCP_QUICKACK
  207. #ifdef TCP_QUICKACK
  208. OPTION_ASSERT(
  209. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 1), 1,
  210. "TCP_QUICKACK enabled");
  211. OPTION_ASSERT(
  212. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 0), 0,
  213. "TCP_QUICKACK disabled");
  214. #endif
  215. // IP_TTL
  216. ttl = 8;
  217. result = setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
  218. OPTION_ASSERT(result, 0, "IP_TIL");
  219. ttl = 0;
  220. opt_len = sizeof(ttl);
  221. result = getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len);
  222. OPTION_ASSERT(ttl, 8, "IP_TTL");
  223. OPTION_ASSERT(result, 0, "IP_TIL");
  224. // IPV6_V6ONLY
  225. OPTION_ASSERT(
  226. set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1),
  227. 1, "IPV6_V6ONLY enabled");
  228. OPTION_ASSERT(
  229. set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 0),
  230. 0, "IPV6_V6ONLY disabled");
  231. // IP_MULTICAST_LOOP
  232. OPTION_ASSERT(
  233. set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1),
  234. 1, "IP_MULTICAST_LOOP enabled");
  235. OPTION_ASSERT(
  236. set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 0),
  237. 0, "IP_MULTICAST_LOOP disabled");
  238. // IP_MULTICAST_TTL
  239. ttl = 8;
  240. result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
  241. sizeof(ttl));
  242. OPTION_ASSERT(result, 0, "IP_MULTICAST_TTL");
  243. ttl = 0;
  244. opt_len = sizeof(ttl);
  245. result =
  246. getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len);
  247. OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL");
  248. OPTION_ASSERT(result, 0, "IP_MULTICAST_TTL");
  249. // IPV6_MULTICAST_LOOP
  250. OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
  251. IPV6_MULTICAST_LOOP, 1),
  252. 1, "IPV6_MULTICAST_LOOP enabled");
  253. OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
  254. IPV6_MULTICAST_LOOP, 0),
  255. 0, "IPV6_MULTICAST_LOOP disabled");
  256. printf("[Client] Close sockets\n");
  257. close(tcp_socket_fd);
  258. close(udp_socket_fd);
  259. close(udp_ipv6_socket_fd);
  260. return EXIT_SUCCESS;
  261. }