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
open_tcp_socket()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
init_sockaddr(struct sockaddr_in & address,unsigned ipAddress,unsigned port)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
tcp_pair(int pair[])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
main(int argc,char ** argv)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