📄 mftp_snd.cc
字号:
/* * (c) 1997-98 StarBurst Communications Inc. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Christoph Haenle, chris@cs.vu.nl * File: mftp_snd.cc * Last change: Dec 07, 1998 * * This software may freely be used only for non-commercial purposes * * $Header: /nfs/jade/vint/CVSROOT/ns-2/apps/mftp_snd.cc,v 1.9 2000/09/01 03:04:06 haoboy Exp $ */// This file contains functionality specific to the MFTP sender.#include <stdlib.h> // strtoul, etc.#include <assert.h>#include <stdio.h>#include "config.h"#include "tclcl.h"#include "agent.h"#include "packet.h"#include "ip.h"#include "mftp_snd.h"#include "trace.h"#include "bitops.h" // due to IS_BITSET, etc.#define min(a, b) ((a) < (b) ? (a) : (b))static class MFTPSndAgentClass : public TclClass {public: MFTPSndAgentClass() : TclClass("Agent/MFTP/Snd") {} TclObject* create(int, const char*const*) { return (new MFTPSndAgent()); }} class_mftpsnd_agent;int hdr_mftp::offset_;static class MFTPHeaderClass : public PacketHeaderClass {public: MFTPHeaderClass() : PacketHeaderClass("PacketHeader/MFTP", sizeof(hdr_mftp)) { bind_offset(&hdr_mftp::offset_); }} class_mftphdr;MFTPSndAgent::MFTPSndAgent() : MFTPAgent(), naks(0), retx(0), fseek_offset(0), read_ahead_bufsize(0), CurrentPass(0), CurrentGroup(0), CwPat(0), MinGroupNbInBuf(0), NbGroupsInBuf(0){ bind("readAheadBufsize_", &readAheadBufsize_); bind_time("txStatusDelay_", &txStatusDelay_); bind("nakCount_", &nakCount_);}MFTPSndAgent::~MFTPSndAgent(){ delete [] naks; // NOTE: delete on NULL pointer has no effect delete [] retx;}int MFTPSndAgent::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "send") == 0) { if(strcmp(argv[2], "data") == 0) { return send_data(); } else if(strcmp(argv[2], "statreq") == 0) { unsigned long pass_nb, block_lo, block_hi; double rsp_backoff_window=2343.2343; int nb_scanned = 0; if(argc == 7) { nb_scanned += sscanf(argv[3], "%lu", &pass_nb); nb_scanned += sscanf(argv[4], "%lu", &block_lo); nb_scanned += sscanf(argv[5], "%lu", &block_hi); nb_scanned += sscanf(argv[6], "%lf", &rsp_backoff_window); } if(nb_scanned != 4) { tcl.resultf("%s: wrong number of parameters for \"send statreq\"", name_); return TCL_ERROR; } send_status_request(pass_nb, block_lo, block_hi, rsp_backoff_window); return TCL_OK; } } if(strcmp(argv[1], "start") == 0) { if(MFTPAgent::init() == TCL_ERROR) { return TCL_ERROR; }; init_user_file((unsigned long) readAheadBufsize_); return TCL_OK; } return Agent::command(argc, argv);}void MFTPSndAgent::recv(Packet* p, Handler* h){ hdr_ip* ih = hdr_ip::access(p); hdr_mftp* mh = hdr_mftp::access(p); if(ih->daddr() == 0) { assert(false); // Packet from local agent. } else { switch(mh->type) { case hdr_mftp::PDU_DATA_TRANSFER: case hdr_mftp::PDU_STATUS_REQUEST: // as the sender is a member of the multicast group as well, // it receives all data it has sent. So just ignore it. break; case hdr_mftp::PDU_NAK: process_nak(mh->spec.nak, p->accessdata(), CurrentPass-1); // -1 because we have // incremented the pass-number already in send_data. break; default: assert(false); // unknown packet type (also possible: just ignore packet rather than exit) } Packet::free(p); }}void MFTPSndAgent::send_status_request(unsigned long pass_nb, unsigned long block_lo, unsigned long block_hi, double rsp_backoff_window){ Packet* p = Agent::allocpkt(); hdr_mftp* hdr = hdr_mftp::access(p); assert(FileDGrams > 0); // we need this requirement here // initialize the header of the status request packet: hdr->type = hdr_mftp::PDU_STATUS_REQUEST; hdr->spec.statReq.pass_nb = pass_nb; hdr->spec.statReq.block_lo = block_lo; hdr->spec.statReq.block_hi = block_hi; hdr->spec.statReq.RspBackoffWindow = rsp_backoff_window; // transmit packet hdr_cmn* ch = hdr_cmn::access(p); ch->size() = sizeof(hdr_mftp); target_->recv(p);}// process incoming nak:void MFTPSndAgent::process_nak(hdr_mftp::Spec::Nak& nak, unsigned char* nak_bitmap, unsigned long currentPass){ assert(1 <= nak.nak_count && nak.nak_count <= nb_groups); // or else some receiver is fooling us. assert(nak.pass_nb <= currentPass); // pass greater than requested? => a receiver is fooling us. Tcl& tcl = Tcl::instance(); tcl.evalf("%s recv nak %lu %lu %lu", name_, (unsigned long) nak.pass_nb, (unsigned long) nak.block_nb, (unsigned long) nak.nak_count); assert(dtus_per_block % 8 == 0); // This property is required for the following // start_group_nb corresponds to first bit of NAK-bitmap: const unsigned long start_group_nb = dtus_per_block * nak.block_nb; // end_group_nb corresponds to last group number of NAK-bitmap plus one const unsigned long end_group_nb = min(nb_groups, dtus_per_block * (nak.block_nb + 1)); // get starting index into naks-array for this block const unsigned long nak_index = start_group_nb / 8; // number of status bytes in pdu const unsigned long nak_bytes = (end_group_nb - start_group_nb + 7) / 8; // pointer to location in array at which the received nak bitmap must be // or'd to the sender-bitmap (the bitmap in which the sender collects the naks) unsigned char* nak_array = naks + nak_index; // if this nak pdu is from a previous pass (i.e. a delayed nak), ignore the status // bits for dtu's that we've just retransmitted in the current pass: if(nak.pass_nb < currentPass) { unsigned char* retx_array = retx + nak_index; for(unsigned long i = 0; i < nak_bytes; i++) { if(*nak_bitmap) { // "AND out" bits for already transmitted packets and // "OR in" the result into newly constructed NAK bitmap *nak_array |= (*nak_bitmap & (~*retx_array)); } nak_array++; retx_array++; nak_bitmap++; } } else { assert(nak.pass_nb == currentPass); // this nak belongs to the current pass for(unsigned long i = 0; i < nak_bytes; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -