testsock.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. * Copyright (c) 2018-2023 SignalWire, Inc
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in all
  12. * copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. #include "libks/ks.h"
  23. #include <tap.h>
  24. static char v4[48] = "";
  25. static char v6[48] = "";
  26. static int mask = 0;
  27. static int tcp_port = 8090;
  28. static int udp_cl_port = 9090;
  29. static int udp_sv_port = 9091;
  30. static char __MSG[] = "TESTING................................................................................/TESTING";
  31. struct tcp_data {
  32. ks_socket_t sock;
  33. ks_sockaddr_t addr;
  34. int ready;
  35. char *ip;
  36. };
  37. void server_callback(ks_socket_t server_sock, ks_socket_t client_sock, ks_sockaddr_t *addr, void *user_data)
  38. {
  39. //struct tcp_data *tcp_data = (struct tcp_data *) user_data;
  40. char buf[8192] = "";
  41. ks_status_t status;
  42. ks_size_t bytes;
  43. printf("TCP SERVER SOCK %d connection from %s:%u\n", (int)server_sock, addr->host, addr->port);
  44. do {
  45. bytes = sizeof(buf);;
  46. status = ks_socket_recv(client_sock, buf, &bytes);
  47. if (status != KS_STATUS_SUCCESS) {
  48. printf("TCP SERVER BAIL %s\n", strerror(ks_errno()));
  49. break;
  50. }
  51. printf("TCP SERVER READ %ld bytes [%s]\n", (long)bytes, buf);
  52. } while(ks_zstr_buf(buf) || strcmp(buf, __MSG));
  53. bytes = strlen(buf);
  54. ks_socket_send(client_sock, buf, &bytes);
  55. printf("TCP SERVER WRITE %ld bytes\n", (long)bytes);
  56. ks_socket_close(&client_sock);
  57. printf("TCP SERVER COMPLETE\n");
  58. }
  59. static void *tcp_sock_server(ks_thread_t *thread, void *thread_data)
  60. {
  61. struct tcp_data *tcp_data = (struct tcp_data *) thread_data;
  62. tcp_data->ready = 1;
  63. ks_listen_sock(tcp_data->sock, &tcp_data->addr, 0, server_callback, tcp_data);
  64. printf("TCP THREAD DONE\n");
  65. return NULL;
  66. }
  67. static int test_addr(int v)
  68. {
  69. ks_sockaddr_t addr1, addr2, addr3, addr4, addr5;
  70. printf("TESTING ADDR v%d\n", v);
  71. if (v == 4) {
  72. if (ks_addr_set(&addr1, "10.100.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) {
  73. return 0;
  74. }
  75. if (strcmp(addr1.host, "10.100.200.5")) {
  76. return 0;
  77. }
  78. if (ks_addr_set(&addr2, "10.100.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) {
  79. return 0;
  80. }
  81. if (ks_addr_set(&addr3, "10.100.200.5", 1234, AF_INET) != KS_STATUS_SUCCESS) {
  82. return 0;
  83. }
  84. if (ks_addr_set(&addr4, "10.199.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) {
  85. return 0;
  86. }
  87. } else {
  88. if (ks_addr_set(&addr1, "1607:f418:1210::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) {
  89. return 0;
  90. }
  91. if (strcmp(addr1.host, "1607:f418:1210::1")) {
  92. return 0;
  93. }
  94. if (ks_addr_set(&addr2, "1607:f418:1210::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) {
  95. return 0;
  96. }
  97. if (ks_addr_set(&addr3, "1607:f418:1210::1", 1234, AF_INET6) != KS_STATUS_SUCCESS) {
  98. return 0;
  99. }
  100. if (ks_addr_set(&addr4, "1337:a118:1306::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) {
  101. return 0;
  102. }
  103. }
  104. if (ks_addr_copy(&addr5, &addr4) != KS_STATUS_SUCCESS) {
  105. return 0;
  106. }
  107. if (!ks_addr_cmp(&addr1, &addr2)) {
  108. return 0;
  109. }
  110. if (ks_addr_cmp(&addr1, &addr3)) {
  111. return 0;
  112. }
  113. if (ks_addr_cmp(&addr1, &addr4)) {
  114. return 0;
  115. }
  116. if (!ks_addr_cmp(&addr4, &addr5)) {
  117. return 0;
  118. }
  119. if (ks_addr_cmp(&addr1, &addr5)) {
  120. return 0;
  121. }
  122. return 1;
  123. }
  124. static int test_tcp(char *ip)
  125. {
  126. ks_thread_t *thread_p = NULL;
  127. ks_pool_t *pool;
  128. ks_sockaddr_t addr;
  129. int family = AF_INET;
  130. ks_socket_t cl_sock = KS_SOCK_INVALID;
  131. char buf[8192] = "";
  132. struct tcp_data tcp_data = { 0 };
  133. int r = 1, sanity = 100;
  134. ks_pool_open(&pool);
  135. if (strchr(ip, ':')) {
  136. family = AF_INET6;
  137. }
  138. if (ks_addr_set(&tcp_data.addr, ip, tcp_port, family) != KS_STATUS_SUCCESS) {
  139. r = 0;
  140. printf("TCP CLIENT Can't set ADDR\n");
  141. goto end;
  142. }
  143. if ((tcp_data.sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) {
  144. r = 0;
  145. printf("TCP CLIENT Can't create sock family %d\n", family);
  146. goto end;
  147. }
  148. ks_socket_option(tcp_data.sock, SO_REUSEADDR, KS_TRUE);
  149. ks_socket_option(tcp_data.sock, TCP_NODELAY, KS_TRUE);
  150. tcp_data.ip = ip;
  151. ks_thread_create(&thread_p, tcp_sock_server, &tcp_data, pool);
  152. while(!tcp_data.ready && --sanity > 0) {
  153. ks_sleep(10000);
  154. }
  155. ks_addr_set(&addr, ip, tcp_port, family);
  156. cl_sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr);
  157. //int x;
  158. printf("TCP CLIENT SOCKET %d %s %d\n", (int)cl_sock, addr.host, addr.port);
  159. ks_size_t msglen = strlen(__MSG);
  160. ks_socket_send(cl_sock, __MSG, &msglen);
  161. printf("TCP CLIENT WRITE %d bytes\n", (int)msglen);
  162. //x = write((int)cl_sock, __MSG, (unsigned)strlen(__MSG));
  163. //printf("TCP CLIENT WRITE %d bytes\n", x);
  164. msglen = sizeof(buf);
  165. ks_socket_recv(cl_sock, buf, &msglen);
  166. printf("TCP CLIENT READ %d bytes [%s]\n", (int)msglen, buf);
  167. //x = read((int)cl_sock, buf, sizeof(buf));
  168. //printf("TCP CLIENT READ %d bytes [%s]\n", x, buf);
  169. end:
  170. if (tcp_data.sock != KS_SOCK_INVALID) {
  171. ks_socket_shutdown(tcp_data.sock, 2);
  172. ks_socket_close(&tcp_data.sock);
  173. }
  174. if (thread_p) {
  175. ks_thread_join(thread_p);
  176. }
  177. ks_socket_close(&cl_sock);
  178. ks_pool_close(&pool);
  179. return r;
  180. }
  181. struct udp_data {
  182. int ready;
  183. char *ip;
  184. ks_socket_t sv_sock;
  185. };
  186. static void *udp_sock_server(ks_thread_t *thread, void *thread_data)
  187. {
  188. struct udp_data *udp_data = (struct udp_data *) thread_data;
  189. int family = AF_INET;
  190. ks_status_t status;
  191. ks_sockaddr_t addr, remote_addr = KS_SA_INIT;
  192. char buf[8192] = "";
  193. ks_size_t bytes;
  194. udp_data->sv_sock = KS_SOCK_INVALID;
  195. if (strchr(udp_data->ip, ':')) {
  196. family = AF_INET6;
  197. }
  198. ks_addr_set(&addr, udp_data->ip, udp_sv_port, family);
  199. remote_addr.family = family;
  200. if ((udp_data->sv_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) {
  201. printf("UDP SERVER SOCKET ERROR %s\n", strerror(ks_errno()));
  202. goto end;
  203. }
  204. ks_socket_option(udp_data->sv_sock, SO_REUSEADDR, KS_TRUE);
  205. if (ks_addr_bind(udp_data->sv_sock, &addr) != KS_STATUS_SUCCESS) {
  206. printf("UDP SERVER BIND ERROR %s\n", strerror(ks_errno()));
  207. goto end;
  208. }
  209. udp_data->ready = 1;
  210. printf("UDP SERVER SOCKET %d %s %d\n", (int)(udp_data->sv_sock), addr.host, addr.port);
  211. bytes = sizeof(buf);
  212. if ((status = ks_socket_recvfrom(udp_data->sv_sock, buf, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) {
  213. printf("UDP SERVER RECVFROM ERR %s\n", strerror(ks_errno()));
  214. goto end;
  215. }
  216. printf("UDP SERVER READ %ld bytes [%s]\n", (long)bytes, buf);
  217. if (strcmp(buf, __MSG)) {
  218. printf("INVALID MESSAGE\n");
  219. goto end;
  220. }
  221. printf("UDP SERVER WAIT 2 seconds to test nonblocking sockets\n");
  222. ks_sleep(2000000);
  223. printf("UDP SERVER RESPOND TO %d %s %d\n", (int)(udp_data->sv_sock), remote_addr.host, remote_addr.port);
  224. bytes = strlen(buf);
  225. if ((status = ks_socket_sendto(udp_data->sv_sock, buf, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) {
  226. printf("UDP SERVER SENDTO ERR %s\n", strerror(ks_errno()));
  227. goto end;
  228. }
  229. printf("UDP SERVER WRITE %ld bytes [%s]\n", (long)bytes, buf);
  230. end:
  231. udp_data->ready = -1;
  232. printf("UDP THREAD DONE\n");
  233. ks_socket_close(&udp_data->sv_sock);
  234. return NULL;
  235. }
  236. static int test_udp(char *ip)
  237. {
  238. ks_thread_t *thread_p = NULL;
  239. ks_pool_t *pool;
  240. ks_sockaddr_t addr, remote_addr;
  241. int family = AF_INET;
  242. ks_socket_t cl_sock = KS_SOCK_INVALID;
  243. char buf[8192] = "";
  244. int r = 1, sanity = 100;
  245. struct udp_data udp_data = { 0 };
  246. ks_size_t bytes = 0;
  247. ks_status_t status;
  248. ks_pool_open(&pool);
  249. if (strchr(ip, ':')) {
  250. family = AF_INET6;
  251. }
  252. ks_addr_set(&addr, ip, udp_cl_port, family);
  253. if ((cl_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) {
  254. printf("UDP CLIENT SOCKET ERROR %s\n", strerror(ks_errno()));
  255. r = 0; goto end;
  256. }
  257. ks_socket_option(cl_sock, SO_REUSEADDR, KS_TRUE);
  258. if (ks_addr_bind(cl_sock, &addr) != KS_STATUS_SUCCESS) {
  259. printf("UDP CLIENT BIND ERROR %s\n", strerror(ks_errno()));
  260. r = 0; goto end;
  261. }
  262. ks_addr_set(&remote_addr, ip, udp_sv_port, family);
  263. udp_data.ip = ip;
  264. ks_thread_create(&thread_p, udp_sock_server, &udp_data, pool);
  265. while(!udp_data.ready && --sanity > 0) {
  266. ks_sleep(10000);
  267. }
  268. printf("UDP CLIENT SOCKET %d %s %d -> %s %d\n", (int)cl_sock, addr.host, addr.port, remote_addr.host, remote_addr.port);
  269. bytes = strlen(__MSG);
  270. if ((status = ks_socket_sendto(cl_sock, __MSG, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) {
  271. printf("UDP CLIENT SENDTO ERR %s\n", strerror(ks_errno()));
  272. r = 0; goto end;
  273. }
  274. printf("UDP CLIENT WRITE %ld bytes\n", (long)bytes);
  275. ks_socket_option(cl_sock, KS_SO_NONBLOCK, KS_TRUE);
  276. sanity = 300;
  277. do {
  278. status = ks_socket_recvfrom(cl_sock, buf, &bytes, &remote_addr);
  279. if (status == KS_STATUS_BREAK && --sanity > 0) {
  280. if ((sanity % 50) == 0) printf("UDP CLIENT SLEEP NONBLOCKING\n");
  281. ks_sleep(10000);
  282. } else if (status != KS_STATUS_SUCCESS) {
  283. printf("UDP CLIENT RECVFROM ERR %s\n", strerror(ks_errno()));
  284. r = 0; goto end;
  285. }
  286. } while(status != KS_STATUS_SUCCESS);
  287. printf("UDP CLIENT READ %ld bytes\n", (long)bytes);
  288. end:
  289. if (thread_p) {
  290. ks_thread_join(thread_p);
  291. }
  292. if (udp_data.ready > 0 && udp_data.sv_sock && ks_socket_valid(udp_data.sv_sock)) {
  293. ks_socket_shutdown(udp_data.sv_sock, 2);
  294. ks_socket_close(&udp_data.sv_sock);
  295. }
  296. ks_socket_close(&cl_sock);
  297. ks_pool_close(&pool);
  298. return r;
  299. }
  300. int main(void)
  301. {
  302. int have_v4 = 0, have_v6 = 0;
  303. ks_init();
  304. ks_find_local_ip(v4, sizeof(v4), &mask, AF_INET, NULL);
  305. ks_find_local_ip(v6, sizeof(v6), NULL, AF_INET6, NULL);
  306. printf("IPS: v4: [%s] v6: [%s]\n", v4, v6);
  307. have_v4 = ks_zstr_buf(v4) ? 0 : 1;
  308. have_v6 = ks_zstr_buf(v6) ? 0 : 1;
  309. plan((have_v4 * 3) + (have_v6 * 2) + 1); // FIXME test_udp(v6) doesn't work in CI
  310. ok(have_v4 || have_v6);
  311. if (have_v4) {
  312. ok(test_tcp(v4));
  313. ok(test_udp(v4));
  314. ok(test_addr(4));
  315. }
  316. if (have_v6) {
  317. ok(test_tcp(v6));
  318. //ok(test_udp(v6)); FIXME doesn't work in CI
  319. ok(test_addr(6));
  320. }
  321. ks_shutdown();
  322. done_testing();
  323. }