CS118-Project-2 / client.cpp
client.cpp
Raw
#include "shared.h"

#define MYPORT 8080

using namespace std;

int sendFile(string fileName, int sockfd, int id, int initialACK, addrinfo*p);
void sendSyn(int sockfd, addrinfo*p);
void sendSYNACKResponse(CPacket pc, int sockfd, addrinfo*p);
void endConnection(unsigned int s, unsigned short cID, int sockfd, addrinfo*p);

int masterCwnd = 512;
int masterSSThresh = INIT_SSTHRESH;

int msDiff(struct timeval t1, struct timeval t2)
{
    return (((t1.tv_sec - t2.tv_sec) * 1000000) + (t1.tv_usec - t2.tv_usec))/1000;
}

void printSent(CPacket p, int cwnd, int ssthresh, bool dup = false){
  cout << "SEND " << p.mSeqNum << " ";
  cout << p.mAckNum << " " << p.mID << " ";
  cout << cwnd << " " << ssthresh;
  if(p.flags & 4){
    cout << " ACK";
  }
  if(p.flags & 2){
    cout << " SYN";
  }
  if(p.flags & 1){
    cout << " FIN";
  }
  if(dup){
    cout << " DUP";
  }
  cout << endl;
}

void printRecv(CPacket p, int cwnd, int ssthresh){
  cout << "RECV " << p.mSeqNum << " ";
  cout << p.mAckNum << " " << p.mID << " ";
  cout << cwnd << " " << ssthresh;
  if(p.flags & 4){
    cout << " ACK";
  }
  if(p.flags & 2){
    cout << " SIN";
  }
  if(p.flags & 1){
    cout << " FIN";
  }
  cout << endl;
}


int main(int argc, char * argv[])
{
  if(argc != 4){
    std::cerr << "ERROR: Not enough arguments to set up client" << endl;
    exit(EXIT_FAILURE);
  }



  string ipString = argv[1]; // get host name or ip address from arguments
  string portString = argv[2]; //get port number
  string fileName = argv[3]; //get filename 

  

  //make sure port number is in fact a number
  for(char c : portString) {
    if(!isdigit(c)) {
      cerr << "ERROR: Not a port number" << endl;
      exit(EXIT_FAILURE);
    }
  }

  bool foundDigit = false;
  for(char c : ipString) {
    if(isdigit(c)){
      foundDigit = true;
    } else if(!isdigit(c) && foundDigit){
      if(c == '.'){
        continue;
      } else {
        cerr << "ERROR: bad hostname or ip" << endl;
        exit(EXIT_FAILURE);
      }
    }
  }

  

  int portNum = stoi(argv[2]);

  if(portNum < PORT_MIN || portNum > PORT_MAX) { // make sure port number isnt too large or small
    cerr << "ERROR: Invalid port number" << endl;
    exit(EXIT_FAILURE);
  }

  //now set up the socket
  int sockfd;
  struct addrinfo hints, *p;
  memset(&hints, 0, sizeof(hints));
  hints.ai_family   = AF_INET;
  hints.ai_socktype = SOCK_DGRAM;
  //hints.ai_flags    = AI_PASSIVE;

  int gAddRes = getaddrinfo(argv[1], argv[2], &hints, &p);
  if (gAddRes != 0) {
      std::cerr << "ERROR: getaddrinfo error" << endl;
      exit(EXIT_FAILURE);
  }

  if (p == NULL) {
      std::cerr << "ERROR: No addresses found\n";
      exit(EXIT_FAILURE);
  }
  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
    cerr << "ERROR: Socket failed" << endl;
    exit(EXIT_FAILURE);
  }

  struct timeval timeout;
  timeout.tv_sec = 10;
  timeout.tv_usec = 0;
  setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));


  //connection established
  //send and read messages here*

  //Start 3 way handshake: send syn
  struct CPacket response;
  response.mAckNum = 0;
  unsigned short connectionID = 0;

  
  sendSyn(sockfd,p);

  
  while(true){
    int bytesRecv = recvfrom(sockfd, &response, sizeof(response), 0, (struct sockaddr *)p->ai_addr, &(p->ai_addrlen));
    response = convertCPacketToHost(response);
    printRecv(response, masterCwnd, masterSSThresh);
    if(bytesRecv < 0){
      cerr << "ERROR: bad recv" << endl;
      exit(EXIT_FAILURE);
    }
    else if(bytesRecv == 0) {
      cerr << "ERROR: server did not send any data" << endl;
      exit(EXIT_FAILURE);
    }
    else if((bool) ((response.flags & 2) >> 1) && (bool) ((response.flags & 4) >> 2)){
      connectionID = response.mID;
      sendSYNACKResponse(response, sockfd,p);
      unsigned int finalSeq = sendFile(fileName, sockfd, connectionID, response.mSeqNum, p);
      endConnection(finalSeq, connectionID, sockfd, p);  
      break;
    } 
    else{
      cerr << "ERROR: response to syn packet has wrong flags" << endl;
      exit(EXIT_FAILURE);
    }
  }

  
  close(portNum);
  return 0;

}

void sendSyn(int sockfd, addrinfo* p){
  struct CPacket syn;
  syn.mSeqNum = INITIAL_SEQ_C;
  syn.mAckNum = 0;
  syn.mID = 0;
  syn.flags = 2;

  struct CPacket newSyn = convertCPacketToNetwork(syn);
  int s = sendto(sockfd, &newSyn, HEAD_SIZE, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen);
  if(s < 0){
    cerr << "ERROR: bad send with syn" << endl;
    exit(EXIT_FAILURE);
  }
  printSent(syn, masterCwnd, masterSSThresh);
}

void sendSYNACKResponse(CPacket pc, int sockfd, addrinfo* p){
  struct CPacket r;
  r.mSeqNum = (INITIAL_SEQ_C + 1) % (MAX_NUM + 1);
  r.mAckNum = (pc.mSeqNum + 1) % (MAX_NUM + 1);
  r.mID = pc.mID;
  r.flags = 4;
  struct CPacket newr = convertCPacketToNetwork(r);
  
  if(sendto(sockfd, &newr, 12, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1){
    cerr << "ERROR: cant send synack response" << endl;
    exit(EXIT_FAILURE);
  }

  printSent(r, masterCwnd, masterSSThresh);

  struct CPacket response;
  int test = recvfrom(sockfd, &response, sizeof(response), 0, (struct sockaddr *)p->ai_addr, &(p->ai_addrlen));
  response = convertCPacketToHost(response);
  printRecv(response, masterCwnd, masterSSThresh);
  if(masterCwnd < masterSSThresh && (response.flags & 4)){
    masterCwnd += 512;
  } else if (response.flags & 4){
    masterCwnd += (512 * 512) / masterCwnd;
  }
}

//function for doing final FIN handshake
void endConnection(unsigned int s, unsigned short cID, int sockfd, addrinfo*p){
  struct timeval timeout;
  timeout.tv_sec = 4;
  timeout.tv_usec = 0;
  setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

  struct timeval start, end;
  CPacket fin;
  CPacket response;
  fin.mSeqNum = s % (MAX_NUM + 1);
  fin.mAckNum = 0;
  fin.mID = cID;
  fin.flags = 1;

  CPacket newFin = convertCPacketToNetwork(fin);
  if(sendto(sockfd, &newFin, HEAD_SIZE, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1)
  {
    cerr << "ERROR: could not send fin packer" << endl;
    exit(EXIT_FAILURE);
  }
  printSent(fin, masterCwnd, masterSSThresh);
  int bytesRecv = recvfrom(sockfd, &response, sizeof(response), 0, (struct sockaddr *)p->ai_addr, &(p->ai_addrlen));
  response = convertCPacketToHost(response);

  printRecv(response, masterCwnd, masterSSThresh);
  if(bytesRecv < 0){
    cerr << "ERROR: could not recieve fin ack" << endl;
    exit(EXIT_FAILURE);
  } else if(bytesRecv == 0){
    cerr << "ERROR: received no bytes for fin ack" << endl;
    exit(EXIT_FAILURE);
  } else {
    if(response.mAckNum != s + 1){
      cerr << "ERROR: ack of our fin from server  bad acknum: " << s << " ----- " << response.mAckNum << endl;
      exit(EXIT_FAILURE);
    } else if (response.flags == 4) {
      gettimeofday(&start, NULL);
      bool gotAfin = false;
      while(1){
        bytesRecv = recvfrom(sockfd, &response, sizeof(response), 0,(struct sockaddr *)p->ai_addr, &(p->ai_addrlen));
        response = convertCPacketToHost(response);
        printRecv(response, masterCwnd, masterSSThresh);
        if(bytesRecv < 0 || bytesRecv == 0){
          if(gotAfin){
            break;
          }
          cerr << "ERROR: couldnt receive server fin" << endl;
          exit(EXIT_FAILURE);
        }
        if(response.flags != 1){
          cerr << "ERROR: wrong flags on server fin" << endl;
          exit(EXIT_FAILURE);
        }
        gettimeofday(&end, NULL);
        gotAfin = true;
        int time_diff = msDiff(end, start);
        if(time_diff > 2000){
          break;
        }
        CPacket a;
        a.mAckNum = (response.mSeqNum + 1) % (MAX_NUM + 1);
        a.mSeqNum = (fin.mSeqNum + 1) % (MAX_NUM + 1);
        a.mID = cID;
        a.flags = 4;
        CPacket b = convertCPacketToNetwork(a);
        if(sendto(sockfd, &b, HEAD_SIZE, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1)
        {
          cerr << "ERROR: could not send fin packer" << endl;
          exit(EXIT_FAILURE);
        }
        printSent(a, masterCwnd, masterSSThresh);
      }
    } else if(response.flags == 5){
        while(1){
          gettimeofday(&start, NULL);
          CPacket a;
          a.mAckNum = (response.mSeqNum + 1) % (MAX_NUM + 1);
          a.mSeqNum = (fin.mSeqNum + 1) % (MAX_NUM + 1);
          a.mID = cID;
          a.flags = 4;
          CPacket b = convertCPacketToNetwork(a);
          if(sendto(sockfd, &b, HEAD_SIZE, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1)
          {
            cerr << "ERROR: could not send find ack to server" << endl;
            exit(EXIT_FAILURE);
          }
          printSent(a, masterCwnd, masterSSThresh);
          bytesRecv = recvfrom(sockfd, &response, sizeof(response), 0,(struct sockaddr *)p->ai_addr, &(p->ai_addrlen));
          gettimeofday(&end, NULL);
          if(bytesRecv < 1){
            //cerr << "DEBUG: bad recv after ack while waiting" << endl;
            break;
          } else {
            int time_diff = msDiff(end, start);
            if(time_diff > 2000){
              break;
            } else {
              response = convertCPacketToHost(response);
              printRecv(response, masterCwnd, masterSSThresh);
            }
          }
        }
    }
    else {
      cerr << "ERROR: idek" << endl;
      exit(EXIT_FAILURE);
    }
  }
}


int sendFile(string fileName, int sockfd, int id, int intialACK, addrinfo*p)
{
  bool end = false;
  unsigned int cwnd = MIN_CWND;
  int bytes_read = MIN_CWND;
  char file_buff[MIN_CWND];
  ifstream inputFile(fileName);
  int read_size  = MIN_CWND;
  unsigned int lastACK = 0;

  CPacket ack;
  CPacket pack;
  pack.flags = 4;
  pack.mID = id;
  pack.mAckNum = (intialACK + 1) % (MAX_NUM + 1);
  pack.mSeqNum = INITIAL_SEQ_C + 1;

  queue<CPacket> packetsLeft;

  while(packetsLeft.size() > 0 || end == false)
  {
    //create and send packets from file
    if(packetsLeft.size() < cwnd || (MIN_CWND && end == true))
    { 
      //read from file 
      for(unsigned int i = packetsLeft.size(); i < 1; i++){
        memset(file_buff, 0, sizeof(file_buff));
        if(!inputFile.is_open()){
          cerr << "ERROR: file not open" << endl;
          exit(EXIT_FAILURE);
        }
        inputFile.read(file_buff, read_size);
        bytes_read = inputFile.gcount();

        if(bytes_read == -1)
        {
          cerr << "ERROR: could not read file" << endl;
          exit(EXIT_FAILURE);
        }
        else if(bytes_read == 0) 
        {
          end = true;
          break;
        }
        else if(bytes_read < read_size) {
          end = true;
        }

        //copy file data read into packet data
        memcpy(pack.data, file_buff, bytes_read);
        struct CPacket newPack = convertCPacketToNetwork(pack);
        //attempt to send packet to server
        if(sendto(sockfd, &newPack, HEAD_SIZE + bytes_read, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1)
        {
          cerr << "ERROR: could not send packet" << endl;
          exit(EXIT_FAILURE);
        }
        printSent(pack, masterCwnd, masterSSThresh);
        //update sequence number for next packet to send
      }
      struct timeval start, end;
      gettimeofday(&start, NULL);
      while(1){
        struct timeval timeout;
        timeout.tv_sec = 0;
        timeout.tv_usec = 500000;
        fd_set set;
        FD_ZERO(&set);
        FD_SET(sockfd, &set);
        int rv = select(sockfd+1, &set, NULL, NULL, &timeout);
        if(rv == 0){
          masterSSThresh = masterCwnd / 2;
          masterCwnd = 512;
          struct CPacket newPack = convertCPacketToNetwork(pack);
          if(sendto(sockfd, &newPack, HEAD_SIZE + bytes_read, 0, (struct sockaddr *)p->ai_addr, p->ai_addrlen) == -1)
          {
            cerr << "ERROR: could not send packet" << endl;
            exit(EXIT_FAILURE);
          }
          printSent(pack, masterCwnd, masterSSThresh, true);
        } else {
          break;
        }
        gettimeofday(&end, NULL);
        if(msDiff(end, start) > 10000){
          cerr << "ERROR: TIMEOUT" << endl;
          exit(EXIT_FAILURE);
        }
      }
      pack.mSeqNum = (pack.mSeqNum + bytes_read) % (MAX_NUM + 1);
      //receive ack from server
      if(recvfrom(sockfd, (void*) &ack, 12, 0, (struct sockaddr *)p->ai_addr, &(p->ai_addrlen)) == -1)
      {
        cerr << "ERROR: could not receive ack properly" << endl;
        exit(EXIT_FAILURE);
      }
      ack = convertCPacketToHost(ack);
      printRecv(ack, masterCwnd, masterSSThresh);
      if(masterCwnd < masterSSThresh && (ack.flags & 4)){
        masterCwnd += 512;
      } else if (ack.flags & 4){
        masterCwnd += (512 * 512) / masterCwnd;
      }
      if(lastACK == ack.mAckNum){
      }
      lastACK = ack.mAckNum;
      if (lastACK != pack.mSeqNum){
      } else {
      }
    }
  }
  return pack.mSeqNum;
}