1
import os, multiprocessing, subprocess
2
from runner import BrowserCore, path_from_root
3
from tools.shared import *
9
# NOTE: may just kill the process in Windows
12
return e.errno == errno.EPERM
15
def kill_pids(pids, sig):
17
if not pid_exists(pid):
19
print '[killing %d]' % pid
22
print '[kill succeeded]'
25
# ask nicely (to try and catch the children)
26
kill_pids(pids, signal.SIGTERM)
28
# extreme prejudice, may leave children
29
kill_pids(pids, signal.SIGKILL)
31
def make_relay_server(port1, port2):
32
print >> sys.stderr, 'creating relay server on ports %d,%d' % (port1, port2)
33
proc = Popen([PYTHON, path_from_root('tests', 'sockets', 'socket_relay.py'), str(port1), str(port2)])
36
class WebsockifyServerHarness:
37
def __init__(self, filename, args, listen_port):
39
self.filename = filename
40
self.listen_port = listen_port
41
self.target_port = listen_port-1
42
self.args = args or []
45
import socket, websockify
48
# NOTE empty filename support is a hack to support
49
# the current test_enet
51
Popen([CLANG_CC, path_from_root('tests', self.filename), '-o', 'server', '-DSOCKK=%d' % self.target_port] + self.args).communicate()
52
process = Popen([os.path.abspath('server')])
53
self.pids.append(process.pid)
55
# start the websocket proxy
56
print >> sys.stderr, 'running websockify on %d, forward to tcp %d' % (self.listen_port, self.target_port)
57
wsp = websockify.WebSocketProxy(verbose=True, listen_port=self.listen_port, target_host="127.0.0.1", target_port=self.target_port, run_once=True)
58
self.websockify = multiprocessing.Process(target=wsp.start_server)
59
self.websockify.start()
60
self.pids.append(self.websockify.pid)
61
print '[Websockify on process %s]' % str(self.pids[-2:])
63
def __exit__(self, *args, **kwargs):
64
# try to kill the websockify proxy gracefully
65
if self.websockify.is_alive():
66
self.websockify.terminate()
67
self.websockify.join()
69
# clean up any processes we started
73
class CompiledServerHarness:
74
def __init__(self, filename, args, listen_port):
76
self.filename = filename
77
self.listen_port = listen_port
78
self.args = args or []
81
# assuming this is only used for WebSocket tests at the moment, validate that
82
# the ws module is installed
83
child = Popen(listify(NODE_JS) + ['-e', 'require("ws");'])
85
assert child.returncode == 0, 'ws module for Node.js not installed. Please run \'npm install\' from %s' % EMSCRIPTEN_ROOT
88
Popen([PYTHON, EMCC, path_from_root('tests', self.filename), '-o', 'server.js', '-DSOCKK=%d' % self.listen_port] + self.args).communicate()
89
process = Popen(listify(NODE_JS) + ['server.js'])
90
self.pids.append(process.pid)
92
def __exit__(self, *args, **kwargs):
93
# clean up any processes we started
96
# always run these tests last
97
# make sure to use different ports in each one because it takes a while for the processes to be cleaned up
99
# NOTE all datagram tests are temporarily disabled, as
100
# we can't truly test datagram sockets until we have
101
# proper listen server support.
103
class sockets(BrowserCore):
107
#include <arpa/inet.h>
110
printf("*%x,%x,%x,%x,%x,%x*\n", htonl(0xa1b2c3d4), htonl(0xfe3572e0), htonl(0x07abcdf0), htons(0xabcd), ntohl(0x43211234), ntohs(0xbeaf));
111
in_addr_t i = inet_addr("190.180.10.78");
116
self.do_run(src, '*d4c3b2a1,e07235fe,f0cdab07,cdab,34122143,afbe*\n4e0ab4be\n')
118
def test_inet2(self):
121
#include <arpa/inet.h>
124
struct in_addr x, x2;
127
printf("%s\n", inet_ntoa(x));
128
int r = inet_aton(inet_ntoa(x), &x2);
129
printf("%s\n", inet_ntoa(x2));
133
self.do_run(src, '120.86.52.18\n120.86.52.18\n')
135
def test_inet3(self):
138
#include <arpa/inet.h>
139
#include <sys/socket.h>
142
struct in_addr x, x2;
145
printf("%s\n", inet_ntop(AF_INET,&x,dst,sizeof dst));
146
int r = inet_aton(inet_ntoa(x), &x2);
147
printf("%s\n", inet_ntop(AF_INET,&x2,dst,sizeof dst));
151
self.do_run(src, '120.86.52.18\n120.86.52.18\n')
153
def test_inet4(self):
154
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
158
#include <arpa/inet.h>
159
#include <sys/socket.h>
161
void test(char *test_addr){
163
struct in6_addr addr;
164
unsigned char *p = (unsigned char*)&addr;
166
ret = inet_pton(AF_INET6,test_addr,&addr);
167
if(ret == -1) return;
169
if(inet_ntop(AF_INET6,&addr,str,sizeof(str)) == NULL ) return;
170
printf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x - %s\n",
171
p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15],str);
177
test("::17.18.19.20");
178
test("::ffff:1.2.3.4");
180
test("::255.255.255.255");
187
test("ffff::a:b:c:d");
188
test("ffff::a:b:c:d:e");
191
test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
192
test("1::255.255.255.255");
194
//below should fail and not produce results..
201
"0000:0000:0000:0000:0000:0000:0000:0000 - ::\n"
202
"0000:0000:0000:0000:0000:0000:0000:0001 - ::1\n"
203
"0000:0000:0000:0000:0000:0000:0102:0304 - ::1.2.3.4\n"
204
"0000:0000:0000:0000:0000:0000:1112:1314 - ::17.18.19.20\n"
205
"0000:0000:0000:0000:0000:ffff:0102:0304 - ::ffff:1.2.3.4\n"
206
"0001:0000:0000:0000:0000:0000:0000:ffff - 1::ffff\n"
207
"0000:0000:0000:0000:0000:0000:ffff:ffff - ::255.255.255.255\n"
208
"0000:ff00:0001:0000:0000:0000:0000:0000 - 0:ff00:1::\n"
209
"0000:00ff:0000:0000:0000:0000:0000:0000 - 0:ff::\n"
210
"abcd:0000:0000:0000:0000:0000:0000:0000 - abcd::\n"
211
"ffff:0000:0000:0000:0000:0000:0000:000a - ffff::a\n"
212
"ffff:0000:0000:0000:0000:0000:000a:000b - ffff::a:b\n"
213
"ffff:0000:0000:0000:0000:000a:000b:000c - ffff::a:b:c\n"
214
"ffff:0000:0000:0000:000a:000b:000c:000d - ffff::a:b:c:d\n"
215
"ffff:0000:0000:000a:000b:000c:000d:000e - ffff::a:b:c:d:e\n"
216
"0000:0000:0000:0001:0002:0000:0000:0000 - ::1:2:0:0:0\n"
217
"0000:0000:0001:0002:0003:0000:0000:0000 - 0:0:1:2:3::\n"
218
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\n"
219
"0001:0000:0000:0000:0000:0000:ffff:ffff - 1::ffff:ffff\n"
222
def test_getaddrinfo(self):
223
self.do_run(open(path_from_root('tests', 'sockets', 'test_getaddrinfo.c')).read(), 'success')
225
def test_getnameinfo(self):
226
self.do_run(open(path_from_root('tests', 'sockets', 'test_getnameinfo.c')).read(), 'success')
228
def test_gethostbyname(self):
229
self.do_run(open(path_from_root('tests', 'sockets', 'test_gethostbyname.c')).read(), 'success')
231
def test_sockets_echo(self):
232
sockets_include = '-I'+path_from_root('tests', 'sockets')
234
# Websockify-proxied servers can't run dgram tests
236
(WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49160), 0),
237
(CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 49161), 0),
238
(CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 49162), 1)
241
for harness, datagram in harnesses:
243
self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram, sockets_include])
245
def test_sockets_echo_bigdata(self):
246
sockets_include = '-I'+path_from_root('tests', 'sockets')
248
# generate a large string literal to use as our message
250
for i in range(256*256*2):
251
message += str(unichr(ord('a') + (i % 26)))
253
# re-write the client test with this literal (it's too big to pass via command line)
254
input_filename = path_from_root('tests', 'sockets', 'test_sockets_echo_client.c')
255
input = open(input_filename).read()
256
output = input.replace('#define MESSAGE "pingtothepong"', '#define MESSAGE "%s"' % message)
259
(WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49170), 0),
260
(CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 49171), 0),
261
(CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 49172), 1)
264
for harness, datagram in harnesses:
266
self.btest(output, expected='0', args=[sockets_include, '-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram], force_c=True)
268
def test_sockets_partial(self):
270
WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_partial_server.c'), [], 49180),
271
CompiledServerHarness(os.path.join('sockets', 'test_sockets_partial_server.c'), [], 49181)
274
self.btest(os.path.join('sockets', 'test_sockets_partial_client.c'), expected='165', args=['-DSOCKK=%d' % harness.listen_port])
276
def test_sockets_select_server_down(self):
278
WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_select_server_down_server.c'), [], 49190),
279
CompiledServerHarness(os.path.join('sockets', 'test_sockets_select_server_down_server.c'), [], 49191)
282
self.btest(os.path.join('sockets', 'test_sockets_select_server_down_client.c'), expected='266', args=['-DSOCKK=%d' % harness.listen_port])
284
def test_sockets_select_server_closes_connection_rw(self):
285
sockets_include = '-I'+path_from_root('tests', 'sockets')
288
WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DCLOSE_CLIENT_AFTER_ECHO'], 49200),
289
CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DCLOSE_CLIENT_AFTER_ECHO'], 49201)
292
self.btest(os.path.join('sockets', 'test_sockets_select_server_closes_connection_client_rw.c'), expected='266', args=[sockets_include, '-DSOCKK=%d' % harness.listen_port])
295
try_delete(self.in_dir('enet'))
296
shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
298
os.chdir(self.in_dir('enet'))
299
Popen([PYTHON, path_from_root('emconfigure'), './configure']).communicate()
300
Popen([PYTHON, path_from_root('emmake'), 'make']).communicate()
301
enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I'+path_from_root('tests', 'enet', 'include')]
305
CompiledServerHarness(os.path.join('sockets', 'test_enet_server.c'), enet, 49210)
308
self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=enet + ['-DSOCKK=%d' % harness.listen_port])
310
# This test is no longer in use for WebSockets as we can't truly emulate
311
# a server in the browser (in the past, there were some hacks to make it
312
# somewhat work, but those have been removed). However, with WebRTC it
313
# should be able to resurect this test.
314
# def test_enet_in_browser(self):
315
# try_delete(self.in_dir('enet'))
316
# shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
318
# os.chdir(self.in_dir('enet'))
319
# Popen([PYTHON, path_from_root('emconfigure'), './configure']).communicate()
320
# Popen([PYTHON, path_from_root('emmake'), 'make']).communicate()
321
# enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I'+path_from_root('tests', 'enet', 'include')]
323
# Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_enet_server.c'), '-o', 'server.html', '-DSOCKK=2235'] + enet).communicate()
325
# with WebsockifyServerHarness('', [], 2235, 2234):
326
# with WebsockifyServerHarness('', [], 2237, 2236):
329
# proc = make_relay_server(2234, 2236)
330
# pids.append(proc.pid)
331
# self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=['-DSOCKK=2237', '-DUSE_IFRAME=1'] + enet)
335
def test_webrtc(self):
336
host_src = 'webrtc_host.c'
337
peer_src = 'webrtc_peer.c'
339
host_outfile = 'host.html'
340
peer_outfile = 'peer.html'
342
host_filepath = path_from_root('tests', 'sockets', host_src)
343
temp_host_filepath = os.path.join(self.get_dir(), os.path.basename(host_src))
344
with open(host_filepath) as f: host_src = f.read()
345
with open(temp_host_filepath, 'w') as f: f.write(self.with_report_result(host_src))
347
peer_filepath = path_from_root('tests', 'sockets', peer_src)
348
temp_peer_filepath = os.path.join(self.get_dir(), os.path.basename(peer_src))
349
with open(peer_filepath) as f: peer_src = f.read()
350
with open(temp_peer_filepath, 'w') as f: f.write(self.with_report_result(peer_src))
352
open(os.path.join(self.get_dir(), 'host_pre.js'), 'w').write('''
355
broker: 'https://mdsw.ch:8080',
357
onpeer: function(peer, route) {
358
window.open('http://localhost:8888/peer.html?' + route);
359
// iframe = document.createElement("IFRAME");
360
// iframe.setAttribute("src", "http://localhost:8888/peer.html?" + route);
361
// iframe.style.display = "none";
362
// document.body.appendChild(iframe);
365
onconnect: function(peer) {
367
ondisconnect: function(peer) {
369
onerror: function(error) {
370
console.error(error);
376
open(os.path.join(self.get_dir(), 'peer_pre.js'), 'w').write('''
379
broker: 'https://mdsw.ch:8080',
380
session: window.location.toString().split('?')[1],
381
onpeer: function(peer, route) {
382
peer.connect(Module['webrtc']['session']);
384
onconnect: function(peer) {
386
ondisconnect: function(peer) {
387
// Calling window.close() from this handler hangs my browser, so run it in the next turn
388
setTimeout(window.close, 0);
390
onerror: function(error) {
391
console.error(error);
397
Popen([PYTHON, EMCC, temp_host_filepath, '-o', host_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'host_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate()
398
Popen([PYTHON, EMCC, temp_peer_filepath, '-o', peer_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'peer_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate()
401
self.run_browser(host_outfile, '.', ['/report_result?' + e for e in expected])