Skip to content

Commit 76c7d10

Browse files
authored
Use SO_REUSEADDR when binding listening socket in test_sockets_echo_server. NFC (#26680)
This prevents issues with running the test back to back.
1 parent 792783a commit 76c7d10

File tree

2 files changed

+36
-27
lines changed

2 files changed

+36
-27
lines changed

test/sockets/test_sockets_echo_server.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,23 @@ int main() {
212212

213213
ioctlarg_t on = 1;
214214
if (ioctlsocket(server.fd, FIONBIO, &on) == SOCKET_ERROR) {
215-
perror("ioctlsocket failed");
215+
perror("ioctlsocket FIONBIO failed");
216216
exit(EXIT_FAILURE);
217217
}
218218

219+
#ifndef __EMSCRIPTEN__
220+
// This server is compiled using both the host compiler and using emscripten.
221+
// When compiling for the host we use SO_REUSEADDR to avoid `Address already
222+
// in use` errors when repeatedly running a given test. With emscripten
223+
// `SO_REUSEADDR` is not implemented.
224+
// TODO(sbc): Implement/stub SO_REUSEADDR in emscripten.
225+
int opt = 1;
226+
if (setsockopt(server.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == SOCKET_ERROR) {
227+
perror("setsockopt SO_REUSEADDR failed");
228+
exit(EXIT_FAILURE);
229+
}
230+
#endif
231+
219232
memset(&addr, 0, sizeof(addr));
220233
addr.sin_family = AF_INET;
221234
addr.sin_port = htons(SOCKK);
@@ -226,7 +239,7 @@ int main() {
226239

227240
res = bind(server.fd, (struct sockaddr *)&addr, sizeof(addr));
228241
if (res == SOCKET_ERROR) {
229-
perror("bind failed");
242+
fprintf(stderr, "bind (%d) failed: %s\n", SOCKK, strerror(errno));
230243
exit(EXIT_FAILURE);
231244
}
232245

test/test_sockets.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,19 @@ def decorated(self, *args, **kwargs):
5050
return decorated
5151

5252

53-
def clean_processes(processes):
54-
for p in processes:
55-
if getattr(p, 'exitcode', None) is None and getattr(p, 'returncode', None) is None:
56-
# ask nicely (to try and catch the children)
57-
try:
58-
p.terminate() # SIGTERM
59-
except OSError:
60-
pass
61-
time.sleep(1)
62-
# send a forcible kill immediately afterwards. If the process did not die before, this should clean it.
63-
try:
64-
p.terminate() # SIGKILL
65-
except OSError:
66-
pass
53+
def clean_process(p):
54+
if getattr(p, 'exitcode', None) is None and getattr(p, 'returncode', None) is None:
55+
# ask nicely (to try and catch the children)
56+
try:
57+
p.terminate() # SIGTERM
58+
except OSError:
59+
pass
60+
time.sleep(1)
61+
# send a forcible kill immediately afterwards. If the process did not die before, this should clean it.
62+
try:
63+
p.terminate() # SIGKILL
64+
except OSError:
65+
pass
6766

6867

6968
class WebsockifyServerHarness:
@@ -112,7 +111,6 @@ def __enter__(self):
112111
except OSError:
113112
time.sleep(1)
114113
else:
115-
clean_processes(self.processes)
116114
raise Exception('[Websockify failed to start up in a timely manner]')
117115

118116
print('[Websockify on process %s]' % str(self.processes[-2:]))
@@ -125,12 +123,13 @@ def __exit__(self, *args, **kwargs):
125123
self.websockify.join()
126124

127125
# clean up any processes we started
128-
clean_processes(self.processes)
126+
for p in self.processes:
127+
clean_process(p)
129128

130129

131130
class CompiledServerHarness:
132131
def __init__(self, filename, args, listen_port):
133-
self.processes = []
132+
self.process = None
134133
self.filename = filename
135134
self.listen_port = listen_port
136135
self.args = args or []
@@ -149,13 +148,11 @@ def __enter__(self):
149148
proc = run_process([EMCC, '-Werror', test_file(self.filename), '-o', 'server' + suffix, '-DSOCKK=%d' % self.listen_port] + self.args)
150149
print('Socket server build: out:', proc.stdout or '', '/ err:', proc.stderr or '')
151150

152-
process = Popen(config.NODE_JS + ['server' + suffix])
153-
self.processes.append(process)
151+
self.process = Popen(config.NODE_JS + ['server' + suffix])
154152
return self
155153

156154
def __exit__(self, *args, **kwargs):
157-
# clean up any processes we started
158-
clean_processes(self.processes)
155+
clean_process(self.process)
159156

160157
# always run these tests last
161158
# make sure to use different ports in each one because it takes a while for the processes to be cleaned up
@@ -164,17 +161,16 @@ def __exit__(self, *args, **kwargs):
164161
# Executes a native executable server process
165162
class BackgroundServerProcess:
166163
def __init__(self, args):
167-
self.processes = []
164+
self.process = None
168165
self.args = args
169166

170167
def __enter__(self):
171168
print('Running background server: ' + str(self.args))
172-
process = Popen(self.args)
173-
self.processes.append(process)
169+
self.process = Popen(self.args)
174170
return self
175171

176172
def __exit__(self, *args, **kwargs):
177-
clean_processes(self.processes)
173+
clean_process(self.process)
178174

179175

180176
def NodeJsWebSocketEchoServerProcess():

0 commit comments

Comments
 (0)