1 /* 2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 //! A test app trying to reproduce bug #2197. 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <netinet/in.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <sys/select.h> 15 #include <sys/socket.h> 16 17 18 static int 19 open_tcp_socket() 20 { 21 int fd = socket(AF_INET, SOCK_STREAM, 0); 22 if (fd < 0) 23 return -1; 24 25 // make it non-blocking 26 fcntl(fd, F_SETFL, O_NONBLOCK); 27 28 return fd; 29 } 30 31 32 static void 33 init_sockaddr(struct sockaddr_in& address, unsigned ipAddress, unsigned port) 34 { 35 memset(&address, 0, sizeof(sockaddr_in)); 36 address.sin_family = AF_INET; 37 address.sin_port = htons(port); 38 address.sin_addr.s_addr = htonl(ipAddress); 39 } 40 41 42 static int 43 tcp_pair(int pair[]) 44 { 45 pair[0] = pair[1] = -1; 46 47 int listenSocket = open_tcp_socket(); 48 if (listenSocket < 0) 49 return -1; 50 51 sockaddr_in listenAddress; 52 sockaddr_in peerAddress; 53 sockaddr_in address; 54 socklen_t length; 55 init_sockaddr(listenAddress, INADDR_LOOPBACK, 0); 56 57 if (bind(listenSocket, (sockaddr*)&listenAddress, sizeof(sockaddr_in)) != 0) 58 goto error; 59 60 length = sizeof(sockaddr_in); 61 if (getsockname(listenSocket, (sockaddr*)&listenAddress, &length) != 0) 62 goto error; 63 64 if (listen(listenSocket, 5) != 0) 65 goto error; 66 67 pair[0] = open_tcp_socket(); 68 if (pair[0] < 0) 69 goto error; 70 71 init_sockaddr(address, INADDR_LOOPBACK, ntohs(listenAddress.sin_port)); 72 73 if (connect(pair[0], (sockaddr*)&address, sizeof(sockaddr_in)) != 0 74 && errno != EINPROGRESS) 75 goto error; 76 77 if (errno == EINPROGRESS) { 78 struct timeval tv; 79 tv.tv_sec = 100000; 80 tv.tv_usec = 0; 81 fd_set set; 82 FD_ZERO(&set); 83 FD_SET(pair[0], &set); 84 if (select(pair[0] + 1, NULL, &set, NULL, &tv) < 0) 85 fprintf(stderr, "write select() failed: %s\n", strerror(errno)); 86 } 87 88 length = sizeof(sockaddr_in); 89 if (getsockname(pair[0], (sockaddr*)&address, &length) != 0) 90 goto error; 91 92 while (true) { 93 pair[1] = accept(listenSocket, (sockaddr*)&peerAddress, &length); 94 if (pair[1] >= 0) 95 break; 96 97 if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ETIMEDOUT) 98 goto error; 99 100 struct timeval tv; 101 tv.tv_sec = 100000; 102 tv.tv_usec = 0; 103 fd_set set; 104 FD_ZERO(&set); 105 FD_SET(listenSocket, &set); 106 if (select(listenSocket + 1, &set, NULL, NULL, &tv) < 0) 107 fprintf(stderr, "read select() failed: %s\n", strerror(errno)); 108 } 109 110 if (peerAddress.sin_port != address.sin_port) 111 goto error; 112 113 close(listenSocket); 114 return 0; 115 116 error: 117 close(listenSocket); 118 for (int i = 0; i < 2; i++) { 119 if (pair[i] >= 0) 120 close(pair[i]); 121 } 122 123 return -1; 124 } 125 126 127 int 128 main(int argc, char** argv) 129 { 130 int pair[2]; 131 if (tcp_pair(pair) == 0) { 132 close(pair[0]); 133 close(pair[1]); 134 } else 135 fprintf(stderr, "pair failed: %s\n", strerror(errno)); 136 return 0; 137 } 138 139