void main_loop() { int res; fd_set fdr; fd_set fdw; // see if there are any connections to accept or read / write from FD_ZERO(&fdr); FD_ZERO(&fdw); FD_SET(server.fd, &fdr); FD_SET(server.fd, &fdw); #if !TEST_DGRAM if (client.fd) FD_SET(client.fd, &fdr); if (client.fd) FD_SET(client.fd, &fdw); #endif res = select(64, &fdr, &fdw, NULL, NULL); if (res == -1) { perror("select failed"); exit(EXIT_SUCCESS); } #if !TEST_DGRAM // for TCP sockets, we may need to accept a connection if (FD_ISSET(server.fd, &fdr)) { #if TEST_ACCEPT_ADDR // Do an accept with non-NULL addr and addlen parameters. This tests a fix to a bug in the implementation of // accept which had a parameter "addrp" but used "addr" internally if addrp was set - giving a ReferenceError. struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; socklen_t addrlen = sizeof(addr); client.fd = accept(server.fd, (struct sockaddr *) &addr, &addrlen); #else client.fd = accept(server.fd, NULL, NULL); #endif assert(client.fd != -1); } #endif #if !TEST_DGRAM int fd = client.fd; #else int fd = server.fd; #endif if (client.state == MSG_READ) { if (!FD_ISSET(fd, &fdr)) { return; } socklen_t addrlen = sizeof(client.addr); res = do_msg_read(fd, &client.msg, client.read, 0, (struct sockaddr *)&client.addr, &addrlen); if (res == -1) { return; } else if (res == 0) { // client disconnected memset(&client, 0, sizeof(client_t)); return; } client.read += res; // once we've read the entire message, echo it back if (client.read >= client.msg.length) { client.read = 0; client.state = MSG_WRITE; } } if (client.state == MSG_WRITE) { if (!FD_ISSET(fd, &fdw)) { return; } res = do_msg_write(fd, &client.msg, client.wrote, 0, (struct sockaddr *)&client.addr, sizeof(client.addr)); if (res == -1) { return; } else if (res == 0) { // client disconnected memset(&client, 0, sizeof(client_t)); return; } client.wrote += res; if (client.wrote >= client.msg.length) { client.wrote = 0; client.state = MSG_READ; #if CLOSE_CLIENT_AFTER_ECHO close(client.fd); memset(&client, 0, sizeof(client_t)); #endif } } }
void main_loop() { static char out[1024*2]; static int pos = 0; fd_set fdr; fd_set fdw; int res; // make sure that server.fd is ready to read / write FD_ZERO(&fdr); FD_ZERO(&fdw); FD_SET(server.fd, &fdr); FD_SET(server.fd, &fdw); res = select(64, &fdr, &fdw, NULL, NULL); if (res == -1) { perror("select failed"); finish(EXIT_FAILURE); } if (server.state == MSG_READ) { if (!FD_ISSET(server.fd, &fdr)) { return; } #if !TEST_DGRAM // as a test, confirm with ioctl that we have data available // after selecting int available; res = ioctl(server.fd, FIONREAD, &available); assert(res != -1); assert(available); #endif res = do_msg_read(server.fd, &server.msg, echo_read, 0, NULL, NULL); if (res == -1) { return; } else if (res == 0) { perror("server closed"); finish(EXIT_FAILURE); } echo_read += res; // once we've read the entire message, validate it if (echo_read >= server.msg.length) { assert(!strcmp(server.msg.buffer, MESSAGE)); finish(EXIT_SUCCESS); } } if (server.state == MSG_WRITE) { if (!FD_ISSET(server.fd, &fdw)) { return; } res = do_msg_write(server.fd, &echo_msg, echo_wrote, 0, NULL, 0); if (res == -1) { return; } else if (res == 0) { perror("server closed"); finish(EXIT_FAILURE); } echo_wrote += res; // once we're done writing the message, read it back if (echo_wrote >= echo_msg.length) { server.state = MSG_READ; } } }
void main_loop() { static int state = 0; static int readPos = 0; static int writePos = 0; int selectRes; ssize_t transferAmount; fd_set sett; switch (state) { case 0: // writing 10 bytes to the server // since the socket in the read file descriptors has no available data, // select should tell us 0 handles are ready FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, &sett, NULL, NULL, NULL); if (selectRes != 0) { printf("case 0: read select != 0 (%d)\n", selectRes); finish(EXIT_FAILURE); } // the socket in the write file descriptors has to result in either a 0 or 1 // the connection either is setting up or is established and writing is possible FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, NULL, &sett, NULL, NULL); if (selectRes == -1) { printf("case 0: write select == -1\n"); finish(EXIT_FAILURE); } else if (selectRes == 0) { return; } // send a single byte transferAmount = do_msg_write(sockfd, &writemsg, writePos, 1, NULL, 0); if (transferAmount != -1) writePos += transferAmount; // after 10 bytes switch to next state if (writePos >= writemsg.length) { state = 1; } break; case 1: // wait until we can read one byte to make sure the server // has sent the data and then closed the connection FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, &sett, NULL, NULL, NULL); if (selectRes == -1) { printf("case 1: read selectRes == -1\n"); finish(EXIT_FAILURE); } else if (selectRes == 0) { return; } // read a single byte transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL); if (transferAmount == 0) { perror("server closed"); finish(EXIT_FAILURE); } else if (transferAmount != -1) { readPos += transferAmount; } // if successfully reading 1 byte, switch to next state if (readPos >= 1) { state = 2; } break; case 2: // calling select with the socket in the write file descriptors should // succeed, but the socket should not set in the set. FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, NULL, &sett, NULL, NULL); if (selectRes != 0 || FD_ISSET(sockfd, &sett)) { printf("case 2: write selectRes != 0 || FD_ISSET(sockfd, &sett)\n"); finish(EXIT_FAILURE); } // calling select with the socket in the read file descriptors // has to succeed because there is still data in the inQueue FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, &sett, NULL, NULL, NULL); if (selectRes != 1) { printf("case 2: read selectRes != 1\n"); finish(EXIT_FAILURE); } else if (selectRes == 0) { return; } // read a single byte transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL); if (transferAmount == 0) { perror("server closed"); finish(EXIT_FAILURE); } else if (transferAmount != -1) { readPos += transferAmount; } // with 10 bytes read the inQueue is empty => switch state if (readPos >= readmsg.length) { state = 3; } break; case 3: // calling select with the socket in the read file descriptors // should succeed FD_ZERO(&sett); FD_SET(sockfd, &sett); selectRes = select(64, &sett, NULL, NULL, NULL); if (selectRes != 1) { printf("case 3: read selectRes != 1\n"); finish(EXIT_FAILURE); } // but recv should return 0 signaling the remote // end has closed the connection. transferAmount = do_msg_read(sockfd, &readmsg, readPos, 0, NULL, NULL); if (transferAmount) { printf("case 3: read != 0\n"); finish(EXIT_FAILURE); } // report back success, the 266 is just an arbitrary value without // deeper meaning finish(266); break; default: printf("Impossible state!\n"); finish(EXIT_FAILURE); break; } return; }