#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; }