socket_opts.c 10 KB

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