📄 flooding.h
字号:
* * One subsequent problem is how to know if a packet has been received * before. An easy solution is to use an unique sequence number when * the source initiates a packet. However, we don't want to store * the sequence numbers for all packets received so far. @seq_number_t@ * is used to remember a few (32 more precisely) most recent packets. * The details of this class are not revelant. Just remember that * the only function @check()@ will tell if a sequence number has * seen before. *******************************************************************/ class seq_number_t { public: seq_number_t () : current(0),bits(0u) {} bool check(int n) { if( n + (int)sizeof(unsigned long) <= current ) return true; if ( n > current ) { bits = bits << (n - current); current = n; } unsigned long flag = 1 << (current - n); unsigned long r = flag & bits; bits |= flag; return r; } private: int current; uint32_t bits; }; /******************************************************************* * For each source, we must maintain a @seq_number_t@ object, so we better * keep them in a map. *******************************************************************/ typedef std::map<ether_addr_t, seq_number_t, ether_addr_t::compare> cache_t; cache_t m_seq_cache;};template <class PLD>Flooding<PLD>::Flooding(){ connect delay.to_component, depart;}template <class PLD>Flooding<PLD>::~Flooding(){}template <class PLD>void Flooding<PLD>::Start() { m_mac_busy=false; m_seq_number=1u; m_seq_cache.insert(make_pair(MyEtherAddr,seq_number_t())); SentPackets=RecvPackets=RecvUniPackets=0l; TotalDelay=0.0;}template <class PLD>void Flooding<PLD>::Stop() { //printf("%s: sent %d, recv %d\n",GetName(),SentPackets,RecvPackets); //printf("%s: %f \n", GetName(), (double)RecvPackets/RecvUniPackets);}/******************************************************************* * This function is the member function bound to the inport * @from_transport@. When there is a payload packet to be * transmitted, a new network layer packet will be created, with the * payload packet stored in the payload field. *******************************************************************/template <class PLD>void Flooding<PLD>::from_transport( payload_t& pld, ether_addr_t& dst, unsigned int size){/******************************************************************* * If the mac layer is busy transmitting another packet, we have to * ignore this new packet. When doing so, we must not forgot to * release the packet. Since @PLD@ may be a packet structure or a * packet pointer, the best way is to call the @free()@ function via * the helper class @packet_trait@. *******************************************************************/ if(m_mac_busy) { packet_trait<PLD>::free(pld); return; } packet_t* p=packet_t::alloc(); p->pld=pld; m_seq_number++; m_seq_cache[MyEtherAddr].check(m_seq_number); p->hdr.seq_number=m_seq_number; p->hdr.size=size+2*sizeof(unsigned int); m_mac_busy=true; SentPackets++;/******************************************************************* * The @Printf@ statement will be executed only if a macro, * @<a href=manual.html#COST_DEBUG>COST_DEBUG</a>@, * is defined, and if the first argument, @DumpPackets@, * is true. If @COST_DEBUG@ is not defined, this statement will have * no effect. *******************************************************************/ Printf((DumpPackets,"creates %s\n",p->dump().c_str())); p->hdr.send_time=SimTime(); to_mac(p,ether_addr_t::BROADCAST,size);}/******************************************************************* * We are now receiving a packet from the mac layer. *******************************************************************/template <class PLD>void Flooding<PLD>::from_mac_data (packet_t* pkt, ether_addr_t& dst){ ether_addr_t src; src=pkt->pld.src_addr; RecvPackets++; TotalDelay+=SimTime()-pkt->hdr.send_time; Printf((DumpPackets,"receives %s\n",pkt->dump().c_str())); cache_t::iterator iter=m_seq_cache.find(src); if(iter==m_seq_cache.end()) { // couldn't find the source address in the cache. // so we create a new record iter=(m_seq_cache.insert(make_pair(src,seq_number_t()))).first; } if( !iter->second.check(pkt->hdr.seq_number) ) { // the received packet is new RecvUniPackets++; if(pkt->pld.dst_addr==MyEtherAddr||pkt->pld.dst_addr==ether_addr_t::BROADCAST) { // the packets arrivs at its destination pkt->inc_pld_ref(); to_transport(pkt->pld); } else { // rebroadcast needed if(m_mac_busy==false) { Printf((DumpPackets,"forwards %s\n",pkt->dump().c_str()));/******************************************************************* * Note that this @Write()@ function takes two arguments. We don't * want the mac layer to send the packet immediately, so the second * argument is used to tell the mac layer when to do so. * * We actually have a bug here. We don't set the flag @m_mac_busy@ to * @true@ after writing the packet to the outport. The reason is we * don't have a simple way to modify a variable at a certain future * time. The consequence is that @m_mac_busy@ doesn't reflect the * status of the mac layer correctly. However, it doesn't matter * because packets that go through may still be dropped by the mac * layer. * *******************************************************************/ SentPackets++; pkt->hdr.send_time=SimTime(); delay.Set(pkt,SimTime()+Random(ForwardDelay)); return; } } } pkt->free();}/******************************************************************* * If an ack is recevied, the mac layer must be free, not matter * whether the previous transmission is successful or not. *******************************************************************/template <class PLD>void Flooding<PLD>::from_mac_ack(bool){ m_mac_busy=false;}template <class PLD>void Flooding<PLD>::depart(packet_t* p, unsigned int i){ m_mac_busy=true; to_mac(p,ether_addr_t::BROADCAST,p->hdr.size);}#endif /*flooding_h*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -