📄 snooptcp.cc
字号:
else if (ack == _mh_last_ack && datalen == 0) // duplicate ack w/o data // (duplicate acks with data are not semantically "duplicate acks") p = mh_dup_ack(p, tcph, ack); else if (SEQ_LT(ack, _mh_last_ack)) // spurious ack: ignore return p; _mh_last_win = ntohs(tcph->th_win); return p;}voidSnoopTCP::PCB::mh_data(Packet *, const click_tcp *tcph, int datalen){ // initialize connection (starting up snoop in the middle of a connection) // or mark it alive if (datalen) { if (!_mh_exists) initialize(false, tcph, datalen); else _mh_alive = true; } // XXX rest}SnoopTCP::PCB *SnoopTCP::find(unsigned s_ip, unsigned short s_port, unsigned int mh_ip, unsigned short mh_port, bool create){ IPFlowID q(s_ip, s_port, mh_ip, mh_port); if (PCB **pcbp = _map.findp(q)) return *pcbp; else if (create) { PCB *pcb = new PCB(); if (pcb) _map.insert(q, pcb); return pcb; } else return 0;}Packet *SnoopTCP::handle_packet(int port, Packet *p){ const click_ip *iph = p->ip_header(); if (p->length() < 40 || iph->ip_p != IPPROTO_TCP) { DEBUG_CHATTER("Non TCP"); // ignore non-TCP traffic return p; } const click_tcp *tcph = p->tcp_header(); int header_len = (iph->ip_hl << 2) + (tcph->th_off << 2); int datalen = p->length() - header_len; // get or create corresponding PCB // don't create a PCB for packets w/o data PCB *pcb; if (port == 0) pcb = find(iph->ip_src.s_addr, tcph->th_sport, iph->ip_dst.s_addr, tcph->th_dport, datalen > 0); else pcb = find(iph->ip_dst.s_addr, tcph->th_dport, iph->ip_src.s_addr, tcph->th_sport, datalen > 0); if (!pcb) // out of space, could not create PCB return p; // SYN flag: initialize that side of the connection if (tcph->th_flags & TH_SYN) { DEBUG_CHATTER("SYN packet"); pcb->clear(port == 0); pcb->initialize(port == 0, tcph, datalen); return p; } // FIN or RST: kill that side of the connection if (tcph->th_flags & (TH_FIN | TH_RST)) { pcb->clear(port == 0); return p; } if (port == 0) { if (tcph->th_flags & TH_ACK) pcb->s_ack(p, tcph, datalen); if (datalen > 0) p = pcb->s_data(p, tcph, datalen); } else { if (tcph->th_flags & TH_ACK) p = pcb->mh_ack(p, tcph, datalen); if (datalen > 0) pcb->mh_data(p, tcph, datalen); } return p;}voidSnoopTCP::push(int port, Packet *p){ p = handle_packet(port, p); if (p) output(port).push(p);}Packet *SnoopTCP::pull(int port){ Packet *p = input(port).pull(); if (p) p = handle_packet(port, p); return p;}#if 0Packet *SnoopTCP::PCB::add_data(Packet *p, unsigned th_seq){ bool full = next_i(_head) == _tail; int entry = -1; if (SEQ_GT(th_seq, _max)) { // New packet with higher seqno - common case if (full) { // skip if buffer is full DEBUG_CHATTER("buffer full"); return p; } _max = th_seq; entry = _expected_ack = _head; _head = next_i(_head); } else if (SEQ_LT(th_seq, _cache[_tail].seq)) { if (SEQ_LT(th_seq, _una)) { // already acked - don't cache DEBUG_CHATTER("\tway out-of-order pkt %d, lastack %d\n", th_seq, _una); return p; } // new packet earlier than anything cached if (full) { // skip if buffer is full DEBUG_CHATTER("buffer full"); return p; } _tail = prev_i(_tail); entry = _tail; } else if (_tail == _head) // nothing has been cached and we got a spurious packet return p; else // somewhere in the middle for (int i = _tail; i != _head; i = next_i(i)) { if (_cache[i].seq == th_seq) { // either a repeat packet or a fragment thereof DEBUG_CHATTER("have pkt %d at %d", th_seq, i); if (_cache[i].packet->length() <= p->length()) { // replace fragment/packet with new one _cache[i].packet->kill(); _cache[i].packet = p->clone(); } _cache[i].num_rxmit = 0; _cache[i].sender_rxmit = 1; //microtime(&(packet->snd_time)); return p; } else if (SEQ_GT(_cache[i].seq, th_seq)) { // insert new packet in the middle if (full) { // skip if buffer is full DEBUG_CHATTER("buffer full"); return p; } for (int j = _tail; j != i; j = next_i(j)) _cache[prev_i(j)] = _cache[j]; entry = i; _tail = prev_i(_tail); DEBUG_CHATTER("\tcache reorg; pkt %d, head %d, tail %d", th_seq, _head, _tail); break; } } // Cache packet at `_cache[entry]' //microtime(&(packet->snd_time)); assert(entry >= 0); p->use(); _cache[entry].packet = p; _cache[entry].seq = th_seq; _cache[entry].num_rxmit = 0; _cache[entry].sender_rxmit = 0; DEBUG_CHATTER("\t%d at %d\n", th_seq, entry); if (SEQ_LT(th_seq, _max)) { // out-of-order DEBUG_CHATTER("\tpkt %x out of order, last %x\n", th_seq, _max); if (_tail == entry) { _cache[entry].sender_rxmit = 1; _cache[entry].num_rxmit = 0; } _expected_ack = _tail; } return p;}#endif#if 0Packet *SnoopTCP::PCB::add_ack(Packet *p, unsigned th_ack, int data_len, unsigned short win, SnoopTCP *snp){ DEBUG_CHATTER("ack %d, expect %d, dacks %d, seen %d dups\tcached %d-%d", th_ack, _expected_ack, _expected_dup_acks, _dup_acks, _cache[_tail].seq, _cache[prev_i(_head)].seq); if (SEQ_GT(th_ack, _una)) { // new ack DEBUG_CHATTER("new ack %d", th_ack); // XXX update RTT ?? int i = _tail; while (i != _head && SEQ_LT(_cache[i].seq, th_ack)) { _cache[i].packet->kill(); i = next_i(i); } _tail = i; _una = th_ack; _dup_acks = 0; _last_win = win; return p; } else if (SEQ_LT(th_ack, _una)) { // out-of-order ack; just forward it on DEBUG_CHATTER("spurious ack %d", th_ack); return p; } else { if (_last_win != win || data_len > 0) { // not a duplicate ack -- window change ad or piggyback ACK DEBUG_CHATTER("data/window ad"); _last_win = win; return p; } // duplicate ack // first look for the appropriate cache entry int entry = -1; for (int i = _tail; i != _head; i = next_i(i)) if (_cache[i].seq == th_ack) { entry = i; break; } // just forward the duplicate ack if there is no such packet, or the // sender has already retransmitted it if (entry < 0 || _cache[entry].sender_rxmit) return p; // otherwise, check if we're expecting it if (_expected_dup_acks > 0) { --_expected_dup_acks; DEBUG_CHATTER("expected, discarding"); // discard if not piggybacked if (data_len) return p; else return 0; } else if (!_expected_dup_acks) { // Compute number of expected dups _expected_dup_acks = _head - _expected_ack; if (_expected_dup_acks < 0) _expected_dup_acks += SNOOP_MAX_BUF; _expected_dup_acks--; _expected_ack = next_i(_tail); DEBUG_CHATTER(" ack %d expect %d more\n", th_ack, _expected_dup_acks); // Retransmit _dup_acks++; _cache[entry].num_rxmit++; click_chatter("dup ack %d, retransmitting", _una); snp->output(2).push(_cache[entry].packet); // Squelch packet if no data content if (data_len) return p; else return 0; } else { DEBUG_CHATTER("Help! Inconsistent state"); return p; } }}#endifCLICK_ENDDECLSELEMENT_REQUIRES(false)EXPORT_ELEMENT(SnoopTCP)#include <click/hashmap.cc>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -