diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-10-01 16:35:27 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-10-01 16:35:27 -0700 |
commit | 6c8ac389060b685dec87faade39841c2799c4d0a (patch) | |
tree | 497941020c5863a2a0052ad1088b47c2b0b39424 | |
parent | 2a4599a92a570a461a60b1eb79df03908a047711 (diff) |
add socket send(), and almost working test
-rw-r--r-- | src/library.js | 30 | ||||
-rwxr-xr-x | tests/runner.py | 48 | ||||
-rw-r--r-- | tests/socket_relay.py | 55 | ||||
-rw-r--r-- | tests/websockets_bi.c | 134 | ||||
-rw-r--r-- | tests/websockets_bi_side.c | 56 |
5 files changed, 306 insertions, 17 deletions
diff --git a/src/library.js b/src/library.js index 938a3c92..a41887bd 100644 --- a/src/library.js +++ b/src/library.js @@ -6391,6 +6391,29 @@ LibraryManager.library = { console.log('binary!'); } } + info.sendQueue = []; + info.senderWaiting = false; + info.sender = function(data) { + if (data) { + info.sendQueue.push(data); + } else if (info.sendQueue.length == 0) { + return; + } + if (info.socket.readyState != info.socket.OPEN) { + if (!info.senderWaiting) { + console.log('waiting for socket in order to send'); + setTimeout(info.sender, 100); + info.senderWaiting = true; + } + return; + } + for (var i = 0; i < info.sendQueue.length; i++) { + console.log('sending ' + info.sendQueue[i]); + info.socket.send(window.btoa(info.sendQueue[i])); + } + info.sendQueue = []; + info.senderWaiting = false; + } return 0; }, @@ -6413,6 +6436,13 @@ LibraryManager.library = { return ret; }, + send__deps: ['$Sockets'], + send: function(fd, buf, len, flags) { + var info = Sockets.fds[fd]; + if (!info) return -1; + info.sender(Pointer_stringify(buf, len)); + }, + shutdown: function(fd, how) { var info = Sockets.fds[fd]; if (!info) return -1; diff --git a/tests/runner.py b/tests/runner.py index 80926468..7b318412 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -8662,28 +8662,34 @@ elif 'browser' in str(sys.argv): ''') self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js']) + # Runs a websocket server at a specific port. port is the true tcp socket we forward to, port+1 is the websocket one class WebsockHarness: - def __init__(self, port): + def __init__(self, port, server_func=None, no_server=False): self.port = port + self.server_func = server_func + self.no_server = no_server def __enter__(self): self.pids = [] - def server_func(q): - proc = Popen([path_from_root('tests', 'socket_server.sh'), str(self.port)]) - q.put(proc.pid) - proc.communicate() - - server_queue = multiprocessing.Queue() - self.server = multiprocessing.Process(target=server_func, args=(server_queue,)) - self.server.start() - self.pids.append(self.server.pid) - while True: - if not server_queue.empty(): - self.pids.append(server_queue.get()) - break - time.sleep(0.1) - print '[Socket server on processes %s]' % str(self.pids[-2:]) + if not self.no_server: + def server_func(q): + proc = Popen([path_from_root('tests', 'socket_server.sh'), str(self.port)]) + q.put(proc.pid) + proc.communicate() + + server_func = self.server_func or server_func + + server_queue = multiprocessing.Queue() + self.server = multiprocessing.Process(target=server_func, args=(server_queue,)) + self.server.start() + self.pids.append(self.server.pid) + while True: + if not server_queue.empty(): + self.pids.append(server_queue.get()) + break + time.sleep(0.1) + print '[Socket server on processes %s]' % str(self.pids[-2:]) def websockify_func(q): proc = Popen([path_from_root('third_party', 'websockify', 'other', 'websockify'), '-vvv', str(self.port+1), '127.0.0.1:' + str(self.port)]) @@ -8711,7 +8717,15 @@ elif 'browser' in str(sys.argv): with self.WebsockHarness(8990): self.btest('websockets.c', expected='571') - #def test_websockets_bi(self): + def test_zz_websockets_bi(self): + def server_func(q): + proc = Popen(['python', path_from_root('tests', 'socket_relay.py'), '8990', '8995']) + q.put(proc.pid) + proc.communicate() + with self.WebsockHarness(8990, server_func): + with self.WebsockHarness(8995, no_server=True): + Popen(['python', EMCC, path_from_root('tests', 'websockets_bi_side.c'), '-o', 'side.html']).communicate() + self.btest('websockets_bi.c', expected='2499') elif 'benchmark' in str(sys.argv): # Benchmarks. Run them with argument |benchmark|. To run a specific test, do diff --git a/tests/socket_relay.py b/tests/socket_relay.py new file mode 100644 index 00000000..e5b3ccef --- /dev/null +++ b/tests/socket_relay.py @@ -0,0 +1,55 @@ +''' +Listens on 2 ports and relays between them. + +Listens to ports A and B. When someone connects to port A, and then +sends some data to port A, that data is sent to someone who +connected to socket B. And so forth. + +This is different than say socat which will listen to one port +and then make a connection to another port, and do bidirectional +communication. We need to actually listen on both ports. +''' + +import os, sys, socket, time, threading + +ports = [int(sys.argv[1]), int(sys.argv[2])] + +class Listener(threading.Thread): + def run(self): + self.conn = None + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + global ports + port = ports[0] + ports = ports[1:] + print 'listener binding to ', port + s.bind(('127.0.0.1', port)) + s.listen(1) + print 'listener', port, 'waiting for connection' + conn, addr = s.accept() + self.conn = conn + while 1: + time.sleep(1) + print 'listener', port, 'waiting for data' + data = conn.recv(1024) + if not data: + continue + while not self.other.conn: + print 'listener', port, 'waiting for other connection in order to send data' + time.sleep(1) + print 'listener', port, 'sending data', data + self.other.conn.send(data) + +in_listener = Listener() +in_listener.daemon = True +in_listener.start() + +out_listener = Listener() +out_listener.daemon = True +out_listener.start() + +in_listener.other = out_listener +out_listener.other = in_listener + +while 1: + time.sleep(1) + diff --git a/tests/websockets_bi.c b/tests/websockets_bi.c new file mode 100644 index 00000000..338d1caf --- /dev/null +++ b/tests/websockets_bi.c @@ -0,0 +1,134 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 28 + +int SocketFD; + +unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) +{ + int bytes; + if (ioctl(sock, FIONREAD, &bytes)) return 0; + if (bytes == 0) return 0; + + char buffer[1024]; + int n; + unsigned int offset = 0; + while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) || + errno == EINTR) { + if(n>0) + { + if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); } + memcpy(output+offset, buffer, n); + offset += n; + } + } + + if(n < 0) { + fprintf(stderr, "error in get_all_buf!"); + exit(EXIT_FAILURE); + } + return offset; +} + +int done = 0; + +void iter(void *arg) { + /* perform read write operations ... */ + static char out[1024*2]; + static int pos = 0; + int n = get_all_buf(SocketFD, out+pos, 1024-pos); + if (n) printf("read! %d\n", n); + pos += n; + if (pos >= EXPECTED_BYTES) { + int i, sum = 0; + for (i=0; i < pos; i++) { + printf("%x\n", out[i]); + sum += out[i]; + } + + shutdown(SocketFD, SHUT_RDWR); + + close(SocketFD); + + done = 1; + + printf("sum: %d\n", sum); + + emscripten_cancel_main_loop(); + +#if EMSCRIPTEN + int result = sum; + REPORT_RESULT(); +#endif + } +} + +int main(void) +{ + printf("hello from main page\n"); + + struct sockaddr_in stSockAddr; + int Res; + SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (-1 == SocketFD) + { + perror("cannot create socket"); + exit(EXIT_FAILURE); + } + + memset(&stSockAddr, 0, sizeof(stSockAddr)); + + stSockAddr.sin_family = AF_INET; + stSockAddr.sin_port = htons( +#if EMSCRIPTEN + 8991 +#else + 8990 +#endif + ); + Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr); + + if (0 > Res) { + perror("error: first parameter is not a valid address family"); + close(SocketFD); + exit(EXIT_FAILURE); + } else if (0 == Res) { + perror("char string (second parameter does not contain valid ipaddress)"); + close(SocketFD); + exit(EXIT_FAILURE); + } + + if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + perror("connect failed"); + close(SocketFD); + exit(EXIT_FAILURE); + + } + +#if EMSCRIPTEN + emscripten_run_script("console.log('adding iframe');" + "var iframe = document.createElement('iframe');" + "iframe.src = 'side.html';" + "document.body.appendChild(iframe);" + "console.log('added.');"); + emscripten_set_main_loop(iter, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +} + diff --git a/tests/websockets_bi_side.c b/tests/websockets_bi_side.c new file mode 100644 index 00000000..52a2c40e --- /dev/null +++ b/tests/websockets_bi_side.c @@ -0,0 +1,56 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <emscripten.h> + +#define EXPECTED_BYTES 5 + +int main(void) +{ +emscripten_run_script("console.log('hallo from siide')"); + printf("hello from side page\n"); + + struct sockaddr_in stSockAddr; + int Res; + int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (-1 == SocketFD) + { + perror("cannot create socket"); + exit(EXIT_FAILURE); + } + + memset(&stSockAddr, 0, sizeof(stSockAddr)); + + stSockAddr.sin_family = AF_INET; + stSockAddr.sin_port = htons(8996); + Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr); + + if (0 > Res) { + perror("error: first parameter is not a valid address family"); + close(SocketFD); + exit(EXIT_FAILURE); + } else if (0 == Res) { + perror("char string (second parameter does not contain valid ipaddress)"); + close(SocketFD); + exit(EXIT_FAILURE); + } + + if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + perror("connect failed"); + close(SocketFD); + exit(EXIT_FAILURE); + } + + char data[] = "hello from the other siide\n"; + send(SocketFD, data, sizeof(data), 0); + + return EXIT_SUCCESS; +} + |