Ticket #9678: socket_test_send_recv_1_socket.c

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