diff options
22 files changed, 1000 insertions, 1103 deletions
diff --git a/src/library.js b/src/library.js index e85008f3..b68a9324 100644 --- a/src/library.js +++ b/src/library.js @@ -1022,14 +1022,14 @@ LibraryManager.library = { if (relative.charAt(0) !== '.') { throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY); } - // see if the new path alreay exists + // see if the new path already exists var new_node; try { new_node = FS.lookupNode(new_dir, new_name); } catch (e) { // not fatal } - // early out if nothing needs to changews + // early out if nothing needs to change if (old_node === new_node) { return; } @@ -1383,7 +1383,7 @@ LibraryManager.library = { stream.stream_ops.allocate(stream, offset, length); }, mmap: function(stream, buffer, offset, length, position, prot, flags) { - // TODO if PROT is PROT_WRITE, make sure we have write acccess + // TODO if PROT is PROT_WRITE, make sure we have write access if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) { throw new FS.ErrnoError(ERRNO_CODES.EACCES); } @@ -1695,7 +1695,7 @@ LibraryManager.library = { } }, // NOTE: This is weird to support stdout and stderr - // overrides in addition to print and printErr orverrides. + // overrides in addition to print and printErr overrides. default_tty_ops: { get_char: function(tty) { if (!tty.input.length) { @@ -2901,7 +2901,7 @@ LibraryManager.library = { value = ENV['PATH'] || '/'; break; case {{{ cDefine('_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS') }}}: - // Mimicing glibc. + // Mimicking glibc. value = 'POSIX_V6_ILP32_OFF32\nPOSIX_V6_ILP32_OFFBIG'; break; case {{{ cDefine('_CS_GNU_LIBC_VERSION') }}}: @@ -9464,17 +9464,30 @@ LibraryManager.library = { return -1; } - return 0; + // always "fail" in non-blocking mode + ___setErrNo(ERRNO_CODES.EINPROGRESS); + return -1; }, recv__deps: ['$FS'], recv: function(fd, buf, len, flags) { var info = FS.getStream(fd); - if (!info) return -1; - if (!info.hasData()) { - ___setErrNo(ERRNO_CODES.EAGAIN); // no data, and all sockets are nonblocking, so this is the right behavior + if (!info) { + ___setErrNo(ERRNO_CODES.EBADF); return -1; } +#if SOCKET_WEBRTC == 0 + if (!info.hasData()) { + if (info.socket.readyState === WebSocket.CLOSING || info.socket.readyState === WebSocket.CLOSED) { + // socket has closed + return 0; + } else { + // else, our socket is in a valid state but truly has nothing available + ___setErrNo(ERRNO_CODES.EAGAIN); + return -1; + } + } +#endif var buffer = info.inQueue.shift(); #if SOCKET_DEBUG Module.print('recv: ' + [Array.prototype.slice.call(buffer)]); @@ -9496,7 +9509,19 @@ LibraryManager.library = { send__deps: ['$FS'], send: function(fd, buf, len, flags) { var info = FS.getStream(fd); - if (!info) return -1; + if (!info) { + ___setErrNo(ERRNO_CODES.EBADF); + return -1; + } +#if SOCKET_WEBRTC == 0 + if (info.socket.readyState === WebSocket.CLOSING || info.socket.readyState === WebSocket.CLOSED) { + ___setErrNo(ERRNO_CODES.ENOTCONN); + return -1; + } else if (info.socket.readyState === WebSocket.CONNECTING) { + ___setErrNo(ERRNO_CODES.EAGAIN); + return -1; + } +#endif info.sender(HEAPU8.subarray(buf, buf+len)); return len; }, @@ -9634,7 +9659,8 @@ LibraryManager.library = { bind__deps: ['connect'], bind: function(fd, addr, addrlen) { - return _connect(fd, addr, addrlen); + _connect(fd, addr, addrlen); + return 0; }, listen: function(fd, backlog) { @@ -9667,24 +9693,12 @@ LibraryManager.library = { var errorCondition = 0; function canRead(info) { - // make sure hasData exists. - // we do create it when the socket is connected, - // but other implementations may create it lazily - if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED) && info.inQueue.length == 0) { - errorCondition = -1; - return false; - } - return info.hasData && info.hasData(); + return (info.hasData && info.hasData()) || + info.socket.readyState == WebSocket.CLOSING || // let recv return 0 once closed + info.socket.readyState == WebSocket.CLOSED; } function canWrite(info) { - // make sure socket exists. - // we do create it when the socket is connected, - // but other implementations may create it lazily - if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED)) { - errorCondition = -1; - return false; - } return info.socket && (info.socket.readyState == info.socket.OPEN); } @@ -9703,7 +9717,11 @@ LibraryManager.library = { if (int_ & mask) { // index is in the set, check if it is ready for read var info = FS.getStream(fd); - if (info && can(info)) { + if (!info) { + ___setErrNo(ERRNO_CODES.EBADF); + return -1; + } + if (can(info)) { // set bit fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask); bitsSet++; diff --git a/tests/runner.py b/tests/runner.py index e77efffb..096f3426 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -27,6 +27,10 @@ Running the main part of the test suite. Don't forget to run the other parts! benchmark - run before and after each set of changes before pushing to master, verify no regressions browser - runs pages in a web browser + +There are also commands to run specific subsets of the test suite: + + browser sockets - runs websocket networking tests browser audio - runs audio tests in a web browser (requires human verification) To run one of those parts, do something like @@ -12400,6 +12404,24 @@ elif 'browser' in str(sys.argv): 'browser.test_freealut' ] + if 'sockets' in sys.argv: + print + print 'Running the browser socket tests.' + print + i = sys.argv.index('sockets') + sys.argv = sys.argv[:i] + sys.argv[i+1:] + i = sys.argv.index('browser') + sys.argv = sys.argv[:i] + sys.argv[i+1:] + sys.argv += [ + 'browser.test_sockets_bi', + 'browser.test_sockets_gethostbyname', + 'browser.test_sockets_bi_bigdata', + 'browser.test_sockets_select_server_down', + 'browser.test_sockets_select_server_closes_connection', + 'browser.test_sockets_select_server_closes_connection_rw', + 'browser.test_enet' + ] + # Run a server and a web page. When a test runs, we tell the server about it, # which tells the web page, which then opens a window with the test. Doing # it this way then allows the page to close() itself when done. @@ -14011,14 +14033,14 @@ Press any key to continue.''' # always run these tests last # make sure to use different ports in each one because it takes a while for the processes to be cleaned up - def test_websockets(self): + def test_sockets(self): try: with self.WebsockHarness(8990): - self.btest('websockets.c', expected='571') + self.btest('sockets/test_sockets.c', expected='571', args=['-DSOCKK=8991']) finally: self.clean_pids() - def test_websockets_partial(self): + def test_sockets_partial(self): def partial(q): import socket @@ -14041,7 +14063,7 @@ Press any key to continue.''' try: with self.WebsockHarness(8990, partial): - self.btest('websockets_partial.c', expected='165') + self.btest('sockets/test_sockets_partial.c', expected='165', args=['-DSOCKK=8991']) finally: self.clean_pids() @@ -14053,44 +14075,35 @@ Press any key to continue.''' proc.communicate() return relay_server - def test_websockets_bi(self): + def test_sockets_bi(self): for datagram in [0,1]: for fileops in [0,1]: try: print >> sys.stderr, 'test_websocket_bi datagram %d, fileops %d' % (datagram, fileops) - with self.WebsockHarness(8992, self.make_relay_server(8992, 8994)): - with self.WebsockHarness(8994, no_server=True): - Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side.c'), '-o', 'side.html', '-DSOCKK=8995', '-DTEST_DGRAM=%d' % datagram]).communicate() - self.btest('websockets_bi.c', expected='2499', args=['-DSOCKK=8993', '-DTEST_DGRAM=%d' % datagram, '-DTEST_FILE_OPS=%s' % fileops]) + with self.WebsockHarness(6992, self.make_relay_server(6992, 6994)): + with self.WebsockHarness(6994, no_server=True): + Popen([PYTHON, EMCC, path_from_root('tests', 'sockets/test_sockets_bi_side.c'), '-o', 'side.html', '-DSOCKK=6995', '-DTEST_DGRAM=%d' % datagram]).communicate() + self.btest('sockets/test_sockets_bi.c', expected='2499', args=['-DSOCKK=6993', '-DTEST_DGRAM=%d' % datagram, '-DTEST_FILE_OPS=%s' % fileops]) finally: self.clean_pids() - def test_websockets_bi_listen(self): - try: - with self.WebsockHarness(6992, self.make_relay_server(6992, 6994)): - with self.WebsockHarness(6994, no_server=True): - Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side.c'), '-o', 'side.html', '-DSOCKK=6995']).communicate() - self.btest('websockets_bi_listener.c', expected='2499', args=['-DSOCKK=6993']) - finally: - self.clean_pids() - - def test_websockets_gethostbyname(self): + def test_sockets_gethostbyname(self): try: with self.WebsockHarness(7000): - self.btest('websockets_gethostbyname.c', expected='571', args=['-O2']) + self.btest('sockets/test_sockets_gethostbyname.c', expected='571', args=['-O2', '-DSOCKK=7001']) finally: self.clean_pids() - def test_websockets_bi_bigdata(self): + def test_sockets_bi_bigdata(self): try: with self.WebsockHarness(3992, self.make_relay_server(3992, 3994)): with self.WebsockHarness(3994, no_server=True): - Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side_bigdata.c'), '-o', 'side.html', '-DSOCKK=3995', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests')]).communicate() - self.btest('websockets_bi_bigdata.c', expected='0', args=['-DSOCKK=3993', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests')]) + Popen([PYTHON, EMCC, path_from_root('tests', 'sockets/test_sockets_bi_side_bigdata.c'), '-o', 'side.html', '-DSOCKK=3995', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests/sockets')]).communicate() + self.btest('sockets/test_sockets_bi_bigdata.c', expected='0', args=['-DSOCKK=3993', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests/sockets')]) finally: self.clean_pids() - def test_websockets_select_server_down(self): + def test_sockets_select_server_down(self): def closedServer(q): import socket @@ -14099,11 +14112,11 @@ Press any key to continue.''' ssock.bind(("127.0.0.1", 8994)) try: with self.WebsockHarness(8994, closedServer): - self.btest('websockets_select.c', expected='266') + self.btest('sockets/test_sockets_select.c', expected='266', args=['-DSOCKK=8995']) finally: self.clean_pids() - def test_websockets_select_server_closes_connection(self): + def test_sockets_select_server_closes_connection(self): def closingServer(q): import socket @@ -14119,11 +14132,11 @@ Press any key to continue.''' try: with self.WebsockHarness(8994, closingServer): - self.btest('websockets_select_server_closes_connection.c', expected='266') + self.btest('sockets/test_sockets_select_server_closes_connection.c', expected='266', args=['-DSOCKK=8995']) finally: self.clean_pids() - def test_websockets_select_server_closes_connection_rw(self): + def test_sockets_select_server_closes_connection_rw(self): def closingServer_rw(q): import socket @@ -14151,7 +14164,7 @@ Press any key to continue.''' try: with self.WebsockHarness(8998, closingServer_rw): - self.btest('websockets_select_server_closes_connection_rw.c', expected='266') + self.btest('sockets/test_sockets_select_server_closes_connection_rw.c', expected='266', args=['-DSOCKK=8999']) finally: self.clean_pids() diff --git a/tests/websockets.c b/tests/sockets/test_sockets.c index 8882f5ba..8845ef43 100644 --- a/tests/websockets.c +++ b/tests/sockets/test_sockets.c @@ -7,6 +7,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> #include <sys/ioctl.h> #include <assert.h> #if EMSCRIPTEN @@ -15,12 +16,18 @@ #define EXPECTED_BYTES 5 -int SocketFD; - +int sockfd; int not_always_data = 0; -unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) -{ +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} + +unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) { // select check for IO fd_set sett; FD_ZERO(&sett); @@ -35,6 +42,7 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) int bytes; if (ioctl(sock, FIONREAD, &bytes) || bytes == 0) { not_always_data = 1; + printf("ioctl says 0, FD_ISSET says %ld\n", FD_ISSET(sock, &sett)); assert(FD_ISSET(sock, &sett) == 0); return 0; } @@ -47,28 +55,42 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) 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); } + if(n > 0) { + if (((unsigned int) n)+offset > maxsize) { + fprintf(stderr, "too much data!"); + finish(EXIT_FAILURE); + } memcpy(output+offset, buffer, n); offset += n; } } - if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { fprintf(stderr, "error in get_all_buf! %d", errno); - exit(EXIT_FAILURE); + finish(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); + fd_set fdr; + int res; + + // make sure that sockfd is ready to read + FD_ZERO(&fdr); + FD_SET(sockfd, &fdr); + res = select(64, &fdr, NULL, NULL, NULL); + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + } else if (!FD_ISSET(sockfd, &fdr)) { + return; + } + + // perform read write operations ... + int n = get_all_buf(sockfd, out+pos, 1024-pos); if (n) printf("read! %d\n", n); pos += n; if (pos >= EXPECTED_BYTES) { @@ -78,70 +100,44 @@ void iter(void *arg) { sum += out[i]; } - shutdown(SocketFD, SHUT_RDWR); - - close(SocketFD); + shutdown(sockfd, SHUT_RDWR); - done = 1; + close(sockfd); printf("sum: %d\n", sum); - -#if EMSCRIPTEN - //assert(not_always_data == 1); - - int result = sum; - REPORT_RESULT(); -#endif + finish(sum); } } -int main(void) -{ - struct sockaddr_in stSockAddr; - int Res; - SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); +void main() { + struct sockaddr_in addr; + int res; - if (-1 == SocketFD) - { + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { perror("cannot create socket"); - exit(EXIT_FAILURE); + finish(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); + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(SOCKK); + if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) { + perror("inet_pton failed"); + finish(EXIT_FAILURE); } - - if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { perror("connect failed"); - close(SocketFD); - exit(EXIT_FAILURE); - + finish(EXIT_FAILURE); } #if EMSCRIPTEN emscripten_set_main_loop(iter, 0, 0); #else - while (!done) iter(NULL); + while (1) iter(NULL); #endif - - return EXIT_SUCCESS; } diff --git a/tests/websockets_bi.c b/tests/sockets/test_sockets_bi.c index fb60177b..4266d20c 100644 --- a/tests/websockets_bi.c +++ b/tests/sockets/test_sockets_bi.c @@ -7,6 +7,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> #include <sys/ioctl.h> #if EMSCRIPTEN #include <emscripten.h> @@ -14,14 +15,17 @@ #define EXPECTED_BYTES 28 -#ifndef SOCKK -#define SOCKK 8992 -#endif +int sockfd; -int SocketFD; +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} -unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) -{ +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; @@ -35,9 +39,11 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) || #endif errno == EINTR) { - if(n>0) - { - if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); } + if(n > 0) { + if (((unsigned int) n)+offset > maxsize) { + fprintf(stderr, "too much data!"); + finish(EXIT_FAILURE); + } memcpy(output+offset, buffer, n); offset += n; } @@ -45,18 +51,30 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { fprintf(stderr, "error in get_all_buf!"); - exit(EXIT_FAILURE); + finish(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); + fd_set fdr; + int res; + + // make sure that sockfd is ready to read + FD_ZERO(&fdr); + FD_SET(sockfd, &fdr); + res = select(64, &fdr, NULL, NULL, NULL); + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + } else if (!FD_ISSET(sockfd, &fdr)) { + return; + } + + // perform read write operations ... + int n = get_all_buf(sockfd, out+pos, 1024-pos); if (n) printf("read! %d\n", n); pos += n; if (pos >= EXPECTED_BYTES) { @@ -66,62 +84,43 @@ void iter(void *arg) { sum += out[i]; } - shutdown(SocketFD, SHUT_RDWR); - - close(SocketFD); - - done = 1; + shutdown(sockfd, SHUT_RDWR); + close(sockfd); printf("sum: %d\n", sum); - - emscripten_cancel_main_loop(); - -#if EMSCRIPTEN - int result = sum; - REPORT_RESULT(); -#endif + finish(sum); } } -int main(void) -{ +int main() { + struct sockaddr_in addr; + int res; + printf("hello from main page\n"); - struct sockaddr_in stSockAddr; - int Res; #if !TEST_DGRAM - SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); #else - SocketFD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); #endif - - if (-1 == SocketFD) - { + if (sockfd == -1) { perror("cannot create socket"); - exit(EXIT_FAILURE); + finish(EXIT_FAILURE); } - - memset(&stSockAddr, 0, sizeof(stSockAddr)); - - stSockAddr.sin_family = AF_INET; - stSockAddr.sin_port = htons(SOCKK); - 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); + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(SOCKK); + if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) { + perror("inet_pton failed"); + finish(EXIT_FAILURE); } - - if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { perror("connect failed"); - close(SocketFD); - exit(EXIT_FAILURE); - + finish(EXIT_FAILURE); } #if EMSCRIPTEN @@ -132,9 +131,8 @@ int main(void) "console.log('added.');"); emscripten_set_main_loop(iter, 0, 0); #else - while (!done) iter(NULL); + while (1) iter(NULL); #endif return EXIT_SUCCESS; } - diff --git a/tests/websockets_bi_bigdata.c b/tests/sockets/test_sockets_bi_bigdata.c index 2039f83c..c1d8100e 100644 --- a/tests/websockets_bi_bigdata.c +++ b/tests/sockets/test_sockets_bi_bigdata.c @@ -7,19 +7,27 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> #include <sys/ioctl.h> #if EMSCRIPTEN #include <emscripten.h> #endif -#include "websockets_bigdata.h" +#include "test_sockets_bigdata.h" #define EXPECTED_BYTES DATA_SIZE -int SocketFD; +int sockfd; -unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) -{ +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} + +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; @@ -29,41 +37,51 @@ unsigned int get_all_buf(int sock, char* output, unsigned int maxsize) 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); } + if (n > 0) { + if (((unsigned int) n)+offset > maxsize) { + fprintf(stderr, "too much data!"); + finish(EXIT_FAILURE); + } memcpy(output+offset, buffer, n); offset += n; } } - if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { fprintf(stderr, "error in get_all_buf!"); - exit(EXIT_FAILURE); + finish(EXIT_FAILURE); } return offset; } -int done = 0; - void iter(void *arg) { - /* perform read write operations ... */ static char out[EXPECTED_BYTES]; static int pos = 0; + fd_set fdr; + int res; + + // make sure that sockfd has finished connecting and is ready to read + FD_ZERO(&fdr); + FD_SET(sockfd, &fdr); + res = select(64, &fdr, NULL, NULL, NULL); + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + return; + } else if (!FD_ISSET(sockfd, &fdr)) { + return; + } + + // perform read write operations ... printf("so far %d, expecting up to %d\n", pos, EXPECTED_BYTES-pos); - int n = get_all_buf(SocketFD, out+pos, EXPECTED_BYTES-pos); - if (n) printf("read! %d\n", n); - pos += n; + res = get_all_buf(sockfd, out+pos, EXPECTED_BYTES-pos); + if (res) printf("read! %d\n", res); + pos += res; if (pos >= EXPECTED_BYTES) { - shutdown(SocketFD, SHUT_RDWR); - - close(SocketFD); - - done = 1; + shutdown(sockfd, SHUT_RDWR); - emscripten_cancel_main_loop(); + close(sockfd); -#if EMSCRIPTEN char *comp = generateData(); int result = strcmp(comp, out); if (result != 0) { @@ -71,52 +89,35 @@ void iter(void *arg) { printf("%d:%d\n", comp[i], out[i]); } } - REPORT_RESULT(); -#endif + finish(result); } } -int main(void) -{ - printf("hello from main page\n"); +int main() { + struct sockaddr_in addr; + int res; - struct sockaddr_in stSockAddr; - int Res; - SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + printf("hello from main page\n"); - if (-1 == SocketFD) - { + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { perror("cannot create socket"); - exit(EXIT_FAILURE); + finish(EXIT_FAILURE); } - - memset(&stSockAddr, 0, sizeof(stSockAddr)); - - stSockAddr.sin_family = AF_INET; - stSockAddr.sin_port = htons( -#if EMSCRIPTEN - 3993 -#else - 3992 -#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); + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(SOCKK); + if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) { + perror("inet_pton failed"); + finish(EXIT_FAILURE); } - if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { perror("connect failed"); - close(SocketFD); - exit(EXIT_FAILURE); - + finish(EXIT_FAILURE); } #if EMSCRIPTEN @@ -129,7 +130,7 @@ int main(void) "console.log('added.');"); emscripten_set_main_loop(iter, 3, 0); #else - while (!done) iter(NULL); + while (1) iter(NULL); #endif return EXIT_SUCCESS; diff --git a/tests/sockets/test_sockets_bi_side.c b/tests/sockets/test_sockets_bi_side.c new file mode 100644 index 00000000..b8910632 --- /dev/null +++ b/tests/sockets/test_sockets_bi_side.c @@ -0,0 +1,93 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 + +int sockfd = -1; + +void finish(int result) { + close(sockfd); + exit(result); +} + +void loop() { + fd_set fdw; + int res; + + // Make sure that sockfd has actually finished connecting + // and is ready to read. + FD_ZERO(&fdw); + FD_SET(sockfd, &fdw); + res = select(64, NULL, &fdw, NULL, NULL); + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + } else if (!FD_ISSET(sockfd, &fdw)) { + return; + } + + char data[] |