diff options
author | Anthony Pesch <inolen@gmail.com> | 2013-08-07 14:07:43 -0700 |
---|---|---|
committer | Anthony Pesch <inolen@gmail.com> | 2013-08-07 20:38:55 -0700 |
commit | 337817bf6c153f7cc2441c67dbc67ba510ed6b45 (patch) | |
tree | a8a44e10c5128906644f0d39f13f8eb8a15e9c66 /tests/sockets | |
parent | accadc7759ca6e3690749417ef7d26d443bea5f7 (diff) |
renamed socket tests
Diffstat (limited to 'tests/sockets')
-rw-r--r-- | tests/sockets/test_sockets.c | 143 | ||||
-rw-r--r-- | tests/sockets/test_sockets_bi.c | 140 | ||||
-rw-r--r-- | tests/sockets/test_sockets_bi_bigdata.c | 138 | ||||
-rw-r--r-- | tests/sockets/test_sockets_bi_side.c | 93 | ||||
-rw-r--r-- | tests/sockets/test_sockets_bi_side_bigdata.c | 90 | ||||
-rw-r--r-- | tests/sockets/test_sockets_bigdata.h | 20 | ||||
-rw-r--r-- | tests/sockets/test_sockets_gethostbyname.c | 138 | ||||
-rw-r--r-- | tests/sockets/test_sockets_partial.c | 119 | ||||
-rw-r--r-- | tests/sockets/test_sockets_select.c | 98 | ||||
-rw-r--r-- | tests/sockets/test_sockets_select_server_closes_connection.c | 112 | ||||
-rw-r--r-- | tests/sockets/test_sockets_select_server_closes_connection_rw.c | 209 |
11 files changed, 1300 insertions, 0 deletions
diff --git a/tests/sockets/test_sockets.c b/tests/sockets/test_sockets.c new file mode 100644 index 00000000..8845ef43 --- /dev/null +++ b/tests/sockets/test_sockets.c @@ -0,0 +1,143 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 + +int sockfd; +int not_always_data = 0; + +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); + assert(select(64, &sett, NULL, NULL, NULL) == 0); // empty set + FD_SET(sock, &sett); + assert(select(0, &sett, NULL, NULL, NULL) == 0); // max FD to check is 0 + assert(FD_ISSET(sock, &sett) == 0); + FD_SET(sock, &sett); + int select_says_yes = select(64, &sett, NULL, NULL, NULL); + + // ioctl check for IO + 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; + } + + assert(FD_ISSET(sock, &sett)); + assert(select_says_yes); // ioctl must agree with select + + 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!"); + finish(EXIT_FAILURE); + } + memcpy(output+offset, buffer, n); + offset += n; + } + } + + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "error in get_all_buf! %d", errno); + finish(EXIT_FAILURE); + } + return offset; +} + +void iter(void *arg) { + static char out[1024*2]; + static int pos = 0; + 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) { + int i, sum = 0; + for (i=0; i < pos; i++) { + printf("%x\n", out[i]); + sum += out[i]; + } + + shutdown(sockfd, SHUT_RDWR); + + close(sockfd); + + printf("sum: %d\n", sum); + finish(sum); + } +} + +void main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (1) iter(NULL); +#endif +} + diff --git a/tests/sockets/test_sockets_bi.c b/tests/sockets/test_sockets_bi.c new file mode 100644 index 00000000..e19f7fe8 --- /dev/null +++ b/tests/sockets/test_sockets_bi.c @@ -0,0 +1,140 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 28 + +int sockfd; + +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; + + char buffer[1024]; + int n; + unsigned int offset = 0; +#if TEST_FILE_OPS + while((errno = 0, (n = read(sock, buffer, sizeof(buffer)))>0) || +#else + 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!"); + finish(EXIT_FAILURE); + } + memcpy(output+offset, buffer, n); + offset += n; + } + } + + if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "error in get_all_buf!"); + finish(EXIT_FAILURE); + } + return offset; +} + +void iter(void *arg) { + static char out[1024*2]; + static int pos = 0; + 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) { + int i, sum = 0; + for (i=0; i < pos; i++) { + printf("%x\n", out[i]); + sum += out[i]; + } + + shutdown(sockfd, SHUT_RDWR); + close(sockfd); + + printf("sum: %d\n", sum); + finish(sum); + } +} + +int main() { + struct sockaddr_in addr; + int res; + + printf("hello from main page\n"); + +#if !TEST_DGRAM + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); +#else + sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#endif + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN +#if EMBED_SIDE + emscripten_run_script("console.log('adding iframe');" + "var iframe = document.createElement('iframe');" + "iframe.src = 'side.html';" + "document.body.appendChild(iframe);" + "console.log('added.');"); +#endif + emscripten_set_main_loop(iter, 0, 0); +#else + while (1) iter(NULL); +#endif + + return EXIT_SUCCESS; +} diff --git a/tests/sockets/test_sockets_bi_bigdata.c b/tests/sockets/test_sockets_bi_bigdata.c new file mode 100644 index 00000000..c1d8100e --- /dev/null +++ b/tests/sockets/test_sockets_bi_bigdata.c @@ -0,0 +1,138 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#include "test_sockets_bigdata.h" + +#define EXPECTED_BYTES DATA_SIZE + +int sockfd; + +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; + + char buffer[EXPECTED_BYTES]; + 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!"); + finish(EXIT_FAILURE); + } + memcpy(output+offset, buffer, n); + offset += n; + } + } + + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "error in get_all_buf!"); + finish(EXIT_FAILURE); + } + return offset; +} + +void iter(void *arg) { + 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); + res = get_all_buf(sockfd, out+pos, EXPECTED_BYTES-pos); + if (res) printf("read! %d\n", res); + pos += res; + if (pos >= EXPECTED_BYTES) { + shutdown(sockfd, SHUT_RDWR); + + close(sockfd); + + char *comp = generateData(); + int result = strcmp(comp, out); + if (result != 0) { + for (int i = 0; i < DATA_SIZE; i++) { + printf("%d:%d\n", comp[i], out[i]); + } + } + finish(result); + } +} + +int main() { + struct sockaddr_in addr; + int res; + + printf("hello from main page\n"); + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_run_script("console.log('adding iframe');" + "var iframe = document.createElement('iframe');" + "iframe.src = 'side.html';" + "iframe.width = '100%';" + "iframe.width = '40%';" + "document.body.appendChild(iframe);" + "console.log('added.');"); + emscripten_set_main_loop(iter, 3, 0); +#else + 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[] = "hello from the other siide\n"; + + printf("send..\n"); +#if TEST_FILE_OPS + res = write(sockfd, data, sizeof(data)); +#else + res = send(sockfd, data, sizeof(data), 0); +#endif + if (res == -1) { + if (errno != EAGAIN) { + perror("send error"); + finish(EXIT_FAILURE); + } + return; + } + + finish(EXIT_SUCCESS); +} + +int main() { + struct sockaddr_in addr; + int res; +#if !TEST_DGRAM + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); +#else + sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#endif + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + + emscripten_set_main_loop(loop, 0, 0); + + return EXIT_SUCCESS; +} + diff --git a/tests/sockets/test_sockets_bi_side_bigdata.c b/tests/sockets/test_sockets_bi_side_bigdata.c new file mode 100644 index 00000000..e31029b6 --- /dev/null +++ b/tests/sockets/test_sockets_bi_side_bigdata.c @@ -0,0 +1,90 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#include "test_sockets_bigdata.h" + +#define EXPECTED_BYTES 5 + +int sockfd = -1; +char *data = NULL; + +void finish(int result) { + close(sockfd); + exit(result); +} + +void loop() { + fd_set fdw; + int res; + + // make sure that sockfd has finished connecting and is ready to write + FD_ZERO(&fdw); + FD_SET(sockfd, &fdw); + res = select(64, NULL, &fdw, NULL, NULL); + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + return; + } else if (!FD_ISSET(sockfd, &fdw)) { + return; + } + + printf("send..\n"); + + res = send(sockfd, data, DATA_SIZE, 0); + if (res == -1) { + if (errno != EAGAIN) { + perror("send error"); + finish(EXIT_FAILURE); + } + return; + } + + finish(EXIT_SUCCESS); +} + +int main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + 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); + } + + printf("connect..\n"); + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + + data = generateData(); + + emscripten_set_main_loop(loop, 1, 0); + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tests/sockets/test_sockets_bigdata.h b/tests/sockets/test_sockets_bigdata.h new file mode 100644 index 00000000..17149ad6 --- /dev/null +++ b/tests/sockets/test_sockets_bigdata.h @@ -0,0 +1,20 @@ + +#include <stdlib.h> + +#define DATA_SIZE (256*256*2) +// 1500 fails + +char *generateData() { + char *ret = malloc(256*256*2); + char *curr = ret; + for (int i = 0; i < 256; i++) { + for (int j = 0; j < 256; j++) { + *curr = i; + curr++; + *curr = j; + curr++; + } + } + return ret; +} + diff --git a/tests/sockets/test_sockets_gethostbyname.c b/tests/sockets/test_sockets_gethostbyname.c new file mode 100644 index 00000000..59c55ba1 --- /dev/null +++ b/tests/sockets/test_sockets_gethostbyname.c @@ -0,0 +1,138 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 + +int sockfd; + +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; + + 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!"); + finish(EXIT_FAILURE); + } + memcpy(output+offset, buffer, n); + offset += n; + } + } + + if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + perror("error in get_all_buf!"); + finish(EXIT_FAILURE); + } + return offset; +} + +void iter() { + static char out[1024*2]; + 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); + } 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) { + int i, sum = 0; + for (i=0; i < pos; i++) { + printf("%x\n", out[i]); + sum += out[i]; + } + + shutdown(sockfd, SHUT_RDWR); + + close(sockfd); + + printf("sum: %d\n", sum); + + finish(sum); + } +} + +int main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + finish(EXIT_FAILURE); + } + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(SOCKK); + struct hostent *host0 = gethostbyname("test.com"); // increment hostname counter to check for possible but at 0,0 not differentiating low/high + struct hostent *host = gethostbyname("localhost"); + char **raw_addr_list = host->h_addr_list; + int *raw_addr = (int*)*raw_addr_list; + printf("raw addr: %d\n", *raw_addr); + char name[INET_ADDRSTRLEN]; + if (!inet_ntop(AF_INET, raw_addr, name, sizeof(name))) { + printf("could not figure out name\n"); + finish(EXIT_FAILURE); + } + printf("localhost has 'ip' of %s\n", name); + + if (inet_pton(AF_INET, name, &addr.sin_addr) != 1) { + perror("inet_pton failed"); + finish(EXIT_FAILURE); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (1) iter(); +#endif + + return EXIT_SUCCESS; +} + diff --git a/tests/sockets/test_sockets_partial.c b/tests/sockets/test_sockets_partial.c new file mode 100644 index 00000000..5fe34721 --- /dev/null +++ b/tests/sockets/test_sockets_partial.c @@ -0,0 +1,119 @@ +#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 <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +int sockfd = -1; +int sum = 0; + +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} + +void iter(void *arg) { + char buffer[1024]; + char packetLength; + fd_set fdr; + int i; + 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; + } + + res = recv(sockfd, buffer, 1, 0); + if (res == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return; //try again + } + + perror("unexcepted end of data"); + finish(EXIT_FAILURE); + } + + if (res != 1) { + perror("should read 1 byte"); + finish(EXIT_FAILURE); + } + + packetLength = buffer[0]; + res = recv(sockfd, buffer, packetLength, 0); + + printf("got %d,%d\n", res, packetLength); + + if (res != packetLength) { + fprintf(stderr, "lost packet data, expected: %d readed: %d", packetLength, res); + finish(EXIT_FAILURE); + } + + for (i = 0; i < packetLength; ++i) { + if (buffer[i] != i+1) { + fprintf(stderr, "packet corrupted, expected: %d, actual: %d", i+1, buffer[i]); + finish(EXIT_FAILURE); + } + + sum += buffer[i]; + } + + if (packetLength == buffer[0]) { // \x01\x01 - end marker + printf("sum: %d\n", sum); + finish(sum); + } +} + +int main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + 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); + } + + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +} + diff --git a/tests/sockets/test_sockets_select.c b/tests/sockets/test_sockets_select.c new file mode 100644 index 00000000..e05bd4c8 --- /dev/null +++ b/tests/sockets/test_sockets_select.c @@ -0,0 +1,98 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 + +int sockfd = -1; + +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} + +void iter(void *arg) { + static int retries = 0; + + fd_set sett; + FD_ZERO(&sett); + FD_SET(sockfd, &sett); + + // currently, we've connected to a closed server port. + // the initial async connect "succeeded" and select + // should say that the socket is ready for a non-blocking + // read, however, the read should be 0 sized signalling + // that the remote end has closed. + int handles = select(64, &sett, NULL, NULL, NULL); + if (handles == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + } + + if (FD_ISSET(sockfd, &sett)) { + char buffer[1024]; + int n = recv(sockfd, buffer, sizeof(buffer), 0); + if (n == -1 && retries++ > 10) { + perror("revv failed"); + finish(EXIT_FAILURE); + } else if (!n) { + perror("Connection to websocket server failed as expected."); + finish(266); + } + } +} + +// This is for testing a websocket connection to a closed server port. +// The connect call will succeed (due to the asynchronous websocket +// behavior) but once the underlying websocket system realized that +// the connection cannot be established, the next select call will fail. +int main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + // This call should succeed (even if the server port is closed) + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (1) iter(NULL); +#endif + + return EXIT_FAILURE; +} + diff --git a/tests/sockets/test_sockets_select_server_closes_connection.c b/tests/sockets/test_sockets_select_server_closes_connection.c new file mode 100644 index 00000000..4181b12b --- /dev/null +++ b/tests/sockets/test_sockets_select_server_closes_connection.c @@ -0,0 +1,112 @@ +#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 <fcntl.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 + +int sockfd = -1; + +void finish(int result) { + close(sockfd); +#if EMSCRIPTEN + REPORT_RESULT(); +#endif + exit(result); +} + +void iter(void *arg) { + static char readbuf[1024]; + static int readPos = 0; + + fd_set sett; + FD_ZERO(&sett); + FD_SET(sockfd, &sett); + + int res = select(64, &sett, NULL, NULL, NULL); + + if (res == -1) { + perror("select failed"); + finish(EXIT_FAILURE); + } else if (res == 0) { + return; + } else if (res > 0) { + assert(FD_ISSET(sockfd, &sett)); + + int bytesRead = recv(sockfd, readbuf+readPos, 7-readPos, 0); + if (bytesRead == -1) { + if (errno != EAGAIN) { + perror("recv error"); + finish(EXIT_FAILURE); + } + // try again + return; + } + + if (readPos < 7) { + readPos += bytesRead; + } else { + if (!bytesRead) { + perror("Connection to websocket server was closed as expected"); + finish(266); + } else { + perror("Connection to websocket server was not closed"); + finish(EXIT_FAILURE); + } + } + } + + return; +} + +// Scenario: the server sends data and closes the connection after 7 bytes. +// This test should provoke the situation in which the underlying +// tcp connection has been torn down already but there is still data +// in the queue. The select call has to succeed as long the queue +// still contains data and only then start to throw errors. +int main() { + struct sockaddr_in addr; + int res; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { + perror("cannot create socket"); + finish(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); + } + + // This call should succeed (even if the server port is closed) + res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (res == -1 && errno != EINPROGRESS) { + perror("connect failed"); + finish(EXIT_FAILURE); + } + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else |