socket_opts.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. socklen_t opt_len = sizeof(bool_opt);
  32. setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt));
  33. bool_opt = !bool_opt;
  34. getsockopt(socket_fd, level, optname, &bool_opt, &opt_len);
  35. return bool_opt;
  36. }
  37. int
  38. main(int argc, char *argv[])
  39. {
  40. int tcp_socket_fd = 0;
  41. int udp_socket_fd = 0;
  42. int udp_ipv6_socket_fd = 0;
  43. struct timeval tv;
  44. socklen_t opt_len;
  45. int buf_len;
  46. int result;
  47. struct linger linger_opt;
  48. uint32_t time_s;
  49. struct ip_mreq mcast;
  50. struct ipv6_mreq mcast_ipv6;
  51. unsigned char ttl;
  52. printf("[Client] Create TCP socket\n");
  53. tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  54. if (tcp_socket_fd == -1) {
  55. perror("Create socket failed");
  56. return EXIT_FAILURE;
  57. }
  58. printf("[Client] Create UDP socket\n");
  59. udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  60. if (udp_socket_fd == -1) {
  61. perror("Create socket failed");
  62. return EXIT_FAILURE;
  63. }
  64. printf("[Client] Create UDP IPv6 socket\n");
  65. udp_ipv6_socket_fd = socket(AF_INET6, SOCK_DGRAM, 0);
  66. if (udp_ipv6_socket_fd == -1) {
  67. perror("Create socket failed");
  68. return EXIT_FAILURE;
  69. }
  70. // SO_RCVTIMEO
  71. tv = to_timeval(123, 1000);
  72. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
  73. tv = to_timeval(0, 0);
  74. opt_len = sizeof(tv);
  75. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len);
  76. OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec");
  77. OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec");
  78. // SO_SNDTIMEO
  79. tv = to_timeval(456, 2000);
  80. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
  81. tv = to_timeval(0, 0);
  82. opt_len = sizeof(tv);
  83. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len);
  84. OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec");
  85. OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec");
  86. // SO_SNDBUF
  87. buf_len = 8192;
  88. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, sizeof(buf_len));
  89. buf_len = 0;
  90. opt_len = sizeof(buf_len);
  91. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len);
  92. OPTION_ASSERT(buf_len, 16384, "SO_SNDBUF buf_len");
  93. // SO_RCVBUF
  94. buf_len = 4096;
  95. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, sizeof(buf_len));
  96. buf_len = 0;
  97. opt_len = sizeof(buf_len);
  98. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len);
  99. OPTION_ASSERT(buf_len, 8192, "SO_RCVBUF buf_len");
  100. // SO_KEEPALIVE
  101. OPTION_ASSERT(
  102. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 1), 1,
  103. "SO_KEEPALIVE enabled");
  104. OPTION_ASSERT(
  105. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 0), 0,
  106. "SO_KEEPALIVE disabled");
  107. // SO_REUSEADDR
  108. OPTION_ASSERT(
  109. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 1), 1,
  110. "SO_REUSEADDR enabled");
  111. OPTION_ASSERT(
  112. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 0), 0,
  113. "SO_REUSEADDR disabled");
  114. // SO_REUSEPORT
  115. OPTION_ASSERT(
  116. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 1), 1,
  117. "SO_REUSEPORT enabled");
  118. OPTION_ASSERT(
  119. set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 0), 0,
  120. "SO_REUSEPORT disabled");
  121. // SO_LINGER
  122. linger_opt.l_onoff = 1;
  123. linger_opt.l_linger = 10;
  124. setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt,
  125. sizeof(linger_opt));
  126. linger_opt.l_onoff = 0;
  127. linger_opt.l_linger = 0;
  128. opt_len = sizeof(linger_opt);
  129. getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len);
  130. OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff");
  131. OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger");
  132. // SO_BROADCAST
  133. OPTION_ASSERT(
  134. set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 1), 1,
  135. "SO_BROADCAST enabled");
  136. OPTION_ASSERT(
  137. set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 0), 0,
  138. "SO_BROADCAST disabled");
  139. // TCP_KEEPIDLE
  140. time_s = 16;
  141. setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s,
  142. sizeof(time_s));
  143. time_s = 0;
  144. opt_len = sizeof(time_s);
  145. getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len);
  146. OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE");
  147. // TCP_KEEPINTVL
  148. time_s = 8;
  149. setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s,
  150. sizeof(time_s));
  151. time_s = 0;
  152. opt_len = sizeof(time_s);
  153. getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, &opt_len);
  154. OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL");
  155. // TCP_FASTOPEN_CONNECT
  156. OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
  157. TCP_FASTOPEN_CONNECT, 1),
  158. 1, "TCP_FASTOPEN_CONNECT enabled");
  159. OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
  160. TCP_FASTOPEN_CONNECT, 0),
  161. 0, "TCP_FASTOPEN_CONNECT disabled");
  162. // TCP_NODELAY
  163. OPTION_ASSERT(
  164. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 1), 1,
  165. "TCP_NODELAY enabled");
  166. OPTION_ASSERT(
  167. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 0), 0,
  168. "TCP_NODELAY disabled");
  169. // TCP_QUICKACK
  170. OPTION_ASSERT(
  171. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 1), 1,
  172. "TCP_QUICKACK enabled");
  173. OPTION_ASSERT(
  174. set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 0), 0,
  175. "TCP_QUICKACK disabled");
  176. // IP_TTL
  177. ttl = 8;
  178. setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
  179. ttl = 0;
  180. opt_len = sizeof(ttl);
  181. getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len);
  182. OPTION_ASSERT(ttl, 8, "IP_TTL");
  183. // IPV6_V6ONLY
  184. OPTION_ASSERT(
  185. set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1),
  186. 1, "IPV6_V6ONLY enabled");
  187. OPTION_ASSERT(
  188. set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 0),
  189. 0, "IPV6_V6ONLY disabled");
  190. // IP_MULTICAST_LOOP
  191. OPTION_ASSERT(
  192. set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1),
  193. 1, "IP_MULTICAST_LOOP enabled");
  194. OPTION_ASSERT(
  195. set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 0),
  196. 0, "IP_MULTICAST_LOOP disabled");
  197. // IP_ADD_MEMBERSHIP
  198. mcast.imr_multiaddr.s_addr = 16777440;
  199. mcast.imr_interface.s_addr = htonl(INADDR_ANY);
  200. result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast,
  201. sizeof(mcast));
  202. OPTION_ASSERT(result, 0, "IP_ADD_MEMBERSHIP");
  203. // IP_DROP_MEMBERSHIP
  204. result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcast,
  205. sizeof(mcast));
  206. OPTION_ASSERT(result, 0, "IP_DROP_MEMBERSHIP");
  207. // IP_MULTICAST_TTL
  208. ttl = 8;
  209. setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
  210. ttl = 0;
  211. opt_len = sizeof(ttl);
  212. getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len);
  213. OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL");
  214. // IPV6_MULTICAST_LOOP
  215. OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
  216. IPV6_MULTICAST_LOOP, 1),
  217. 1, "IPV6_MULTICAST_LOOP enabled");
  218. OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
  219. IPV6_MULTICAST_LOOP, 0),
  220. 0, "IPV6_MULTICAST_LOOP disabled");
  221. // IPV6_JOIN_GROUP
  222. setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mcast_ipv6,
  223. sizeof(mcast_ipv6));
  224. // IPV6_LEAVE_GROUP
  225. setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mcast_ipv6,
  226. sizeof(mcast_ipv6));
  227. printf("[Client] Close sockets\n");
  228. close(tcp_socket_fd);
  229. close(udp_socket_fd);
  230. return EXIT_SUCCESS;
  231. }