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;
    }
  }
}
Example #3
0
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;
}