0

I'm having difficulties with this project. Everything's working except for binary files, probably because they're pretty big and would expect timeouts. The packetErrorSends are similar to send but they randomly drop packets. I only put them in the client side to isolate my problem. The algorithm I'm going for is send a piece of the file, if it receives it, send an 's' and continue reading and send the send piece. If it times out, send an 'e' and then hop in the loop, resend the current piece and recv the next status update. "While" checks the status, decides whether to move on or resend that piece. The problem is when is times out, server gets stuck in that loop resending the last chunk of data and client keeps timing out and sending back 'e's (the purpose of the print statements) Any clue what's happening?

client:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "packetErrorSend.h"
#include <sys/time.h>

ssize_t recvx(int sockfd, void *buf, size_t len) {
  int var = recv(sockfd, buf, len, 0);
  if(var != -1)
  {
    return var;
  } else {
    printf("%s \n","Did not receive.");
    exit(1);
  }
}

int main(int argc, char *argv[])
{
  char buf[MAX_PACKET_DATA_SIZE];
  struct addrinfo hints;
  struct addrinfo *rp, *result;
  int bytes_received =  1;
  int s;
  char *server;
  char *port;
  char *file;
  int fd = -1; //file descriptor
  int bytes_written = 1;
  fd_set readfds;
  struct timeval tv;
  int rv = 0;
  int status;
  char sendStatus[1];
  if (argc==4)
  {
    server = argv[1];
    port = argv[2];
    file = argv[3];
  }
  else
  {
    fprintf(stderr, "invalid # of arguments\n");
    exit(1);
  }

  /* Translate host name into peer's IP address */
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = 0;
  hints.ai_protocol = 0;

  if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
  {
    fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
    exit(1);
  }

  /* Iterate through the address list and try to connect */
  for (rp = result; rp != NULL; rp = rp->ai_next)
  {
    if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
    {
      continue;
    }
    if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
    {
      break;
    }
    close(s);
  }

  if (rp == NULL)
  {
    perror("stream-talk-client: connect");
    exit(1);
  }

  freeaddrinfo(result);

  FD_ZERO(&readfds);
  FD_SET(s, &readfds);

  packetErrorSend(s, file, strlen(file)+1, 0);
  tv.tv_sec = 2;
  rv = select(s+1, &readfds, NULL, NULL, &tv);

  if (rv == -1) {
    perror("select"); // error occurred in select()
  } else if (rv == 0) {
    printf("Timeout occurred on filename!  No data after 2 seconds.\n");
    close(s);
    exit(0);
  } else {
    status = recvx(s,buf,1);
  }
  if(status == 0 || buf[0] == 'e')
  {
    fprintf(stderr, "Server Error: unable to access file %s \n", file);
    close(s);
    exit(0);
  }

  if(buf[0] == 's')
  {
    fd =open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if(fd == -1)
    {
      fprintf(stderr,"%s \n","Client Error: Open failed");
      close(s);
      exit(0);
    }

    FD_ZERO(&readfds);
    FD_SET(s, &readfds);
    bytes_received = MAX_PACKET_DATA_SIZE;
    // while(bytes_received >= MAX_PACKET_DATA_SIZE)
    while(bytes_received > 0)
    {
      tv.tv_sec = 3;
      rv = select(s+1, &readfds, NULL, NULL, &tv);
      if (rv == -1) {
        perror("select");
      } else if (rv == 0) {
        printf("bytes_received in timeout %d \n", bytes_received );
        printf("Timeout occurred!  No data after 3 seconds.\n");
        sendStatus[0] = 'e';
        send(s,sendStatus,1,0);
      } else {
        bytes_received = recvx(s, buf, MAX_PACKET_DATA_SIZE);
        printf("%d\n", bytes_received);
        sendStatus[0]='s';
        packetErrorSend(s,sendStatus,1,0);

      }

      bytes_written = write(fd,buf,bytes_received);
      if(bytes_written == -1)
      {
        fprintf(stderr,"%s \n", "Client Error: Write error");
        break;
      }
    }

    if(bytes_received == -1)
    {
      fprintf(stderr,"%s \n", "Client Error: Error receiving file");
      exit(0);
    }
    if(close(fd) != 0)
    {
      printf("%s \n", "Client Error: File did not close successfully");
      exit(0);
    }
    close(s);
  }
  return 0;

}

server:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "packetErrorSend.h"
#include <sys/time.h>

#define SERVER_PORT "5432"
#define MAX_PENDING 5

int main(int argc, char *argv[])
{
  struct addrinfo hints;
  struct addrinfo *rp, *result;
  char file[MAX_PACKET_DATA_SIZE];
  int s, new_s;
  int bytes_transferred = 0;
  int fd; //file descriptor
  char status[1];

  /* Build address data structure */
  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  hints.ai_protocol = 0;
  hints.ai_canonname = NULL;
  hints.ai_addr = NULL;
  hints.ai_next = NULL;

  /* Get local address info */
  if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
  {
    fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
    exit(1);
  }

  /* Iterate through the address list and try to perform passive open */
  for (rp = result; rp != NULL; rp = rp->ai_next)
  {
    if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
    {
      continue;
    }

    if (!bind(s, rp->ai_addr, rp->ai_addrlen))
    {
      break;
    }
    close(s);
  }
  if (rp == NULL)
  {
    perror("stream-talk-server: bind");
    exit(1);
  }
  if (listen(s, MAX_PENDING) == -1)
  {
    perror("stream-talk-server: listen");
    close(s);
    exit(1);
  }

  freeaddrinfo(result);

  /* Wait for connection, then receive and print text */
  while(1)
  {
    for(int i = 0; i < sizeof(file); i++)
    {
      file[i] = '\0';
    }

    if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
    {
      perror("stream-talk-server: accept");
      close(s);
      exit(0);
    }

    if ((bytes_transferred = recv(new_s,file,sizeof(file),0)) > 0)
    {

      fd = open(file,O_RDONLY);
      if(fd < 0)
      {
        perror("open");
        status[0] = 'e';
        send(new_s,status,1,0);
        close(new_s);
        exit(0);
      }
      status[0] = 's';
      send(new_s,status,1,0);
      int datasent = 0;
      bytes_transferred = 1;
      while(bytes_transferred  > 0)    
      {
        status[0] = s;
        bytes_transferred = read(fd,file,MAX_PACKET_DATA_SIZE);
        printf("%d\n",bytes_transferred);
        datasent = send(new_s,file,bytes_transferred,0);
        if (datasent < 0)
        {
          perror("send");
          break;
        }
        recv(new_s,status,1,0);

        printf("before while: %c \n", status[0]);
        while(status[0] == 'e')
        {
          recv(new_s,status,1,0);
          send(new_s,file,bytes_transferred,0);
          printf("in while: %c \n", status[0]);
        }
      }
      if (bytes_transferred == 0)
      {
        break;
      }
      else if(bytes_transferred == -1)
      {
        perror("read");
        close(new_s);
        exit(0);
      }
    }
  }
  close(fd);
  close(new_s);

  return 0;
}
Mike1982
  • 439
  • 10
  • 26
  • I'm not sure I follow. Is the point to *overcome* the unreliability of `packetErrorSend()` to achieve reliable file transfer? – John Bollinger Nov 09 '17 at 23:16
  • yes. so initally we were using send() as reliable. The next phase is to replace send() with packetErrorSend() which drops packets at random and so we have to handle the loss of packets with select statements. The only hint that was given is if the client times out, resend the last packet. However, I'm trying to figure out how to let the server know the client has timed out. – Mike1982 Nov 09 '17 at 23:21
  • What protocol are you using? – Martin James Nov 09 '17 at 23:22
  • stop and wait which should be way easier than sliding window – Mike1982 Nov 09 '17 at 23:27
  • I suggest working out a strategy on paper before trying to convert that to code. List out all the distinct scenarios in which a packet is lost, and devise a strategy for handling each one. This will surely require implementing some new kinds messages. And do not overlook the effect of unreliability on the new messages, too. – John Bollinger Nov 09 '17 at 23:27
  • alright, well my initial strategy laid out on paper, I was thinking of sending the 's' or 'e' message to determine if I'm sending a packet, but then I open another can of worms of what if that gets lost. It's just bouncing back and forth. Maybe just putting a select on the server side might be a better solution. If client times out, then do nothing, keep waiting for data to be read. If server times out, resend the last packet (currently in 'file' buffer). But then I'm back to my original problem of sending the next packet versus sending the current packet. Logic problem I'm struggling with. – Mike1982 Nov 09 '17 at 23:51
  • oh wait, maybe I don't need to do anything. if server times out, resend that packet, else just finish the outer while loop and read the next piece to send – Mike1982 Nov 09 '17 at 23:57
  • ugh no that's not gonna work as is. clients not sending anything for server to receive so can't use select in this case – Mike1982 Nov 10 '17 at 00:05
  • I've updated the code to show the whole thing and current updates. My current status is the client side finished with a blank file and the server keeps going continuously with timeouts. – Mike1982 Nov 10 '17 at 00:32
  • I've updated again with a more specific problem – Mike1982 Nov 11 '17 at 23:32

0 Answers0