/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 2001 University of Mannheim, Praktische Informatik IV * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Praktische Informatik IV, * University of Mannheim. * 4. Neither the name of Praktische Informatik IV nor of University of * Mannheim may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY U. MANNHEIM AND 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 U. MANNHEIM OR 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. */ #include #include #include #include "pcc.h" #define PRINT_JPD 0 #define PRINT_JPD_VERBOSE 0 #define PRINT_NUMPACK_JPD 0 int hdr_pcc::offset_; int hdr_pcc_ack::offset_; static class PCCHeaderClass : public PacketHeaderClass { public: PCCHeaderClass() : PacketHeaderClass("PacketHeader/PCC", sizeof(hdr_pcc)) { bind_offset(&hdr_pcc::offset_); } } class_pcchdr; static class PCC_ACKHeaderClass : public PacketHeaderClass { public: PCC_ACKHeaderClass() : PacketHeaderClass("PacketHeader/PCC_ACK", sizeof(hdr_pcc_ack)) { bind_offset(&hdr_pcc_ack::offset_); } } class_pcc_ackhdr; static class PccClass : public TclClass { public: PccClass() : TclClass("Agent/PCC") {} TclObject* create(int, const char*const*) { return (new PccAgent()); } } class_pcc; PccAgent::PccAgent() : Agent(PT_PCC), send_timer_(this), NoFeedbacktimer_(this), rate_(0) { bind("packetSize_", &size_); bind("ndatapack_", &ndatapack_); bind("AppRate_", &AppRate_); bind("overhead_", &overhead_); bind_bool("printStatus_", &printStatus_); } int PccAgent::command(int argc, const char*const* argv) { if (argc==2) { if (strcmp(argv[1],"start")==0) { start(); return TCL_OK; } if (strcmp(argv[1],"stop")==0) { stop(); return TCL_OK; } } return (Agent::command(argc, argv)); } void PccAgent::start() { seqno_=0; rate_ = AppRate_; //(JPD) here rate is constant (or 0); in real life, would be set by the application rtt_=1; ndatapack_=0; active_ = 1; round_id = 0; last_timestamp_ = 0; last_arrival_ = 0; rcvrate = 0 ; inter_packet = 0; nextpkt(); NoFeedbacktimer_.resched(DEC_NO_REPORT*rtt_); //with rtt_=1, this should be enough time for the receiver to react flowID = (int)(Random::uniform() * 100); } void PccAgent::stop() { double now = Scheduler::instance().clock(); if (PRINT_JPD_VERBOSE) printf("((S%i)) Sender stopped at %f\n", flowID, now); active_ = 0; send_timer_.force_cancel(); NoFeedbacktimer_.force_cancel(); } void PccAgent::nextpkt() { double next = -1; sendpkt(); if (rate_ > SMALLFLOAT) { next = size_/rate_; // randomize between next*(1 +/- overhead_) inter_packet = next*(2*overhead_*Random::uniform()-overhead_+1); if (inter_packet > SMALLFLOAT) send_timer_.resched(inter_packet); } else { if (PRINT_JPD) printf("((S%i)) !!! SendTimer not restarted\n", flowID); } } /* * Receive a status report from the receiver. */ void PccAgent::recv(Packet *pkt, Handler *) { double now = Scheduler::instance().clock(); hdr_pcc_ack *nck = hdr_pcc_ack::access(pkt); last_timestamp_ = nck->timestamp; last_arrival_ = now; rcvrate = nck->rate; //(JPD) rcvrate coming from the receiver is always either 0 or MAXRATE rtt_ = nck->rtt; if (PRINT_JPD) { if (rcvrate<=0 && rate_>0) printf ("((S%i)) !!! At %f: rate changed to %i\n", flowID, now, rcvrate); if (rcvrate>0 && rate_<=0) printf ("((S%i)) !!! At %f: rate changed to %i\n", flowID, now, AppRate_); } if (rcvrate > 0) rate_ = AppRate_; else rate_ = 0; if (PRINT_JPD) printf("((S%i)) From receiver: rate = %f, rtt = %f;", flowID, rate_, rtt_); if (rtt_ <= 0) rtt_ = 1; //not yet a valid rtt from receiver => reset rtt_ to default round_id ++ ; //(JPD) reschedule send timer in case it stopped because rate was 0 if (rate_ > SMALLFLOAT && (send_timer_.status() == TIMER_IDLE)) { if (PRINT_JPD_VERBOSE) printf("((S%i)) rescheduling send_timer (was off) at %f\n", flowID, now); double next = size_/rate_; // randomize between next*(1 +/- overhead_) inter_packet = next*(2*overhead_*Random::uniform()-overhead_+1); if (inter_packet > SMALLFLOAT) send_timer_.resched(inter_packet); } /* if we get no more feedback for some time, set rate to 0 */ double t; // if (rate_ < 2) t = DEC_NO_REPORT*rtt_; //we don't really expect NACKs anymore since we're off // else if (active_ && rate > 0) { if (active_ && rate_ > 1) { t = (rtt_ > size_/rate_)?DEC_NO_REPORT*rtt_:DEC_NO_REPORT*size_/rate_; if (PRINT_JPD_VERBOSE) printf("rescheduling NoFeedbackTimer to %f\n", t); NoFeedbacktimer_.resched(t); } if (printStatus_) { printf("time: %5.2f rate: %5.2f\n", now, rate_); double packetrate = rate_ * rtt_ / size_; printf("time: %5.2f packetrate: %5.2f\n", now, packetrate); } if (PRINT_NUMPACK_JPD) { printf("((S%i)) Sent %i packets, rate: %f, rtt: %f\n", flowID, ndatapack_, rate_, rtt_); } Packet::free(pkt); } void PccAgent::sendpkt() { if (active_) { double now = Scheduler::instance().clock(); Packet* p = allocpkt(); hdr_pcc *pcch = hdr_pcc::access(p); pcch->seqno=seqno_++; pcch->timestamp=now; pcch->timestamp_echo = last_timestamp_; pcch->timestamp_offset = now - last_arrival_; pcch->psize=size_; pcch->round_id=round_id; pcch->sendrate=rate_; //for non-CBR scenarios, a rate estimation (and smoothing) needs to be implemented ndatapack_++; send(p, 0); } } void PccAgent::reduce_rate_on_no_feedback() { if (PRINT_JPD) printf("!!! rate_ set to 0 because of no feedback\n"); rate_ = 0; round_id ++ ; } void PccSendTimer::expire(Event *) { a_->nextpkt(); } void PccNoFeedbackTimer::expire(Event *) { a_->reduce_rate_on_no_feedback (); }