Ticket #9678: socket_test_send_recv_2_sockets.c

File socket_test_send_recv_2_sockets.c, 5.0 KB (added by markh, 7 years ago)
Line 
1#include <stdlib.h>
2#include <netdb.h>
3#include <sys/select.h>
4#include <stdio.h>
5#include <errno.h>
6#include <fcntl.h>
7
8static struct sockaddr_storage pgStatAddr;
9
10typedef int bool;
11
12void
13socket_test_send_recv(void)
14{
15
16 int pgStatSock = -1;
17 int pgStatSock2 = -1;
18 socklen_t alen;
19 struct addrinfo *addrs = NULL,
20 *addr,
21 hints;
22 int ret;
23 fd_set rset;
24 struct timeval tv;
25 char test_byte;
26 int sel_res;
27 bool retry = 1;
28
29#define TESTBYTEVAL ((char) 199)
30
31 /*
32 * Create the UDP socket for sending and receiving statistic messages
33 */
34 hints.ai_flags = AI_PASSIVE;
35 hints.ai_family = PF_UNSPEC;
36 hints.ai_socktype = SOCK_DGRAM;
37 hints.ai_protocol = 0;
38 hints.ai_addrlen = 0;
39 hints.ai_addr = NULL;
40 hints.ai_canonname = NULL;
41 hints.ai_next = NULL;
42 ret = getaddrinfo("localhost", NULL, &hints, &addrs);
43 if (ret || !addrs) {
44 printf("could not resolve \"localhost\": %s\n", gai_strerror(ret));
45 }
46 else {
47
48 /*
49 * Loop through the results to try and find a working address.
50 */
51 for (addr = addrs; addr; addr = addr->ai_next)
52 {
53 /*
54 * Create the socket.
55 */
56 if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) == -1)
57 {
58 printf("could not create socket for statistics collector\n");
59 continue;
60 }
61
62 /*
63 * Bind it to a kernel assigned port on localhost and get the assigned
64 * port via getsockname().
65 */
66 if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
67 {
68 printf("could not bind socket for statistics collector\n");
69 closesocket(pgStatSock);
70 pgStatSock = -1;
71 continue;
72 }
73
74 alen = sizeof(pgStatAddr);
75 if (getsockname(pgStatSock, (struct sockaddr *) & pgStatAddr, &alen) < 0)
76 {
77 printf("could not get address of socket for statistics collector\n");
78 closesocket(pgStatSock);
79 pgStatSock = -1;
80 continue;
81 }
82
83 /*
84 * Open a second socket to do the send as we apparently can't
85 * send through the socket that we use to receive the data.
86 */
87 if ((pgStatSock2 = socket(addr->ai_family, SOCK_DGRAM, 0)) == -1)
88 {
89 printf("could not create socket for statistics collector\n");
90 continue;
91 }
92 if (connect(pgStatSock2, (struct sockaddr *) & pgStatAddr, alen) < 0)
93 {
94 printf("could not connect socket for statistics collector\n");
95 closesocket(pgStatSock2);
96 pgStatSock2 = -1;
97 continue;
98 }
99
100 /*
101 * Try to send and receive a one-byte test message on the socket. This
102 * is to catch situations where the socket can be created but will not
103 * actually pass data (for instance, because kernel packet filtering
104 * rules prevent it).
105 */
106 test_byte = TESTBYTEVAL;
107
108 while (retry) {
109 if (send(pgStatSock2, &test_byte, 1, 0) != 1) {
110 /* if not interrupted, bail out */
111 if (errno != EINTR) {
112 retry = 0;
113 printf("could not send test message on socket for statistics collector\n");
114 closesocket(pgStatSock2);
115 pgStatSock2 = -1;
116 continue;
117 }
118 }
119 else {
120 retry = 0;
121 }
122 }
123
124 /*
125 * There could possibly be a little delay before the message can be
126 * received. We arbitrarily allow up to half a second before deciding
127 * it's broken.
128 */
129 for (;;) /* need a loop to handle EINTR */
130 {
131 FD_ZERO(&rset);
132 FD_SET(pgStatSock, &rset);
133
134 tv.tv_sec = 0;
135 tv.tv_usec = 500000;
136 sel_res = select(pgStatSock + 1, &rset, NULL, NULL, &tv);
137 if (sel_res >= 0 || errno != EINTR)
138 break;
139 }
140 if (sel_res < 0)
141 {
142 printf("select() failed in statistics collector\n");
143 closesocket(pgStatSock);
144 pgStatSock = -1;
145 continue;
146 }
147 if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset))
148 {
149 /*
150 * This is the case we actually think is likely, so take pains to
151 * give a specific message for it.
152 *
153 * errno will not be set meaningfully here, so don't use it.
154 */
155 printf("test message did not get through on socket for statistics collector\n");
156 closesocket(pgStatSock);
157 pgStatSock = -1;
158 continue;
159 }
160
161 test_byte++; /* just make sure variable is changed */
162
163 retry = 1;
164 while (retry) {
165 if (recv(pgStatSock, &test_byte, 1, 0) != 1) {
166 /* if not interrupted, bail out */
167 if (errno != EINTR) {
168 retry = 0;
169 printf("Errno: %i\n", errno);
170 printf("String error: %s\n", strerror(errno));
171 printf("could not receive test message on socket for statistics collector\n");
172 closesocket(pgStatSock);
173 pgStatSock = -1;
174 continue;
175 }
176 }
177 else {
178 retry = 0;
179 }
180 }
181
182 if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */
183 {
184 printf("incorrect test message transmission on socket for statistics collector\n");
185 closesocket(pgStatSock);
186 pgStatSock = -1;
187 continue;
188 }
189
190 /* If we get here, we have a working socket */
191 printf("We have a working socket!\n");
192
193 if (pgStatSock > -1) {
194 closesocket(pgStatSock);
195 }
196 if (pgStatSock2 > -1) {
197 closesocket(pgStatSock2);
198 }
199 break;
200 }
201 }
202
203 if (addrs != NULL)
204 freeaddrinfo(addrs);
205
206}
207
208int main(int argc, char **argv) {
209
210 socket_test_send_recv();
211
212 return 0;
213
214}