PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/client/tests/ipv6connect/src/ipv6connect.c

https://gitlab.com/libvirt/autotest
C | 474 lines | 392 code | 41 blank | 41 comment | 117 complexity | c59c73f41c12080b238774cc6f9b0ae5 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0
  1. // Copyright 2008 Google Inc. Released under the GPL v2.
  2. //
  3. // This test performs numerous connects (with auto-binding), to a server
  4. // listening on all local addresses using an IPv6 socket, by connecting to
  5. // 127.0.0.1, ::ffff:127.0.0.1 and ::1.
  6. //
  7. // The code is really three tests:
  8. //
  9. // - RunWithOneServer, using CreateServer and ConnectAndAccept,
  10. // uses one server socket and repeatedly connects to it.
  11. //
  12. // - RunWithOneShotServers, using CreateServerConnectAndAccept,
  13. // creates servers, connects to them and then discards them.
  14. //
  15. // - RunMultiThreaded, using ThreadedCreateServerConnectAndAccept,
  16. // ThreadedStartServer and ThreadedGetServerFD, is equivalent to
  17. // RunWithOneShotServers but uses multiple threads, one for the
  18. // server and one for the client.
  19. //
  20. // Each of these tests triggers error conditions on different kernels
  21. // to a different extent.
  22. #include <arpa/inet.h>
  23. #include <netinet/in.h>
  24. #include <pthread.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/socket.h>
  29. #include <sys/time.h>
  30. #include <time.h>
  31. #include <unistd.h>
  32. // Which loopback address to connect to.
  33. enum LoopbackAddr { V4_LOOPBACK, V6_LOOPBACK, V6_MAPPED_V4_LOOPBACK };
  34. // Connect to a listening TCP socket, and accept the connection.
  35. static void ConnectAndAccept(enum LoopbackAddr addr, int server_fd, int port) {
  36. struct sockaddr_in6 sa;
  37. socklen_t addr_len;
  38. int client_fd, accepted_fd;
  39. if (addr == V6_LOOPBACK || addr == V6_MAPPED_V4_LOOPBACK) {
  40. char buf[INET6_ADDRSTRLEN];
  41. memset(&sa, 0, sizeof(sa));
  42. if ((client_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  43. perror("socket");
  44. exit(1);
  45. }
  46. if (addr == V6_LOOPBACK) {
  47. inet_pton(AF_INET6, "::1", &sa.sin6_addr);
  48. } else if (addr == V6_MAPPED_V4_LOOPBACK) {
  49. inet_pton(AF_INET6, "::ffff:127.0.0.1", &sa.sin6_addr);
  50. }
  51. if (!inet_ntop(AF_INET6, &sa.sin6_addr, buf, INET6_ADDRSTRLEN)) {
  52. perror("inet_ntop");
  53. exit(1);
  54. }
  55. addr_len = sizeof(sa);
  56. sa.sin6_family = AF_INET6;
  57. sa.sin6_port = port;
  58. if (connect(client_fd, (struct sockaddr*)(&sa),
  59. sizeof(struct sockaddr_in6)) == -1) {
  60. perror("connect");
  61. exit(1);
  62. }
  63. write(2, (addr == V6_LOOPBACK) ? "+" : "-", 1);
  64. } else {
  65. struct sockaddr_in sa4;
  66. if ((client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  67. perror("socket");
  68. exit(1);
  69. }
  70. memset(&sa4, 0, sizeof(sa4));
  71. sa4.sin_family = AF_INET;
  72. inet_pton(AF_INET, "127.0.0.1", &sa4.sin_addr);
  73. sa4.sin_port = port;
  74. if (connect(client_fd, (struct sockaddr*)(&sa4),
  75. sizeof(struct sockaddr_in)) == -1) {
  76. perror("connect");
  77. exit(1);
  78. }
  79. write(2, ".", 1);
  80. }
  81. addr_len = sizeof(sa);
  82. if ((accepted_fd = accept(server_fd,
  83. (struct sockaddr*)(&sa), &addr_len)) == -1) {
  84. perror("accept");
  85. exit(1);
  86. }
  87. close(client_fd);
  88. close(accepted_fd);
  89. }
  90. // Create a listening TCP socket.
  91. static void CreateServer(int* server_fd, int* port) {
  92. struct sockaddr_in6 sa;
  93. socklen_t addr_len;
  94. memset(&sa, 0, sizeof(sa));
  95. if ((*server_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  96. perror("socket");
  97. exit(1);
  98. }
  99. addr_len = sizeof(sa);
  100. sa.sin6_family = AF_INET6;
  101. sa.sin6_addr = in6addr_any;
  102. sa.sin6_port = 0;
  103. if (bind(*server_fd, (struct sockaddr*)(&sa), sizeof(sa)) == -1) {
  104. perror("bind");
  105. exit(1);
  106. }
  107. if (getsockname(*server_fd, (struct sockaddr*)(&sa), &addr_len) == -1) {
  108. perror("getsockname");
  109. exit(1);
  110. }
  111. if (listen(*server_fd, 10) == -1) {
  112. perror("listen");
  113. exit(1);
  114. }
  115. *port = sa.sin6_port;
  116. }
  117. // Create a socket, connect to it, accept, and discard both.
  118. static void CreateServerConnectAndAccept(enum LoopbackAddr addr) {
  119. struct sockaddr_in6 sa;
  120. socklen_t addr_len;
  121. int server_fd, client_fd, accepted_fd, connect_rc;
  122. if ((server_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  123. perror("socket");
  124. exit(1);
  125. }
  126. addr_len = sizeof(sa);
  127. memset(&sa, 0, sizeof(sa));
  128. sa.sin6_family = AF_INET6;
  129. sa.sin6_addr = in6addr_any;
  130. sa.sin6_port = 0;
  131. if (bind(server_fd, (struct sockaddr*)(&sa), sizeof(sa)) == -1) {
  132. perror("bind");
  133. exit(1);
  134. }
  135. if (getsockname(server_fd, (struct sockaddr*)(&sa), &addr_len) == -1) {
  136. perror("getsockname");
  137. exit(1);
  138. }
  139. if (listen(server_fd, 10) == -1) {
  140. perror("listen");
  141. exit(1);
  142. }
  143. if (addr == V6_LOOPBACK || addr == V6_MAPPED_V4_LOOPBACK) {
  144. char buf[INET6_ADDRSTRLEN];
  145. if ((client_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  146. perror("socket");
  147. exit(1);
  148. }
  149. if (addr == V6_LOOPBACK) {
  150. inet_pton(AF_INET6, "::1", &sa.sin6_addr);
  151. } else if (addr == V6_MAPPED_V4_LOOPBACK) {
  152. inet_pton(AF_INET6, "::ffff:127.0.0.1", &sa.sin6_addr);
  153. }
  154. if (!inet_ntop(AF_INET6, &sa.sin6_addr, buf, INET6_ADDRSTRLEN)) {
  155. perror("inet_ntop");
  156. exit(1);
  157. }
  158. connect_rc = connect(client_fd, (struct sockaddr*)(&sa),
  159. sizeof(struct sockaddr_in6));
  160. write(2, (addr == V6_MAPPED_V4_LOOPBACK) ? "-" : "+", 1);
  161. } else {
  162. struct sockaddr_in sa4;
  163. if ((client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  164. perror("socket");
  165. exit(1);
  166. }
  167. memset(&sa4, 0, sizeof(sa4));
  168. sa4.sin_family = AF_INET;
  169. inet_pton(AF_INET, "127.0.0.1", &sa4.sin_addr);
  170. sa4.sin_port = sa.sin6_port;
  171. connect_rc = connect(client_fd, (struct sockaddr*)(&sa4),
  172. sizeof(struct sockaddr_in));
  173. write(2, ".", 1);
  174. }
  175. if (connect_rc == -1) {
  176. perror("connect");
  177. exit(1);
  178. }
  179. addr_len = sizeof(sa);
  180. if ((accepted_fd = accept(server_fd,
  181. (struct sockaddr*)(&sa), &addr_len)) == -1) {
  182. perror("accept");
  183. exit(1);
  184. }
  185. close(accepted_fd);
  186. close(client_fd);
  187. close(server_fd);
  188. }
  189. // Globals for threaded version.
  190. static volatile int threaded_listening = 0;
  191. static int threaded_server_fd;
  192. static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
  193. static pthread_cond_t threaded_cond = PTHREAD_COND_INITIALIZER;
  194. // Block until listening, then return server address.
  195. static int ThreadedGetServerFD() {
  196. pthread_mutex_lock(&threaded_mutex);
  197. while (!threaded_listening) {
  198. pthread_cond_wait(&threaded_cond, &threaded_mutex);
  199. }
  200. pthread_mutex_unlock(&threaded_mutex);
  201. return threaded_server_fd;
  202. }
  203. // Start a server which accepts one connection.
  204. static void* ThreadedStartServer(void* unused) {
  205. struct sockaddr_in6 sa;
  206. socklen_t addr_len = sizeof(sa);
  207. int accept_fd;
  208. if ((threaded_server_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  209. perror("socket");
  210. exit(1);
  211. }
  212. // Any IP, unused port.
  213. memset(&sa, 0, sizeof(sa));
  214. sa.sin6_family = AF_INET6;
  215. sa.sin6_addr = in6addr_any;
  216. sa.sin6_port = 0;
  217. // Bind.
  218. if (bind(threaded_server_fd, (struct sockaddr*)(&sa), sizeof(sa)) == -1) {
  219. perror("bind");
  220. exit(1);
  221. }
  222. // Listen.
  223. if (listen(threaded_server_fd, 10) == -1) {
  224. perror("listen");
  225. exit(1);
  226. }
  227. pthread_mutex_lock(&threaded_mutex);
  228. threaded_listening = 1;
  229. pthread_cond_signal(&threaded_cond);
  230. pthread_mutex_unlock(&threaded_mutex);
  231. // Try to accept.
  232. if ((accept_fd = accept(threaded_server_fd, (struct sockaddr*)(&sa),
  233. &addr_len)) == -1) {
  234. perror("accept");
  235. exit(1);
  236. }
  237. // All done.
  238. close(threaded_server_fd);
  239. close(accept_fd);
  240. threaded_listening = 0;
  241. return NULL;
  242. }
  243. // Start a server thread, then connect to it via TCP.
  244. static void ThreadedCreateServerConnectAndAccept(enum LoopbackAddr addr) {
  245. pthread_t pthread;
  246. int server_fd, client_fd;
  247. struct sockaddr_in6 sa;
  248. socklen_t addr_len = sizeof(sa);
  249. pthread_create(&pthread, NULL, ThreadedStartServer, NULL);
  250. // Get the server address information -- this call will block until
  251. // the server is listening.
  252. server_fd = ThreadedGetServerFD();
  253. memset(&sa, 0, sizeof(sa));
  254. if (getsockname(server_fd, (struct sockaddr*)(&sa), &addr_len) == -1) {
  255. perror("getsockname");
  256. exit(1);
  257. }
  258. if (addr == V6_LOOPBACK || addr == V6_MAPPED_V4_LOOPBACK) {
  259. char buf[INET6_ADDRSTRLEN];
  260. if ((client_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  261. perror("socket");
  262. exit(1);
  263. }
  264. // Check that we are listening on ::
  265. if (!inet_ntop(AF_INET6, &sa.sin6_addr, buf, INET6_ADDRSTRLEN)) {
  266. fprintf(stderr, "inet_ntop failed\n");
  267. exit(1);
  268. }
  269. if (strlen(buf) != 2) {
  270. fprintf(stderr, "Expected to listen on ::, instead listening on %s", buf);
  271. exit(1);
  272. }
  273. if (addr == V6_LOOPBACK) {
  274. inet_pton(AF_INET6, "::1", &sa.sin6_addr);
  275. } else if (addr == V6_MAPPED_V4_LOOPBACK) {
  276. inet_pton(AF_INET6, "::ffff:127.0.0.1", &sa.sin6_addr);
  277. }
  278. if (connect(client_fd, (struct sockaddr*)(&sa),
  279. sizeof(struct sockaddr_in6)) == -1) {
  280. perror("connect");
  281. exit(1);
  282. }
  283. } else {
  284. struct sockaddr_in sa4;
  285. if ((client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  286. perror("socket");
  287. exit(1);
  288. }
  289. memset(&sa4, 0, sizeof(sa4));
  290. sa4.sin_family = AF_INET;
  291. inet_aton("127.0.0.1", &sa4.sin_addr);
  292. sa4.sin_port = sa.sin6_port;
  293. if (connect(client_fd, (struct sockaddr*)(&sa4),
  294. sizeof(struct sockaddr_in)) == -1) {
  295. perror("connect");
  296. exit(1);
  297. }
  298. }
  299. // Update progress.
  300. switch (addr) {
  301. case V4_LOOPBACK:
  302. write(2, ".", 1);
  303. break;
  304. case V6_MAPPED_V4_LOOPBACK:
  305. write(2, "-", 1);
  306. break;
  307. case V6_LOOPBACK:
  308. write(2, "+", 1);
  309. break;
  310. }
  311. // Close our connection and wait for the server thread to shutdown.
  312. close(client_fd);
  313. pthread_join(pthread, NULL);
  314. }
  315. static void RunWithOneServer(int outer, int inner) {
  316. int i, j, server_fd, port;
  317. fprintf(stderr, "Starting test with one server port for all connects\n");
  318. for (i = 0; i < outer; ++i) {
  319. CreateServer(&server_fd, &port);
  320. for (j = 0; j < inner; ++j) {
  321. ConnectAndAccept(V4_LOOPBACK, server_fd, port);
  322. }
  323. write(2, "\n", 1);
  324. for (j = 0; j < inner; ++j) {
  325. ConnectAndAccept(V6_MAPPED_V4_LOOPBACK, server_fd, port);
  326. }
  327. write(2, "\n", 1);
  328. for (j = 0; j < inner; ++j) {
  329. ConnectAndAccept(V6_LOOPBACK, server_fd, port);
  330. }
  331. write(2, "\n", 1);
  332. close(server_fd);
  333. }
  334. }
  335. static void RunWithOneShotServers(int outer, int inner) {
  336. int i, j;
  337. fprintf(stderr, "Starting test with one server port per connect\n");
  338. for (i = 0; i < outer; ++i) {
  339. for (j = 0; j < inner; ++j) {
  340. CreateServerConnectAndAccept(V4_LOOPBACK);
  341. }
  342. write(2, "\n", 1);
  343. for (j = 0; j < inner; ++j) {
  344. CreateServerConnectAndAccept(V6_MAPPED_V4_LOOPBACK);
  345. }
  346. write(2, "\n", 1);
  347. for (j = 0; j < inner; ++j) {
  348. CreateServerConnectAndAccept(V6_LOOPBACK);
  349. }
  350. write(2, "\n", 1);
  351. }
  352. }
  353. static void RunMultiThreaded(int outer, int inner) {
  354. int i, j;
  355. fprintf(stderr, "Starting multi-threaded test\n");
  356. for (i = 0; i < outer; ++i) {
  357. for (j = 0; j < inner; ++j) {
  358. ThreadedCreateServerConnectAndAccept(V4_LOOPBACK);
  359. }
  360. write(2, "\n", 1);
  361. for (j = 0; j < inner; ++j) {
  362. ThreadedCreateServerConnectAndAccept(V6_MAPPED_V4_LOOPBACK);
  363. }
  364. write(2, "\n", 1);
  365. for (j = 0; j < inner; ++j) {
  366. ThreadedCreateServerConnectAndAccept(V6_LOOPBACK);
  367. }
  368. write(2, "\n", 1);
  369. }
  370. }
  371. static const char* usage =
  372. "Usage: %s [types [outer [inner]]]\n"
  373. "Arguments:\n"
  374. "\ttypes: String consisting of [OMT], for the test types to run\n"
  375. "\t O: One server, multiple connects\n"
  376. "\t M: One server per connect (multiple server ports)\n"
  377. "\t T: Multi-threaded version of \'M\'\n"
  378. "\touter: Number of passes through the outer loops, default 10\n"
  379. "\tinner: Number of passes through the inner loops, default 75\n";
  380. static void Usage(char *argv0) {
  381. fprintf(stderr, usage, argv0);
  382. exit(2);
  383. }
  384. int main(int argc, char** argv) {
  385. char *types = "OMT";
  386. int i, inner = 75, outer = 10, timediff;
  387. struct timeval tv0, tv1;
  388. // Parse the options.
  389. if (argc == 4) {
  390. inner = atoi(argv[3]);
  391. if (inner <= 0) {
  392. Usage(argv[0]);
  393. }
  394. argc--;
  395. }
  396. if (argc == 3) {
  397. outer = atoi(argv[2]);
  398. if (outer <= 0) {
  399. Usage(argv[0]);
  400. }
  401. argc--;
  402. }
  403. if (argc == 2) {
  404. types = argv[1];
  405. if (strspn(types, "OMT") != strlen(types)) {
  406. Usage(argv[0]);
  407. }
  408. argc--;
  409. }
  410. if (argc != 1) {
  411. Usage(argv[0]);
  412. }
  413. // Run the tests.
  414. gettimeofday(&tv0, NULL);
  415. for (i = 0; i < strlen(types); ++i) {
  416. switch (types[i]) {
  417. case 'O':
  418. RunWithOneServer(outer, inner);
  419. break;
  420. case 'M':
  421. RunWithOneShotServers(outer, inner);
  422. break;
  423. case 'T':
  424. RunMultiThreaded(outer, inner);
  425. break;
  426. }
  427. }
  428. gettimeofday(&tv1, NULL);
  429. timediff = (tv1.tv_sec - tv0.tv_sec) * 1000000 + tv1.tv_usec - tv0.tv_usec;
  430. fprintf(stderr, "Total time = %d.%06ds\n", timediff / 1000000,
  431. timediff % 1000000);
  432. exit(0);
  433. }