3
#include <sys/socket.h>
4
#include <netinet/in.h>
11
#include <sys/ioctl.h>
14
#include <emscripten.h>
17
#include "test_sockets_msg.h"
19
#define MESSAGE "0123456789"
25
void finish(int result) {
33
void main_loop(void *arg) {
35
static int readPos = 0;
36
static int writePos = 0;
38
ssize_t transferAmount;
43
// writing 10 bytes to the server
45
// since the socket in the read file descriptors has no available data,
46
// select should tell us 0 handles are ready
48
FD_SET(sockfd, &sett);
49
selectRes = select(64, &sett, NULL, NULL, NULL);
51
printf("case 0: read select != 0 (%d)\n", selectRes);
55
// the socket in the write file descriptors has to result in either a 0 or 1
56
// the connection either is setting up or is established and writing is possible
58
FD_SET(sockfd, &sett);
59
selectRes = select(64, NULL, &sett, NULL, NULL);
60
if (selectRes == -1) {
61
printf("case 0: write select == -1\n");
63
} else if (selectRes == 0) {
68
transferAmount = do_msg_write(sockfd, &writemsg, writePos, 1, NULL, 0);
69
if (transferAmount != -1) writePos += transferAmount;
71
// after 10 bytes switch to next state
72
if (writePos >= writemsg.length) {
78
// wait until we can read one byte to make sure the server
79
// has sent the data and then closed the connection
81
FD_SET(sockfd, &sett);
82
selectRes = select(64, &sett, NULL, NULL, NULL);
83
if (selectRes == -1) {
84
printf("case 1: read selectRes == -1\n");
86
} else if (selectRes == 0) {
91
transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL);
92
if (transferAmount == 0) {
93
perror("server closed");
95
} else if (transferAmount != -1) {
96
readPos += transferAmount;
99
// if successfully reading 1 byte, switch to next state
106
// calling select with the socket in the write file descriptors should
107
// succeed, but the socket should not set in the set.
109
FD_SET(sockfd, &sett);
110
selectRes = select(64, NULL, &sett, NULL, NULL);
111
if (selectRes != 0 || FD_ISSET(sockfd, &sett)) {
112
printf("case 2: write selectRes != 0 || FD_ISSET(sockfd, &sett)\n");
113
finish(EXIT_FAILURE);
116
// calling select with the socket in the read file descriptors
117
// has to succeed because there is still data in the inQueue
119
FD_SET(sockfd, &sett);
120
selectRes = select(64, &sett, NULL, NULL, NULL);
121
if (selectRes != 1) {
122
printf("case 2: read selectRes != 1\n");
123
finish(EXIT_FAILURE);
124
} else if (selectRes == 0) {
128
// read a single byte
129
transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL);
130
if (transferAmount == 0) {
131
perror("server closed");
132
finish(EXIT_FAILURE);
133
} else if (transferAmount != -1) {
134
readPos += transferAmount;
137
// with 10 bytes read the inQueue is empty => switch state
138
if (readPos >= readmsg.length) {
144
// calling select with the socket in the read file descriptors
147
FD_SET(sockfd, &sett);
148
selectRes = select(64, &sett, NULL, NULL, NULL);
149
if (selectRes != 1) {
150
printf("case 3: read selectRes != 1\n");
151
finish(EXIT_FAILURE);
154
// but recv should return 0 signaling the remote
155
// end has closed the connection.
156
transferAmount = do_msg_read(sockfd, &readmsg, readPos, 0, NULL, NULL);
157
if (transferAmount) {
158
printf("case 3: read != 0\n");
159
finish(EXIT_FAILURE);
162
// report back success, the 266 is just an arbitrary value without
168
printf("Impossible state!\n");
169
finish(EXIT_FAILURE);
176
// This test checks for an intended asymmetry in the behavior of the select function.
177
// Scenario: the client sends data to the server. After 10 received bytes the
178
// server sends 10 bytes on its own and immediately afterwards closes the connection.
179
// This mimics a typical connect-request-response-disconnect situation.
180
// After the server closed the connection select calls with the socket in the write file
181
// descriptors have to fail as the tcp connection is already down and there is no way
182
// anymore to send data.
183
// Select calls with the socket in the read file descriptor list still have to succeed
184
// as there are still 10 bytes to read from the inQueue. So, for the same socket the
185
// select call behaves differently depending on whether the socket is listed in the
186
// read or write file descriptors.
188
struct sockaddr_in addr;
191
memset(&readmsg, 0, sizeof(msg_t));
192
memset(&writemsg, 0, sizeof(msg_t));
193
writemsg.length = strlen(MESSAGE) + 1;
194
writemsg.buffer = malloc(writemsg.length);
195
strncpy(writemsg.buffer, MESSAGE, writemsg.length);
197
sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
199
perror("cannot create socket");
200
finish(EXIT_FAILURE);
202
fcntl(sockfd, F_SETFL, O_NONBLOCK);
204
memset(&addr, 0, sizeof(addr));
205
addr.sin_family = AF_INET;
206
addr.sin_port = htons(SOCKK);
207
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
208
perror("inet_pton failed");
209
finish(EXIT_FAILURE);
212
// This call should succeed (even if the server port is closed)
213
res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
214
if (res == -1 && errno != EINPROGRESS) {
215
perror("connect failed");
216
finish(EXIT_FAILURE);
220
emscripten_set_main_loop(main_loop, 0, 0);
222
while (1) main_loop(NULL);