// You will build this in project part B - this is merely a // stub that does nothing but integrate into the stack // For project parts A and B, an appropriate binary will be // copied over as part of the build process #include #include #include #include #include #include #include #include #include #include #include #include #include "Minet.h" #include "packet.h" #include "buffer.h" #include "ip.h" #include "tcp.h" #include "tcpstate.h" #include "tcpstate.cc" MinetHandle mux; MinetHandle sock; /* Used to keep the information of all the connections built */ ConnectionList clist; /** Define your macros below **/ #define ACK_TIMEOUT 3 #define NO_OF_RETRIES 0 #define SYN_HEADER 1 #define SYN_ACK_HEADER 2 #define ACK_HEADER 3 #define FIN_ACK_HEADER 4 #define PSH_ACK_HEADER 5 #define SYN_HEADER_LENGTH TCP_HEADER_BASE_LENGTH+IP_HEADER_BASE_LENGTH+20 #define ACK_HEADER_LENGTH TCP_HEADER_BASE_LENGTH+IP_HEADER_BASE_LENGTH+12 #define FIN_HEADER_LENGTH TCP_HEADER_BASE_LENGTH+IP_HEADER_BASE_LENGTH+12 #define TCP_HEADER_OPTION_KIND_SACK 4 #define TCP_HEADER_OPTION_KIND_SACK_LEN 2 /** Write your fuctions below **/ void craftSynPacket(Packet *psend, ConnectionToStateMapping conState, int type, unsigned short no_of_bytes, unsigned int old_time ) { /* To construct a packet with certain parameters */ /* You can write your own if you think this one is buggy or you have better solution */ Connection c = conState.connection; IPHeader ih; TCPHeader tcph; unsigned short totalLength = no_of_bytes; unsigned int seqnum, acknum=0; unsigned char flag=0; unsigned short winsize,up=0; //Where is the definition? at tcp.h /* struct TCPOptions { public: unsigned len; char data[TCP_HEADER_OPTION_MAX_LENGTH];}; */ TCPOptions opt; unsigned int time = Time(); unsigned char hlen = 5; //What is this? int wscale = 2; seqnum = conState.state.GetLastSent(); winsize = conState.state.GetN(); int *ptr; ptr = (int*) opt.data; /**************creat a SYN *********************/ if ( type == SYN_HEADER ) // Line 62 { totalLength = SYN_HEADER_LENGTH; SET_SYN(flag); //flag: Line 75 hlen = 10; opt.len = 20; int mss = TCP_MAXIMUM_SEGMENT_SIZE; *ptr++ = htonl((TCP_HEADER_OPTION_KIND_MSS << 24) | (TCP_HEADER_OPTION_KIND_MSS_LEN << 16) | mss); *ptr++ = htonl((TCP_HEADER_OPTION_KIND_SACK << 24) | (TCP_HEADER_OPTION_KIND_SACK_LEN << 16) | (TCP_HEADER_OPTION_KIND_TS << 8) | TCP_HEADER_OPTION_KIND_TS_LEN ); *ptr++ = htonl(time); /* TSVAL */ *ptr++ = htonl(old_time); /* TSECR */ *ptr++ = htonl((TCP_HEADER_OPTION_KIND_NOP << 24) | (TCP_HEADER_OPTION_KIND_WSF << 16) | (TCP_HEADER_OPTION_KIND_WSF_LEN << 8) | (wscale)); } /*******************creat a ACK ******************************/ if ( type == ACK_HEADER || type == PSH_ACK_HEADER || type == FIN_ACK_HEADER ) { totalLength += ACK_HEADER_LENGTH; SET_ACK(flag); hlen = 8; opt.len = 12; *ptr++ = htonl((TCP_HEADER_OPTION_KIND_NOP << 24) | (TCP_HEADER_OPTION_KIND_NOP << 16) | (TCP_HEADER_OPTION_KIND_TS << 8) | TCP_HEADER_OPTION_KIND_TS_LEN ); *ptr++ = htonl(time); /* TSVAL */ *ptr++ = htonl(old_time); /* TSECR */ seqnum += 1; acknum = conState.state.GetLastRecvd()+1; if ( type == PSH_ACK_HEADER ) SET_PSH(flag); if ( type == FIN_ACK_HEADER ) SET_FIN(flag); } /***************Set IP Header****************************/ ih.SetProtocol(IP_PROTO_TCP); ih.SetSourceIP(c.src); ih.SetDestIP(c.dest); ih.SetTotalLength( totalLength ); //Line 73. // push it onto the packet (*psend).PushFrontHeader(ih); /***************Set TCP Header****************************/ tcph.SetDestPort(c.destport,(*psend)); tcph.SetSourcePort(c.srcport,(*psend)); tcph.SetAckNum(acknum,(*psend)); tcph.SetSeqNum(seqnum,(*psend)); tcph.SetFlags(flag,(*psend)); tcph.SetWinSize(winsize,(*psend)); tcph.SetOptions(opt); tcph.SetUrgentPtr(up,(*psend)); tcph.SetHeaderLen(hlen,(*psend)); tcph.RecomputeChecksum((*psend)); // Now we want to have the tcp header BEHIND the IP header (*psend).PushBackHeader(tcph); tcph.Print(cout); //(*psend).Print(cout); } void muxHandler( MinetEvent event) { /*When receive a IP packet from mux interface*/ cout << "In mux handler now" << endl; Packet pmux; unsigned short len; bool checksumok; unsigned char f = 0; //f stands for flags. unsigned int status; /*Assign received packet to pmux*/ MinetReceive(mux,pmux); pmux.ExtractHeaderFromPayload(20); /*Assign values for TCP Header*/ TCPHeader tcph; tcph=pmux.FindHeader(Headers::TCPHeader); checksumok=tcph.IsCorrectChecksum(pmux);//checksum of TCPHeader included DATA and IPHeader /*Assign values for IP Header*/ IPHeader iph; iph=p.FindHeader(Headers::IPHeader); /* * Assign values for connection class c; * Use sourse IP address, destination IP address, * source Port#, destination Port#, and type of Protocol * to initialize connection c. * */ Connection c; iph.GetDestIP(c.src); iph.GetSourceIP(c.dest); iph.GetProtocol(c.protocol); tcph.GetDestPort(c.srcport); tcph.GetSourcePort(c.destport); /*Assign f with flags received from TCP Header*/ tcph.GetFlags(f); /* * TCP ConnectionList: * Use c and ConnectionList structure to fetch a matched connectionState. * Each connection has a corresponding connection state. * */ ConnectionList::iterator cs = clist.FindMatching(c); /* * If cs not "is" clist.end(), * it means there exists a matching connection State * */ if (cs!=clist.end()) { /*Refer cs to connstate*/ ConnectionToStateMapping& connstate=(*cs); unsigned int currentState; /*Get current TCP State*/ currentState = (*connstate).state.GetState(); /*In different State check the flags received from TCP Header*/ switch(currentState) { /* * CLOSED * * This case only be invoked by call from * Application Layer * * Nothing to do in muxHandle. * */ case 0: {} break; /*****************************************/ /* * LISTEN * * When receive SYN packet * Transfer to SYN_RCVD state * * Other state transfer is invoked by * Application Layer. * * */ case 1: { /*Check f[means Flags] and see if SYN == 1*/ if(IS_SYN(f)) { cout<<"SYN packet Received, move to state SYN_RCVD Line 271"< m; m.connection = req.connection; /*rand() return a random int, SYN_SENT = 3, last parameter is Time_Retries*/ TCPState atcpstate = TCPState(rand(), SYN_SENT, 3); m.timeout = Time() + ACK_TIMEOUT; m.state = atcpstate; //SYN_SENT TCP State m.Print(cout); clist.push_front(m); //Creat and send a SYN packet! Packet psend; craftSynPacket(&psend, m, SYN_HEADER, 0, 0); MinetSend(mux, psend); MinetSend(mux, psend); // Why MinetSend two times. //Send a reply to socket layer. SockRequestResponse repl; repl.type=STATUS; repl.connection=req.connection; repl.bytes=0; repl.error=EOK; MinetSend(sock, repl); } break; case ACCEPT: { } break; case WRITE: { } break; case CLOSE: { } break; case STATUS: { //nothing to do; } break; default: { SockRequestResponse repl; // repl.type=SockRequestResponse::STATUS; repl.type=STATUS; repl.error=EWHAT; MinetSend(sock,repl); } } } // The following funtion timeoutHandler deals with timeout event void timeoutHandler( MinetEvent event, ConnectionList::iterator cs) { if ( (*cs).state.ExpireTimerTries() ) { //clist.erase(cs); //cout<<"NO OF TRIES OVER :: CLOSING CONNECTION"<& m = (*cs); int Len = m.state.SendBuffer.GetSize(); const int Size = TCP_MAXIMUM_SEGMENT_SIZE; char A[Size]; int Start = 0; while( Len > 0 ) /* Retransmit from LastAcked to Lastsend */ { //Resend the data, get the payload int ss = m.state.SendBuffer.GetData(A, Size, Start); Packet p(A, ss); // Set the IP header IPHeader ih; ih.SetProtocol(IP_PROTO_TCP); ih.SetSourceIP(m.connection.src); ih.SetDestIP(m.connection.dest); ih.SetTotalLength(TCP_HEADER_BASE_LENGTH+IP_HEADER_BASE_LENGTH +20); // push it onto the packet p.PushFrontHeader(ih); // Set the TCP header TCPHeader tcpsah; tcpsah.SetDestPort(m.connection.destport,p); tcpsah.SetSourcePort(m.connection.srcport,p); tcpsah.SetSeqNum(m.state.GetLastSent()+Start+ss,p); TCPOptions opt; unsigned int time = Time(); memcpy((void *)(opt.data+12),(void *)(opt.data+8),4); *(int *)(opt.data+8) = htonl(time); tcpsah.SetOptions(opt); tcpsah.RecomputeChecksum(p); p.PushBackHeader(tcpsah); //Send the TCP segment out to mux MinetSend(mux, p); Len -= Size; Start += Size; } } else if((cs->state).GetState()==SYN_SENT || (cs->state).GetState()== TIME_WAIT) { /* Erase this connection */ clist.erase(cs); } } int main(int argc, char *argv[]) { MinetInit(MINET_TCP_MODULE); mux=MinetIsModuleInConfig(MINET_IP_MUX) ? MinetConnect(MINET_IP_MUX) : MINET_NOHANDLE; sock=MinetIsModuleInConfig(MINET_SOCK_MODULE) ? MinetAccept(MINET_SOCK_MODULE) : MINET_NOHANDLE; if (mux==MINET_NOHANDLE && MinetIsModuleInConfig(MINET_IP_MUX)) { MinetSendToMonitor(MinetMonitoringEvent("Can't connect to ip_mux")); return -1; } if (sock==MINET_NOHANDLE && MinetIsModuleInConfig(MINET_SOCK_MODULE)) { MinetSendToMonitor(MinetMonitoringEvent("Can't accept from sock_module")); return -1; } cerr << "tcp_module STUB VERSION handling tcp traffic.......\n"; MinetSendToMonitor(MinetMonitoringEvent("tcp_module STUB VERSION handling tcp traffic........")); MinetEvent event; double timeout=1; /* The following code is the hint for Active connections // HARDODED CONNECTIONS FOR TESTING // active connection Connection acon; acon.dest = "165.124.182.25"; acon.src = "10.10.6.20"; acon.destport = 7070; acon.srcport = 7070; acon.protocol = IP_PROTO_TCP ; ConnectionToStateMapping am; am.connection=acon; TCPState atcpstate = TCPState( rand() , SYN_SENT , 3); am.state=atcpstate; am.Print(cout); clist.push_front(am); Packet psend; //construct the packet here with the following parameters craftSynPacket(&psend,am,SYN_HEADER,0,0); psend.Print(cout); MinetSend(mux,psend); MinetSend(mux,psend); */ while (MinetGetNextEvent(event,timeout)==0) { if (event.eventtype==MinetEvent::Dataflow && event.direction==MinetEvent::IN) { if (event.handle==mux) { // ip packet has arrived from the IP layer! // TODO handle this event muxHandler( event ); } if (event.handle==sock) { // socket request or response has arrived from the application layer sockHandler( event ); } } if (event.eventtype==MinetEvent::Timeout) { // timeout ! probably need to resend some packets ConnectionList::iterator cs = clist.FindEarliest(); // Remember clist is a list which keeps the information of connections. if( cs != clist.end() ) { if ( Time().operator >((*cs).timeout) ) { timeoutHandler(event,cs); } else cout<<"IN TIMEOUT" << endl; } } } MinetDeinit(); return 0; }