src/contrib/pyviz.cc
author Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
Thu Dec 04 18:49:58 2008 +0000 (2008-12-04)
changeset 3902 2f13b3d633bf
parent 3887 7809ce96af0d
child 3903 4efd2ca7592b
permissions -rw-r--r--
Preparation for positioning bitrate labels inside the screen, when possible; now only the actual line clipping algorithm remaining to be implemented...
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2008 INESC Porto
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    18  * Author: Gustavo Carneiro  <gjc@inescporto.pt>
    19  */
    20 
    21 #include <stdlib.h>
    22 #include "pyviz.h"
    23 #include "ns3/simulator.h"
    24 #include "ns3/config.h"
    25 #include "ns3/node-list.h"
    26 #include "ns3/wifi-net-device.h"
    27 #include "ns3/ethernet-header.h"
    28 #include "ns3/log.h"
    29 #include "ns3/ppp-header.h"
    30 
    31 #include <sstream>
    32 
    33 NS_LOG_COMPONENT_DEFINE ("PyViz");
    34 #define NUM_LAST_PACKETS 10
    35 
    36 static
    37 std::vector<std::string>
    38 PathSplit (std::string str)
    39 {
    40   std::vector<std::string> results;
    41   size_t cutAt;
    42   while ((cutAt = str.find_first_of('/')) != str.npos)
    43     {
    44       if(cutAt > 0)
    45         {
    46           results.push_back(str.substr(0,cutAt));
    47         }
    48       str = str.substr(cutAt+1);
    49     }
    50   if (str.length() > 0)
    51     {
    52       results.push_back(str);
    53     }
    54   return results;
    55 }
    56 
    57 
    58 namespace ns3 {
    59 
    60 static PyViz* g_visualizer = NULL;
    61 
    62 PyViz::PyViz ()
    63 {
    64   NS_ASSERT (g_visualizer == NULL);
    65   g_visualizer = this;
    66 
    67   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Tx",
    68                    MakeCallback (&PyViz::TraceNetDevTxWifi, this));
    69 
    70   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Rx",
    71                    MakeCallback (&PyViz::TraceNetDevRxWifi, this));
    72 
    73   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/TxQueue/Dequeue",
    74                    MakeCallback (&PyViz::TraceNetDevTxCsma, this));
    75 
    76   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/Rx",
    77                    MakeCallback (&PyViz::TraceNetDevRxCsma, this));
    78 
    79   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/PromiscRx",
    80                    MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
    81 
    82   Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
    83                    MakeCallback (&PyViz::TraceDrop, this));
    84 
    85   Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
    86                    MakeCallback (&PyViz::TraceDrop, this));
    87 
    88   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/TxQueue/Dequeue",
    89                    MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
    90 
    91   Config::Connect ("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/Rx",
    92                    MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
    93 }
    94 
    95 void
    96 PyViz::RegisterCsmaLikeDevice (std::string const &deviceTypeName)
    97 {
    98   TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
    99 
   100   std::ostringstream sstream;
   101   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
   102   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxCsma, this));
   103 
   104   sstream.str ("");
   105   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
   106   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxCsma, this));
   107 
   108   sstream.str ("");
   109   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/PromiscRx";
   110   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevPromiscRxCsma, this));
   111 }
   112 
   113 void
   114 PyViz::RegisterWifiLikeDevice (std::string const &deviceTypeName)
   115 {
   116   TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
   117 
   118   std::ostringstream sstream;
   119   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Tx";
   120   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxWifi, this));
   121 
   122   sstream.str ("");
   123   sstream <<"/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
   124   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxWifi, this));
   125 }
   126 
   127 void
   128 PyViz::RegisterPointToPointLikeDevice (std::string const &deviceTypeName)
   129 {
   130   TypeId::LookupByName (deviceTypeName); // this will assert if the type name is invalid
   131 
   132   std::ostringstream sstream;
   133   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/TxQueue/Dequeue";
   134   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevTxPointToPoint, this));
   135 
   136   sstream.str ("");
   137   sstream << "/NodeList/*/DeviceList/*/$" << deviceTypeName << "/Rx";
   138   Config::Connect (sstream.str (), MakeCallback (&PyViz::TraceNetDevRxPointToPoint, this));
   139 }
   140 
   141 void
   142 PyViz::SetPacketCaptureOptions (uint32_t nodeId, PacketCaptureOptions options)
   143 {
   144   NS_LOG_DEBUG ("  SetPacketCaptureOptions " << nodeId
   145                 << " PacketCaptureOptions (headers size = " << options.headers.size ()
   146                 << " mode = " << options.mode << " numLastPackets = " << options.numLastPackets
   147                 << ")");
   148   m_packetCaptureOptions[nodeId] = options;
   149 }
   150 
   151 void
   152 PyViz::RegisterDropTracePath (std::string const &tracePath)
   153 {
   154   Config::Connect (tracePath, MakeCallback (&PyViz::TraceDrop, this));
   155 }
   156 
   157 PyViz::~PyViz ()
   158 {
   159   NS_ASSERT (g_visualizer == this);
   160   g_visualizer = NULL;
   161 }
   162 
   163 void PyViz::DoPause (std::string const &message)
   164 {
   165   m_pauseMessages.push_back (message);
   166   m_stop = true;
   167   NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": Have "
   168                 << g_visualizer->m_pauseMessages.size () << " pause messages");
   169 }
   170 
   171 void PyViz::Pause (std::string const &message)
   172 {
   173   NS_ASSERT (g_visualizer);
   174   g_visualizer->DoPause (message);
   175 }
   176 
   177 std::vector<std::string>
   178 PyViz::GetPauseMessages () const
   179 {
   180   NS_LOG_LOGIC (Simulator::Now ().GetSeconds () << ": GetPauseMessages: have "
   181                 << g_visualizer->m_pauseMessages.size () << " pause messages");
   182   return m_pauseMessages;
   183 }
   184     
   185 
   186 void
   187 PyViz::CallbackStopSimulation ()
   188 {
   189   NS_LOG_FUNCTION_NOARGS ();
   190   m_stop = true;
   191 }
   192 
   193 void
   194 PyViz::SimulatorRunUntil (Time time)
   195 {
   196   NS_LOG_LOGIC ("SimulatorRunUntil " << time << " (now is " << Simulator::Now () << ")");
   197 
   198   m_pauseMessages.clear ();
   199   m_transmissionSamples.clear ();
   200   m_packetDrops.clear ();
   201 
   202   Time expirationTime = Simulator::Now () - Seconds (10);
   203 
   204   // Clear very old transmission records
   205   for (std::map<TxRecordKey, TxRecordValue>::iterator iter = m_txRecords.begin ();
   206        iter != m_txRecords.end ();)
   207     {
   208       if (iter->second.time < expirationTime)
   209         {
   210           m_txRecords.erase (iter++);
   211         }
   212       else
   213         {
   214           iter++;
   215         }
   216     }
   217 
   218   // Clear very old packets of interest
   219   for (std::map<uint32_t, Time>::iterator iter = m_packetsOfInterest.begin ();
   220        iter != m_packetsOfInterest.end ();)
   221     {
   222       if (iter->second < expirationTime)
   223         {
   224           m_packetsOfInterest.erase (iter++);
   225         }
   226       else
   227         {
   228           iter++;
   229         }
   230     }
   231 
   232   if (Simulator::IsFinished () || Simulator::Now () >= time)
   233     {
   234       return;
   235     }
   236   // Schedule a dummy callback function for the target time, to make
   237   // sure we stop at the right time.  Otherwise, simulations with few
   238   // events just appear to "jump" big chunks of time.
   239   NS_LOG_LOGIC ("Schedule dummy callback to be called in " << (time - Simulator::Now ()));
   240   m_stop = false;
   241   Simulator::Cancel (m_stopCallbackEvent);
   242   m_stopCallbackEvent = Simulator::Schedule (time - Simulator::Now (), &PyViz::CallbackStopSimulation, this);
   243 
   244   while (!Simulator::IsFinished ())
   245     {
   246       if (m_stop)
   247         {
   248           break;
   249         }
   250       Simulator::RunOneEvent ();
   251     }
   252 }
   253 
   254 bool PyViz::TransmissionSampleKey::operator < (PyViz::TransmissionSampleKey const &other) const
   255 {
   256   if (this->transmitter < other.transmitter)
   257     {
   258       return true;
   259     }
   260   if (this->transmitter != other.transmitter)
   261     {
   262       return false;
   263     }
   264   if (this->receiver < other.receiver)
   265     {
   266       return true;}
   267   if (this->receiver != other.receiver)
   268     {
   269       return false;
   270     }
   271   if (this->channel < other.channel)
   272     {
   273       return true;
   274     }
   275   else
   276     {
   277       return false;
   278     }
   279 }
   280 
   281 bool PyViz::TransmissionSampleKey::operator == (PyViz::TransmissionSampleKey const &other) const
   282 {
   283   bool retval = (transmitter == other.transmitter) &&
   284     (receiver == other.receiver) &&
   285     (channel == other.channel);
   286   return retval;
   287 }
   288 
   289 
   290 PyViz::NetDeviceStatistics &
   291 PyViz::FindNetDeviceStatistics (int node, int interface)
   292 {
   293   std::map<uint32_t, std::vector<NetDeviceStatistics> >::iterator nodeStatsIter = m_nodesStatistics.find (node);
   294   std::vector<NetDeviceStatistics> *stats;
   295   if (nodeStatsIter == m_nodesStatistics.end ())
   296     {
   297       stats = &m_nodesStatistics[node];
   298       stats->resize (NodeList::GetNode (node)->GetNDevices ());
   299     }
   300   else
   301     {
   302       stats = &(nodeStatsIter->second);
   303     }
   304   NetDeviceStatistics &devStats = (*stats)[interface];
   305   return devStats;
   306 }
   307 
   308 bool PyViz::GetPacketCaptureOptions (uint32_t nodeId, const PacketCaptureOptions **outOptions) const
   309 {
   310   std::map<uint32_t, PacketCaptureOptions>::const_iterator iter = m_packetCaptureOptions.find (nodeId);
   311   if (iter == m_packetCaptureOptions.end ())
   312     {
   313       return false;
   314     }
   315   else
   316     {
   317       *outOptions = &iter->second;
   318       return true;
   319     }
   320 }
   321 
   322 bool PyViz::FilterPacket (Ptr<const Packet> packet, const PacketCaptureOptions &options)
   323 {
   324   switch (options.mode)
   325     {
   326     case PACKET_CAPTURE_DISABLED:
   327       return false;
   328 
   329     case PACKET_CAPTURE_FILTER_HEADERS_OR:
   330       {
   331         PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
   332         while (metadataIterator.HasNext ())
   333           {
   334             PacketMetadata::Item item = metadataIterator.Next ();
   335             if (options.headers.find (item.tid) != options.headers.end ())
   336               {
   337                 return true;
   338               }
   339           }
   340         return false;
   341       }
   342 
   343     case PACKET_CAPTURE_FILTER_HEADERS_AND:
   344       {
   345         std::set<TypeId> missingHeaders (options.headers);
   346         PacketMetadata::ItemIterator metadataIterator = packet->BeginItem ();
   347         while (metadataIterator.HasNext ())
   348           {
   349             PacketMetadata::Item item = metadataIterator.Next ();
   350             std::set<TypeId>::iterator missingIter = missingHeaders.find (item.tid);
   351             if (missingIter != missingHeaders.end ())
   352               {
   353                 missingHeaders.erase (missingIter);
   354               }
   355           }
   356         if (missingHeaders.size () == 0)
   357           {
   358             return true;
   359           }
   360         else
   361           {
   362             return false;
   363           }
   364       }
   365 
   366     default:
   367       NS_FATAL_ERROR ("should not be reached");
   368       return false;
   369     }
   370 }
   371 
   372 void PyViz::TraceDrop (std::string context, Ptr<const Packet> packet)
   373 {
   374   NS_LOG_FUNCTION (context << packet->GetUid ());
   375   std::vector<std::string> splitPath = PathSplit (context);
   376   int nodeIndex = atoi (splitPath[1].c_str ());
   377   Ptr<Node> node = NodeList::GetNode (nodeIndex);
   378 
   379   if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
   380     {
   381       // if the transmitting node is not "of interest", we still
   382       // record the transmission if it is a packet of interest.
   383       if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
   384         {
   385           NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
   386           return;
   387         }
   388     }
   389 
   390   // ---- "last packets"
   391   const PacketCaptureOptions *captureOptions;
   392   if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
   393     {
   394       LastPacketsSample &last = m_lastPackets[nodeIndex];
   395       PacketSample lastPacket;
   396       lastPacket.time = Simulator::Now ();
   397       lastPacket.packet = packet->Copy ();
   398       lastPacket.device = NULL;
   399       last.lastDroppedPackets.push_back (lastPacket);
   400       while (last.lastDroppedPackets.size () > captureOptions->numLastPackets)
   401         {
   402           last.lastDroppedPackets.erase (last.lastDroppedPackets.begin ());
   403         }
   404     }
   405 
   406   std::map<Ptr<Node>, uint32_t>::iterator iter = m_packetDrops.find (node);
   407   if (iter == m_packetDrops.end ())
   408     {
   409       m_packetDrops[node] = packet->GetSize ();
   410     }
   411   else
   412     {
   413       iter->second += packet->GetSize ();
   414     }
   415 }
   416 
   417 void
   418 PyViz::TraceNetDevTxWifi (std::string context, Ptr<const Packet> packet, Mac48Address destinationAddress)
   419 {
   420   NS_LOG_FUNCTION (context << packet->GetUid () << *packet);
   421 
   422   std::vector<std::string> splitPath = PathSplit (context);
   423   int nodeIndex = atoi (splitPath[1].c_str ());
   424   int devIndex = atoi (splitPath[3].c_str ());
   425   Ptr<Node> node = NodeList::GetNode (nodeIndex);
   426   Ptr<NetDevice> device = node->GetDevice (devIndex);
   427 
   428   // ---- statistics
   429   NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
   430   ++stats.transmittedPackets;
   431   stats.transmittedBytes += packet->GetSize ();
   432 
   433   // ---- "last packets"
   434   const PacketCaptureOptions *captureOptions;
   435   if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
   436     {
   437       LastPacketsSample &last = m_lastPackets[nodeIndex];
   438       TxPacketSample lastPacket;
   439       lastPacket.time = Simulator::Now ();
   440       lastPacket.packet = packet->Copy ();
   441       lastPacket.device = device;
   442       lastPacket.to = destinationAddress;
   443       last.lastTransmittedPackets.push_back (lastPacket);
   444       while (last.lastTransmittedPackets.size () > captureOptions->numLastPackets)
   445         {
   446           last.lastTransmittedPackets.erase (last.lastTransmittedPackets.begin ());
   447         }
   448     }
   449 
   450   // ---- transmissions records
   451 
   452   if (m_nodesOfInterest.find (nodeIndex) == m_nodesOfInterest.end ())
   453     {
   454       // if the transmitting node is not "of interest", we still
   455       // record the transmission if it is a packet of interest.
   456       if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
   457         {
   458           NS_LOG_DEBUG ("Packet " << packet->GetUid () << " is not of interest");
   459           return;
   460         }
   461     }
   462   else
   463     {
   464       // We will follow this packet throughout the network.
   465       m_packetsOfInterest[packet->GetUid ()] = Simulator::Now ();
   466     }
   467 
   468   TxRecordValue record = { Simulator::Now (), node, false };
   469   if (destinationAddress == device->GetBroadcast ())
   470     {
   471       record.isBroadcast = true;
   472     }
   473   m_txRecords[TxRecordKey (device->GetChannel (), packet->GetUid ())] = record;
   474 }
   475 
   476 void
   477 PyViz::TraceNetDevRxCsma (std::string context, Ptr<const Packet> packet)
   478 {
   479   Ptr<Packet> p = packet->Copy ();
   480   EthernetHeader ethernetHeader;
   481   p->RemoveHeader (ethernetHeader);
   482   TraceNetDevRxWifi (context, p, ethernetHeader.GetSource ());
   483 }
   484 
   485 void
   486 PyViz::TraceNetDevRxPointToPoint (std::string context, Ptr<const Packet> packet)
   487 {
   488   Ptr<Packet> p = packet->Copy ();
   489   PppHeader h;
   490   p->RemoveHeader (h);
   491   TraceNetDevRxWifi (context, p, Mac48Address ());
   492 }
   493 
   494 void
   495 PyViz::TraceNetDevPromiscRxCsma (std::string context, Ptr<const Packet> packet, NetDevice::PacketType packetType)
   496 {
   497   Ptr<Packet> p = packet->Copy ();
   498   EthernetHeader ethernetHeader;
   499   p->RemoveHeader (ethernetHeader);
   500   // Other packet types are already being received by
   501   // TraceNetDevRxCsma; we don't want to receive them twice.
   502   if (packetType == NetDevice::PACKET_OTHERHOST)
   503     {
   504       TraceNetDevRxWifi (context, p, ethernetHeader.GetDestination ());
   505     }
   506 }
   507 
   508 void
   509 PyViz::TraceNetDevTxCsma (std::string context, Ptr<const Packet> packet)
   510 {
   511   EthernetHeader ethernetHeader;
   512   Ptr<Packet> p = packet->Copy ();
   513   p->RemoveHeader (ethernetHeader);
   514   TraceNetDevTxWifi (context, p, ethernetHeader.GetDestination ());
   515 }
   516 
   517 void
   518 PyViz::TraceNetDevTxPointToPoint (std::string context, Ptr<const Packet> packet)
   519 {
   520   Ptr<Packet> p = packet->Copy ();
   521   PppHeader h;
   522   p->RemoveHeader (h);
   523   TraceNetDevTxWifi (context, p, Mac48Address ());
   524 }
   525 
   526 void
   527 PyViz::TraceNetDevRxWifi (std::string context, Ptr<const Packet> packet, Mac48Address from)
   528 {
   529   NS_LOG_FUNCTION (context << packet->GetUid ());
   530   std::vector<std::string> splitPath = PathSplit (context);
   531   int nodeIndex = atoi (splitPath[1].c_str ());
   532   int devIndex = atoi (splitPath[3].c_str ());
   533 
   534   // ---- statistics
   535   NetDeviceStatistics &stats = FindNetDeviceStatistics (nodeIndex, devIndex);
   536   ++stats.receivedPackets;
   537   stats.receivedBytes += packet->GetSize ();
   538 
   539   Ptr<Node> node = NodeList::GetNode (nodeIndex);
   540   Ptr<NetDevice> device = node->GetDevice (devIndex);
   541 
   542   // ---- "last packets"
   543   const PacketCaptureOptions *captureOptions;
   544   if (GetPacketCaptureOptions (nodeIndex, &captureOptions) && FilterPacket (packet, *captureOptions))
   545     {
   546       LastPacketsSample &last = m_lastPackets[nodeIndex];
   547       RxPacketSample lastPacket;
   548       lastPacket.time = Simulator::Now ();
   549       lastPacket.packet = packet->Copy ();
   550       lastPacket.device = device;
   551       lastPacket.from = from;
   552       last.lastReceivedPackets.push_back (lastPacket);
   553       while (last.lastReceivedPackets.size () > captureOptions->numLastPackets)
   554         {
   555           last.lastReceivedPackets.erase (last.lastReceivedPackets.begin ());
   556         }
   557     }
   558 
   559   // ---- transmissions
   560   if (m_packetsOfInterest.find (packet->GetUid ()) == m_packetsOfInterest.end ())
   561     {
   562       NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " is not of interest");
   563       return;
   564     }
   565 
   566   Ptr<Channel> channel = device->GetChannel ();
   567 
   568   std::map<TxRecordKey, TxRecordValue>::iterator recordIter = 
   569     m_txRecords.find (TxRecordKey (channel, packet->GetUid ()));
   570 
   571   if (recordIter == m_txRecords.end ())
   572     {
   573       NS_LOG_DEBUG ("RX Packet " << packet->GetUid () << " was not transmitted?!");
   574       return;
   575     }
   576   
   577   TxRecordValue &record = recordIter->second;
   578   
   579   if (record.srcNode == node)
   580     {
   581       NS_LOG_WARN ("Node " << node->GetId () << " receiving back the same packet (UID=" << packet->GetUid ()
   582                    << ") it had previously transmitted, on the same channel!");
   583       return;
   584     }
   585 
   586   TransmissionSampleKey key = { record.srcNode, node, channel };
   587 
   588 #ifdef  NS3_LOG_ENABLE
   589   NS_LOG_DEBUG("m_transmissionSamples begin:");
   590   if (g_log.IsEnabled (ns3::LOG_DEBUG))
   591     {
   592       for (std::map<TransmissionSampleKey,TransmissionSampleValue>::const_iterator iter
   593              = m_transmissionSamples.begin (); iter != m_transmissionSamples.end (); iter++)
   594         {
   595           NS_LOG_DEBUG(iter->first.transmitter<<"/"<<iter->first.transmitter->GetId () << ", "
   596                        << iter->first.receiver<<"/"<<iter->first.receiver->GetId ()
   597                        << ", " << iter->first.channel << " => " << iter->second.bytes << " (@ " << &iter->second << ")");
   598         }
   599     }
   600   NS_LOG_DEBUG("m_transmissionSamples end.");
   601 #endif
   602 
   603   std::map<TransmissionSampleKey,TransmissionSampleValue>::iterator
   604     iter = m_transmissionSamples.find (key);
   605 
   606   if (iter == m_transmissionSamples.end ())
   607     {
   608       TransmissionSampleValue sample = { packet->GetSize () };
   609       NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
   610                     << key.receiver<<"/"<<key.receiver->GetId()
   611                     << " channel " << channel << ": " << packet->GetSize ()
   612                     << " bytes more. => new sample with " << packet->GetSize () << " bytes.");
   613       m_transmissionSamples[key] = sample;
   614     }
   615   else
   616     {
   617       TransmissionSampleValue &sample = iter->second;
   618       NS_LOG_DEBUG ("RX: from " << key.transmitter<<"/"<<key.transmitter->GetId() << " to "
   619                     << key.receiver<<"/"<<key.receiver->GetId()
   620                     << " channel " << channel << ": " << packet->GetSize ()
   621                     << " bytes more. => sample " << &sample << " with bytes " << sample.bytes);
   622 
   623       sample.bytes += packet->GetSize ();
   624     }
   625 }
   626 
   627 PyViz::TransmissionSampleList
   628 PyViz::GetTransmissionSamples () const
   629 {
   630   NS_LOG_DEBUG ("GetTransmissionSamples BEGIN");
   631   TransmissionSampleList list;
   632   for (std::map<TransmissionSampleKey, TransmissionSampleValue>::const_iterator
   633          iter = m_transmissionSamples.begin ();
   634        iter !=  m_transmissionSamples.end ();
   635        iter++)
   636     {
   637       TransmissionSample sample;
   638       sample.transmitter = iter->first.transmitter;
   639       sample.receiver = iter->first.receiver;
   640       sample.channel = iter->first.channel;
   641       sample.bytes = iter->second.bytes;
   642       NS_LOG_DEBUG ("from " << sample.transmitter->GetId() << " to " << sample.receiver->GetId()
   643                     << ": " << sample.bytes << " bytes.");
   644       list.push_back (sample);
   645     }
   646   NS_LOG_DEBUG ("GetTransmissionSamples END");
   647   return list;
   648 }
   649 
   650 PyViz::PacketDropSampleList
   651 PyViz::GetPacketDropSamples () const
   652 {
   653   NS_LOG_DEBUG ("GetPacketDropSamples BEGIN");
   654   PacketDropSampleList list;
   655   for (std::map<Ptr<Node>, uint32_t>::const_iterator
   656          iter = m_packetDrops.begin ();
   657        iter !=  m_packetDrops.end ();
   658        iter++)
   659     {
   660       PacketDropSample sample;
   661       sample.transmitter = iter->first;
   662       sample.bytes = iter->second;
   663       NS_LOG_DEBUG ("in " << sample.transmitter->GetId() 
   664                     << ": " << sample.bytes << " bytes dropped.");
   665       list.push_back (sample);
   666     }
   667   NS_LOG_DEBUG ("GetPacketDropSamples END");
   668   return list;
   669 }
   670 
   671 void
   672 PyViz::SetNodesOfInterest (std::set<uint32_t> nodes)
   673 {
   674   m_nodesOfInterest = nodes;
   675 }
   676 
   677 std::vector<PyViz::NodeStatistics>
   678 PyViz::GetNodesStatistics () const
   679 {
   680   std::vector<PyViz::NodeStatistics> retval;
   681   for (std::map<uint32_t, std::vector<NetDeviceStatistics> >::const_iterator iter = m_nodesStatistics.begin ();
   682        iter != m_nodesStatistics.end (); iter++)
   683     {
   684       NodeStatistics stats = { iter->first, iter->second };
   685       retval.push_back (stats);
   686     }
   687   return retval;
   688 }
   689 
   690 
   691 PyViz::LastPacketsSample
   692 PyViz::GetLastPackets (uint32_t nodeId) const
   693 {
   694   NS_LOG_DEBUG ("GetLastPackets: " << nodeId);
   695   
   696   std::map<uint32_t, LastPacketsSample>::const_iterator
   697     iter = m_lastPackets.find(nodeId);
   698   if (iter != m_lastPackets.end ())
   699     {
   700       return iter->second;
   701     }
   702   else
   703     {
   704       return LastPacketsSample ();
   705     }
   706 }
   707 
   708 
   709 void
   710 PyViz::LineClipping (double boundsX1, double boundsY1, double boundsX2, double boundsY2,
   711                      double &lineX1, double &lineY1, double &lineX2, double &lineY2)
   712 {
   713 
   714 }
   715 
   716 
   717 }
   718