📄 tcpack.cc
字号:
/* * tcpack.{cc,hh} -- provides TCP like acknowledgement service * Benjie Chen * * Copyright (c) 2001 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <click/confparse.hh>#include <clicknet/ip.h>#include <clicknet/tcp.h>#include <click/elemfilter.hh>#include <click/router.hh>#include <click/error.hh>#include "tcpbuffer.hh"#include "tcpack.hh"CLICK_DECLSTCPAck::TCPAck() : Element(2, 3), _timer(this){}TCPAck::~TCPAck(){}intTCPAck::configure(Vector<String> &conf, ErrorHandler *errh){ _ackdelay_ms = 20; return cp_va_parse(conf, this, errh, cpOptional, cpUnsigned, "ack delay (ms)", &_ackdelay_ms, cpEnd);}intTCPAck::initialize(ErrorHandler *errh){ CastElementFilter filter("TCPBuffer"); Vector<Element*> tcpbuffers; if (router()->downstream_elements(this, 0, &filter, tcpbuffers) < 0) return errh->error("flow-based router context failure"); if (tcpbuffers.size() < 1) return errh->error ("%d downstream elements found, expecting at least 1", tcpbuffers.size()); for(int i=0; i<tcpbuffers.size(); i++) { _tcpbuffer = reinterpret_cast<TCPBuffer*>(tcpbuffers[i]->cast("TCPBuffer")); if (_tcpbuffer) break; } if (!_tcpbuffer) return errh->error("no TCPBuffer element found!"); _synack = false; _needack = false; _timer.initialize(this); _timer.schedule_after_ms(_ackdelay_ms); return 0;}voidTCPAck::push(int port, Packet *p){ bool forward; if (port == 0) forward = iput(p); else forward = oput(p); if (forward) output(port).push(p); else p->kill();}Packet *TCPAck::pull(int port){ bool forward; Packet *p = input(port).pull(); if (p) { if (port == 0) forward = iput(p); else forward = oput(p); if (forward) return p; else { p->kill(); return 0; } } return 0;}boolTCPAck::iput(Packet *p){ const click_tcp *tcph = p->tcp_header(); if (!_synack && (tcph->th_flags&(TH_SYN|TH_ACK))==(TH_SYN|TH_ACK)) { // synack on input, meaning next ackn is the seqn in packet _ack_nxt = ntohl(tcph->th_seq)+1; _synack = true; } if (!_synack) return false; if (tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) return true; // determine what the next ack should be if (TCPBuffer::seqno(p) == _ack_nxt) { // if the packet is what we expected, increment the expected // sequence number, and search for the next expected sequence // number from the tcp buffer. _ack_nxt += TCPBuffer::seqlen(p); bool v = _tcpbuffer->next_missing_seq_no(_ack_nxt, _ack_nxt); // passed seq, buffer cannot be empty assert(v); } else { click_chatter("seqno < ack_nxt: out of order or retransmitted packet"); } _needack = true; if (!_timer.scheduled()) _timer.schedule_after_ms(_ackdelay_ms); return true;}boolTCPAck::oput(Packet *p){ const click_tcp *tcph = p->tcp_header(); if (tcph->th_flags&(TH_SYN|TH_ACK) == (TH_SYN|TH_ACK)) { // synack on output, meaning next ackn is the ackn in packet _ack_nxt = ntohl(tcph->th_ack); _synack = true; } if (!_synack) return false; _needack = false; // XXX BUGGY, BUGGY CODE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! click_tcp *tcph_new = p->uniqueify()->tcp_header(); tcph_new->th_ack = htonl(_ack_nxt); return true;}voidTCPAck::run_timer(){ if (_needack) { send_ack(); _needack = false; }}voidTCPAck::send_ack(){ struct click_ip *ip; struct click_tcp *tcp; WritablePacket *q = Packet::make(sizeof(*ip) + sizeof(*tcp)); if (q == 0) { click_chatter("TCPAck: cannot make packet"); return; } memset(q->data(), '\0', q->length()); ip = (struct click_ip *) q->data(); tcp = (struct click_tcp *) (ip + 1); ip->ip_v = 4; ip->ip_hl = 5; ip->ip_tos = 0x10; ip->ip_len = htons(q->length()); ip->ip_id = htons(0); // what is this used for exactly? ip->ip_off = htons(IP_DF); ip->ip_ttl = 255; ip->ip_p = IP_PROTO_TCP; ip->ip_sum = 0; tcp->th_ack = htonl(_ack_nxt); tcp->th_off = 5; tcp->th_flags = TH_ACK; tcp->th_win = htons(32120); // when and where should this be set? tcp->th_sum = htons(0); tcp->th_urp = htons(0); q->set_ip_header(ip, ip->ip_hl << 2); output(2).push(q);}CLICK_ENDDECLSEXPORT_ELEMENT(TCPAck)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -