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