// Author: Leslie S. Liu (shihuali@usc.edu) // Written on April 22, 2003 // IMSC , University of Southern California // Original Author: Jae Chung (udp-mm.cc) // File: udp-pp.cc // Written for : ns-2.26 // #include "udp-pp.h" #include "rtp.h" #include "random.h" #include int hdr_pp::offset_; // Mulitmedia Header Class static class P2PHeaderClass : public PacketHeaderClass { public: P2PHeaderClass() : PacketHeaderClass("PacketHeader/P2P", sizeof(hdr_pp)) { bind_offset(&hdr_pp::offset_); } } class_pphdr; // UdpPPAgent OTcl linkage class static class UdpPPAgentClass : public TclClass { public: UdpPPAgentClass() : TclClass("Agent/UDP/UDPpp") {} TclObject* create(int, const char*const*) { return (new UdpPPAgent()); } } class_udppp_agent; // Constructor (with no arg) UdpPPAgent::UdpPPAgent() : UdpAgent() { support_pp_ = 0; asm_info.seq = -1; } UdpPPAgent::UdpPPAgent(packet_t type) : UdpAgent(type) { support_pp_ = 0; asm_info.seq = -1; } // Add Support of P2P Application to UdpAgent::sendmsg void UdpPPAgent::sendmsg(int nbytes, const char* flags) { Packet *p; int n, remain; if (size_) { n = (nbytes/size_ + (nbytes%size_ ? 1 : 0)); remain = nbytes%size_; } else printf("Error: UDPpp size = 0\n"); if (nbytes == -1) { printf("Error: sendmsg() for UDPpp should not be -1\n"); return; } double local_time =Scheduler::instance().clock(); while (n-- > 0) { p = allocpkt(); if(n==0 && remain>0) hdr_cmn::access(p)->size() = remain; else hdr_cmn::access(p)->size() = size_; hdr_rtp* rh = hdr_rtp::access(p); rh->flags() = 0; rh->seqno() = ++seqno_; hdr_cmn::access(p)->timestamp() = (u_int32_t)(SAMPLERATE*local_time); // to eliminate recv to use PP fields for non PP packets hdr_pp* mh = hdr_pp::access(p); //mh->ack = 0; mh->seq = 0; mh->nbytes = 0; mh->time = 0; mh->scale = 0; // pp udp packets are distinguished by setting the ip // priority bit to 15 (Max Priority). if(support_pp_) { hdr_ip* ih = hdr_ip::access(p); hdr_pp* ph_buf=(hdr_pp*) flags; ih->prio_ = 15; if(ph_buf->v_data==1) //this is a voice packet { ih->fid_=3; //color of data stream } if(flags) // PP Seq Num is passed as flags { memcpy(mh, flags, sizeof(hdr_pp)); } } // add "beginning of talkspurt" labels (tcl/ex/test-rcvr.tcl) if (flags && (0 ==strcmp(flags, "NEW_BURST"))) rh->flags() |= RTP_M; target_->recv(p); } idle(); } // Support Packet Re-Assembly and P2P Application void UdpPPAgent::recv(Packet* p, Handler*) { hdr_ip* ih = hdr_ip::access(p); int bytes_to_deliver = hdr_cmn::access(p)->size(); // if it is a PP packet (data or ack) if(ih->prio_ == 15) { if(app_) { // if PP Application exists // re-assemble PP Application packet if segmented hdr_pp* mh = hdr_pp::access(p); printf("[NETWORK] UDP transport P2P packet from addr_(%d) to addr_(%d)\n",ih->saddr(),ih->daddr()); //printf("PPAnget::recv: local seq= %d and packet seq= %d \n",asm_info.seq, mh->seq); if(mh->seq == asm_info.seq) asm_info.rbytes += hdr_cmn::access(p)->size(); else { asm_info.seq = mh->seq; asm_info.tbytes = mh->nbytes; asm_info.rbytes = hdr_cmn::access(p)->size(); } // if fully reassembled, pass the packet to applicatio //printf("PPAnget::recv: rbytes= %d and tbytes= %d \n",asm_info.rbytes, asm_info.tbytes); if(asm_info.tbytes == asm_info.rbytes) { hdr_pp mh_buf; memcpy(&mh_buf, mh, sizeof(hdr_pp)); // printf("PPAnget::recv: pass P2P gpacket up to application level\n"); app_->recv_msg(mh_buf.nbytes, (char*) &mh_buf); //now clear up the asm_info for future packet asm_info.seq=-1; } } Packet::free(p); } // if it is a normal data packet (not PP data or ack packet) else { //printf("PPAgent::recv(): Just a normal packet\n"); if (app_) app_->recv(bytes_to_deliver); Packet::free(p); } }