1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 University of Washington
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 
19 #include <stdint.h>
20 #include <string>
21 #include <fstream>
22 
23 #include "ns3/abort.h"
24 #include "ns3/assert.h"
25 #include "ns3/log.h"
26 #include "ns3/ptr.h"
27 #include "ns3/node.h"
28 #include "ns3/names.h"
29 #include "ns3/net-device.h"
30 #include "ns3/pcap-file-wrapper.h"
31 
32 #include "trace-helper.h"
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("TraceHelper");
37 
PcapHelper()38 PcapHelper::PcapHelper ()
39 {
40   NS_LOG_FUNCTION_NOARGS ();
41 }
42 
~PcapHelper()43 PcapHelper::~PcapHelper ()
44 {
45   NS_LOG_FUNCTION_NOARGS ();
46 }
47 
48 Ptr<PcapFileWrapper>
CreateFile(std::string filename,std::ios::openmode filemode,DataLinkType dataLinkType,uint32_t snapLen,int32_t tzCorrection)49 PcapHelper::CreateFile (
50   std::string filename,
51   std::ios::openmode filemode,
52   DataLinkType dataLinkType,
53   uint32_t    snapLen,
54   int32_t     tzCorrection)
55 {
56   NS_LOG_FUNCTION (filename << filemode << dataLinkType << snapLen << tzCorrection);
57 
58   Ptr<PcapFileWrapper> file = CreateObject<PcapFileWrapper> ();
59   file->Open (filename, filemode);
60   NS_ABORT_MSG_IF (file->Fail (), "Unable to Open " << filename << " for mode " << filemode);
61 
62   file->Init (dataLinkType, snapLen, tzCorrection);
63   NS_ABORT_MSG_IF (file->Fail (), "Unable to Init " << filename);
64 
65   //
66   // Note that the pcap helper promptly forgets all about the pcap file.  We
67   // rely on the reference count of the file object which will soon be owned
68   // by the caller to keep the object alive.  If the caller uses the file
69   // object to hook a trace source, ownership of the file object will be
70   // implicitly transferred to the callback which keeps the object alive.
71   // When the callback is destroyed (when either the trace is disconnected or
72   // the object with the trace source is deleted) the callback will be destroyed
73   // and the file object will be destroyed, releasing the pointer and closing
74   // the file.
75   //
76   return file;
77 }
78 
79 std::string
GetFilenameFromDevice(std::string prefix,Ptr<NetDevice> device,bool useObjectNames)80 PcapHelper::GetFilenameFromDevice (std::string prefix, Ptr<NetDevice> device, bool useObjectNames)
81 {
82   NS_LOG_FUNCTION (prefix << device << useObjectNames);
83   NS_ABORT_MSG_UNLESS (prefix.size (), "Empty prefix string");
84 
85   std::ostringstream oss;
86   oss << prefix << "-";
87 
88   std::string nodename;
89   std::string devicename;
90 
91   Ptr<Node> node = device->GetNode ();
92 
93   if (useObjectNames)
94     {
95       nodename = Names::FindName (node);
96       devicename = Names::FindName (device);
97     }
98 
99   if (nodename.size ())
100     {
101       oss << nodename;
102     }
103   else
104     {
105       oss << node->GetId ();
106     }
107 
108   oss << "-";
109 
110   if (devicename.size ())
111     {
112       oss << devicename;
113     }
114   else
115     {
116       oss << device->GetIfIndex ();
117     }
118 
119   oss << ".pcap";
120 
121   return oss.str ();
122 }
123 
124 std::string
GetFilenameFromInterfacePair(std::string prefix,Ptr<Object> object,uint32_t interface,bool useObjectNames)125 PcapHelper::GetFilenameFromInterfacePair (std::string prefix, Ptr<Object> object, uint32_t interface, bool useObjectNames)
126 {
127   NS_LOG_FUNCTION (prefix << object << interface << useObjectNames);
128   NS_ABORT_MSG_UNLESS (prefix.size (), "Empty prefix string");
129 
130   std::ostringstream oss;
131   oss << prefix << "-";
132 
133   std::string objname;
134   std::string nodename;
135 
136   Ptr<Node> node = object->GetObject<Node> ();
137 
138   if (useObjectNames)
139     {
140       objname = Names::FindName (object);
141       nodename = Names::FindName (node);
142     }
143 
144   if (objname.size ())
145     {
146       oss << objname;
147     }
148   else if (nodename.size ())
149     {
150       oss << nodename;
151     }
152   else
153     {
154       oss << "n" << node->GetId ();
155     }
156 
157   oss << "-i" << interface << ".pcap";
158 
159   return oss.str ();
160 }
161 
162 //
163 // The basic default trace sink.  This one just writes the packet to the pcap
164 // file which is good enough for most kinds of captures.
165 //
166 void
DefaultSink(Ptr<PcapFileWrapper> file,Ptr<const Packet> p)167 PcapHelper::DefaultSink (Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
168 {
169   NS_LOG_FUNCTION (file << p);
170   file->Write (Simulator::Now (), p);
171 }
172 
173 void
SinkWithHeader(Ptr<PcapFileWrapper> file,const Header & header,Ptr<const Packet> p)174 PcapHelper::SinkWithHeader (Ptr<PcapFileWrapper> file, const Header &header, Ptr<const Packet> p)
175 {
176   NS_LOG_FUNCTION (file << p);
177   file->Write (Simulator::Now (), header, p);
178 }
179 
AsciiTraceHelper()180 AsciiTraceHelper::AsciiTraceHelper ()
181 {
182   NS_LOG_FUNCTION_NOARGS ();
183 }
184 
~AsciiTraceHelper()185 AsciiTraceHelper::~AsciiTraceHelper ()
186 {
187   NS_LOG_FUNCTION_NOARGS ();
188 }
189 
190 Ptr<OutputStreamWrapper>
CreateFileStream(std::string filename,std::ios::openmode filemode)191 AsciiTraceHelper::CreateFileStream (std::string filename, std::ios::openmode filemode)
192 {
193   NS_LOG_FUNCTION (filename << filemode);
194 
195   Ptr<OutputStreamWrapper> StreamWrapper = Create<OutputStreamWrapper> (filename, filemode);
196 
197   //
198   // Note that the ascii trace helper promptly forgets all about the trace file.
199   // We rely on the reference count of the file object which will soon be owned
200   // by the caller to keep the object alive.  If the caller uses the stream
201   // object to hook a trace source, ownership of the stream object will be
202   // implicitly transferred to the callback which keeps the object alive.
203   // When the callback is destroyed (when either the trace is disconnected or
204   // the object with the trace source is deleted) the callback will be destroyed
205   // and the stream object will be destroyed, releasing the pointer and closing
206   // the underlying file.
207   //
208   return StreamWrapper;
209 }
210 
211 std::string
GetFilenameFromDevice(std::string prefix,Ptr<NetDevice> device,bool useObjectNames)212 AsciiTraceHelper::GetFilenameFromDevice (std::string prefix, Ptr<NetDevice> device, bool useObjectNames)
213 {
214   NS_LOG_FUNCTION (prefix << device << useObjectNames);
215   NS_ABORT_MSG_UNLESS (prefix.size (), "Empty prefix string");
216 
217   std::ostringstream oss;
218   oss << prefix << "-";
219 
220   std::string nodename;
221   std::string devicename;
222 
223   Ptr<Node> node = device->GetNode ();
224 
225   if (useObjectNames)
226     {
227       nodename = Names::FindName (node);
228       devicename = Names::FindName (device);
229     }
230 
231   if (nodename.size ())
232     {
233       oss << nodename;
234     }
235   else
236     {
237       oss << node->GetId ();
238     }
239 
240   oss << "-";
241 
242   if (devicename.size ())
243     {
244       oss << devicename;
245     }
246   else
247     {
248       oss << device->GetIfIndex ();
249     }
250 
251   oss << ".tr";
252 
253   return oss.str ();
254 }
255 
256 std::string
GetFilenameFromInterfacePair(std::string prefix,Ptr<Object> object,uint32_t interface,bool useObjectNames)257 AsciiTraceHelper::GetFilenameFromInterfacePair (
258   std::string prefix,
259   Ptr<Object> object,
260   uint32_t interface,
261   bool useObjectNames)
262 {
263   NS_LOG_FUNCTION (prefix << object << interface << useObjectNames);
264   NS_ABORT_MSG_UNLESS (prefix.size (), "Empty prefix string");
265 
266   std::ostringstream oss;
267   oss << prefix << "-";
268 
269   std::string objname;
270   std::string nodename;
271 
272   Ptr<Node> node = object->GetObject<Node> ();
273 
274   if (useObjectNames)
275     {
276       objname = Names::FindName (object);
277       nodename = Names::FindName (node);
278     }
279 
280   if (objname.size ())
281     {
282       oss << objname;
283     }
284   else if (nodename.size ())
285     {
286       oss << nodename;
287     }
288   else
289     {
290       oss << "n" << node->GetId ();
291     }
292 
293   oss << "-i" << interface << ".tr";
294 
295   return oss.str ();
296 }
297 
298 //
299 // One of the basic default trace sink sets.  Enqueue:
300 //
301 //   When a packet has been sent to a device for transmission, the device is
302 //   expected to place the packet onto a transmit queue even if it does not
303 //   have to delay the packet at all, if only to trigger this event.  This
304 //   event will eventually translate into a '+' operation in the trace file.
305 //
306 //   This is typically implemented by hooking the "TxQueue/Enqueue" trace hook
307 //   in the device (actually the Queue in the device).
308 //
309 void
DefaultEnqueueSinkWithoutContext(Ptr<OutputStreamWrapper> stream,Ptr<const Packet> p)310 AsciiTraceHelper::DefaultEnqueueSinkWithoutContext (Ptr<OutputStreamWrapper> stream, Ptr<const Packet> p)
311 {
312   NS_LOG_FUNCTION (stream << p);
313   *stream->GetStream () << "+ " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
314 }
315 
316 void
DefaultEnqueueSinkWithContext(Ptr<OutputStreamWrapper> stream,std::string context,Ptr<const Packet> p)317 AsciiTraceHelper::DefaultEnqueueSinkWithContext (Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
318 {
319   NS_LOG_FUNCTION (stream << p);
320   *stream->GetStream () << "+ " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
321 }
322 
323 //
324 // One of the basic default trace sink sets.  Drop:
325 //
326 //   When a packet has been sent to a device for transmission, the device is
327 //   expected to place the packet onto a transmit queue.  If this queue is
328 //   full the packet will be dropped.  The device is expected to trigger an
329 //   event to indicate that an outbound packet is being dropped.  This event
330 //   will eventually translate into a 'd' operation in the trace file.
331 //
332 //   This is typically implemented by hooking the "TxQueue/Drop" trace hook
333 //   in the device (actually the Queue in the device).
334 //
335 void
DefaultDropSinkWithoutContext(Ptr<OutputStreamWrapper> stream,Ptr<const Packet> p)336 AsciiTraceHelper::DefaultDropSinkWithoutContext (Ptr<OutputStreamWrapper> stream, Ptr<const Packet> p)
337 {
338   NS_LOG_FUNCTION (stream << p);
339   *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
340 }
341 
342 void
DefaultDropSinkWithContext(Ptr<OutputStreamWrapper> stream,std::string context,Ptr<const Packet> p)343 AsciiTraceHelper::DefaultDropSinkWithContext (Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
344 {
345   NS_LOG_FUNCTION (stream << p);
346   *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
347 }
348 
349 //
350 // One of the basic default trace sink sets.  Dequeue:
351 //
352 //   When a packet has been sent to a device for transmission, the device is
353 //   expected to place the packet onto a transmit queue even if it does not
354 //   have to delay the packet at all.  The device removes the packet from the
355 //   transmit queue when the packet is ready to send, and this dequeue will
356 //   fire a corresponding event.  This event will eventually translate into a
357 //   '-' operation in the trace file.
358 //
359 //   This is typically implemented by hooking the "TxQueue/Dequeue" trace hook
360 //   in the device (actually the Queue in the device).
361 //
362 void
DefaultDequeueSinkWithoutContext(Ptr<OutputStreamWrapper> stream,Ptr<const Packet> p)363 AsciiTraceHelper::DefaultDequeueSinkWithoutContext (Ptr<OutputStreamWrapper> stream, Ptr<const Packet> p)
364 {
365   NS_LOG_FUNCTION (stream << p);
366   *stream->GetStream () << "- " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
367 }
368 
369 void
DefaultDequeueSinkWithContext(Ptr<OutputStreamWrapper> stream,std::string context,Ptr<const Packet> p)370 AsciiTraceHelper::DefaultDequeueSinkWithContext (Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
371 {
372   NS_LOG_FUNCTION (stream << p);
373   *stream->GetStream () << "- " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
374 }
375 
376 //
377 // One of the basic default trace sink sets.  Receive:
378 //
379 //   When a packet is received by a device for transmission, the device is
380 //   expected to trigger this event to indicate the reception has occurred.
381 //   This event will eventually translate into an 'r' operation in the trace
382 //   file.
383 //
384 //   This is typically implemented by hooking the "MacRx" trace hook in the
385 //   device.
386 void
DefaultReceiveSinkWithoutContext(Ptr<OutputStreamWrapper> stream,Ptr<const Packet> p)387 AsciiTraceHelper::DefaultReceiveSinkWithoutContext (Ptr<OutputStreamWrapper> stream, Ptr<const Packet> p)
388 {
389   NS_LOG_FUNCTION (stream << p);
390   *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
391 }
392 
393 void
DefaultReceiveSinkWithContext(Ptr<OutputStreamWrapper> stream,std::string context,Ptr<const Packet> p)394 AsciiTraceHelper::DefaultReceiveSinkWithContext (Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
395 {
396   NS_LOG_FUNCTION (stream << p);
397   *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
398 }
399 
400 void
EnablePcap(std::string prefix,Ptr<NetDevice> nd,bool promiscuous,bool explicitFilename)401 PcapHelperForDevice::EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
402 {
403   EnablePcapInternal (prefix, nd, promiscuous, explicitFilename);
404 }
405 
406 void
EnablePcap(std::string prefix,std::string ndName,bool promiscuous,bool explicitFilename)407 PcapHelperForDevice::EnablePcap (std::string prefix, std::string ndName, bool promiscuous, bool explicitFilename)
408 {
409   Ptr<NetDevice> nd = Names::Find<NetDevice> (ndName);
410   EnablePcap (prefix, nd, promiscuous, explicitFilename);
411 }
412 
413 void
EnablePcap(std::string prefix,NetDeviceContainer d,bool promiscuous)414 PcapHelperForDevice::EnablePcap (std::string prefix, NetDeviceContainer d, bool promiscuous)
415 {
416   for (NetDeviceContainer::Iterator i = d.Begin (); i != d.End (); ++i)
417     {
418       Ptr<NetDevice> dev = *i;
419       EnablePcap (prefix, dev, promiscuous);
420     }
421 }
422 
423 void
EnablePcap(std::string prefix,NodeContainer n,bool promiscuous)424 PcapHelperForDevice::EnablePcap (std::string prefix, NodeContainer n, bool promiscuous)
425 {
426   NetDeviceContainer devs;
427   for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i)
428     {
429       Ptr<Node> node = *i;
430       for (uint32_t j = 0; j < node->GetNDevices (); ++j)
431         {
432           devs.Add (node->GetDevice (j));
433         }
434     }
435   EnablePcap (prefix, devs, promiscuous);
436 }
437 
438 void
EnablePcapAll(std::string prefix,bool promiscuous)439 PcapHelperForDevice::EnablePcapAll (std::string prefix, bool promiscuous)
440 {
441   EnablePcap (prefix, NodeContainer::GetGlobal (), promiscuous);
442 }
443 
444 void
EnablePcap(std::string prefix,uint32_t nodeid,uint32_t deviceid,bool promiscuous)445 PcapHelperForDevice::EnablePcap (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool promiscuous)
446 {
447   NodeContainer n = NodeContainer::GetGlobal ();
448 
449   for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i)
450     {
451       Ptr<Node> node = *i;
452       if (node->GetId () != nodeid)
453         {
454           continue;
455         }
456 
457       NS_ABORT_MSG_IF (deviceid >= node->GetNDevices (), "PcapHelperForDevice::EnablePcap(): Unknown deviceid = "
458                        << deviceid);
459       Ptr<NetDevice> nd = node->GetDevice (deviceid);
460       EnablePcap (prefix, nd, promiscuous);
461       return;
462     }
463 }
464 
465 //
466 // Public API
467 //
468 void
EnableAscii(std::string prefix,Ptr<NetDevice> nd,bool explicitFilename)469 AsciiTraceHelperForDevice::EnableAscii (std::string prefix, Ptr<NetDevice> nd, bool explicitFilename)
470 {
471   EnableAsciiInternal (Ptr<OutputStreamWrapper> (), prefix, nd, explicitFilename);
472 }
473 
474 //
475 // Public API
476 //
477 void
EnableAscii(Ptr<OutputStreamWrapper> stream,Ptr<NetDevice> nd)478 AsciiTraceHelperForDevice::EnableAscii (Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd)
479 {
480   EnableAsciiInternal (stream, std::string (), nd, false);
481 }
482 
483 //
484 // Public API
485 //
486 void
EnableAscii(std::string prefix,std::string ndName,bool explicitFilename)487 AsciiTraceHelperForDevice::EnableAscii (std::string prefix, std::string ndName, bool explicitFilename)
488 {
489   EnableAsciiImpl (Ptr<OutputStreamWrapper> (), prefix, ndName, explicitFilename);
490 }
491 
492 //
493 // Public API
494 //
495 void
EnableAscii(Ptr<OutputStreamWrapper> stream,std::string ndName)496 AsciiTraceHelperForDevice::EnableAscii (Ptr<OutputStreamWrapper> stream, std::string ndName)
497 {
498   EnableAsciiImpl (stream, std::string (), ndName, false);
499 }
500 
501 //
502 // Private API
503 //
504 void
EnableAsciiImpl(Ptr<OutputStreamWrapper> stream,std::string prefix,std::string ndName,bool explicitFilename)505 AsciiTraceHelperForDevice::EnableAsciiImpl (
506   Ptr<OutputStreamWrapper> stream,
507   std::string prefix,
508   std::string ndName,
509   bool explicitFilename)
510 {
511   Ptr<NetDevice> nd = Names::Find<NetDevice> (ndName);
512   EnableAsciiInternal (stream, prefix, nd, explicitFilename);
513 }
514 
515 //
516 // Public API
517 //
518 void
EnableAscii(std::string prefix,NetDeviceContainer d)519 AsciiTraceHelperForDevice::EnableAscii (std::string prefix, NetDeviceContainer d)
520 {
521   EnableAsciiImpl (Ptr<OutputStreamWrapper> (), prefix, d);
522 }
523 
524 //
525 // Public API
526 //
527 void
EnableAscii(Ptr<OutputStreamWrapper> stream,NetDeviceContainer d)528 AsciiTraceHelperForDevice::EnableAscii (Ptr<OutputStreamWrapper> stream, NetDeviceContainer d)
529 {
530   EnableAsciiImpl (stream, std::string (), d);
531 }
532 
533 //
534 // Private API
535 //
536 void
EnableAsciiImpl(Ptr<OutputStreamWrapper> stream,std::string prefix,NetDeviceContainer d)537 AsciiTraceHelperForDevice::EnableAsciiImpl (Ptr<OutputStreamWrapper> stream, std::string prefix, NetDeviceContainer d)
538 {
539   for (NetDeviceContainer::Iterator i = d.Begin (); i != d.End (); ++i)
540     {
541       Ptr<NetDevice> dev = *i;
542       EnableAsciiInternal (stream, prefix, dev, false);
543     }
544 }
545 
546 //
547 // Public API
548 //
549 void
EnableAscii(std::string prefix,NodeContainer n)550 AsciiTraceHelperForDevice::EnableAscii (std::string prefix, NodeContainer n)
551 {
552   EnableAsciiImpl (Ptr<OutputStreamWrapper> (), prefix, n);
553 }
554 
555 //
556 // Public API
557 //
558 void
EnableAscii(Ptr<OutputStreamWrapper> stream,NodeContainer n)559 AsciiTraceHelperForDevice::EnableAscii (Ptr<OutputStreamWrapper> stream, NodeContainer n)
560 {
561   EnableAsciiImpl (stream, std::string (), n);
562 }
563 
564 //
565 // Private API
566 //
567 void
EnableAsciiImpl(Ptr<OutputStreamWrapper> stream,std::string prefix,NodeContainer n)568 AsciiTraceHelperForDevice::EnableAsciiImpl (Ptr<OutputStreamWrapper> stream, std::string prefix, NodeContainer n)
569 {
570   NetDeviceContainer devs;
571   for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i)
572     {
573       Ptr<Node> node = *i;
574       for (uint32_t j = 0; j < node->GetNDevices (); ++j)
575         {
576           devs.Add (node->GetDevice (j));
577         }
578     }
579   EnableAsciiImpl (stream, prefix, devs);
580 }
581 
582 //
583 // Public API
584 //
585 void
EnableAsciiAll(std::string prefix)586 AsciiTraceHelperForDevice::EnableAsciiAll (std::string prefix)
587 {
588   EnableAsciiImpl (Ptr<OutputStreamWrapper> (), prefix, NodeContainer::GetGlobal ());
589 }
590 
591 //
592 // Public API
593 //
594 void
EnableAsciiAll(Ptr<OutputStreamWrapper> stream)595 AsciiTraceHelperForDevice::EnableAsciiAll (Ptr<OutputStreamWrapper> stream)
596 {
597   EnableAsciiImpl (stream, std::string (), NodeContainer::GetGlobal ());
598 }
599 
600 //
601 // Public API
602 //
603 void
EnableAscii(Ptr<OutputStreamWrapper> stream,uint32_t nodeid,uint32_t deviceid)604 AsciiTraceHelperForDevice::EnableAscii (Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t deviceid)
605 {
606   EnableAsciiImpl (stream, std::string (), nodeid, deviceid, false);
607 }
608 
609 //
610 // Public API
611 //
612 void
EnableAscii(std::string prefix,uint32_t nodeid,uint32_t deviceid,bool explicitFilename)613 AsciiTraceHelperForDevice::EnableAscii (
614   std::string prefix,
615   uint32_t nodeid,
616   uint32_t deviceid,
617   bool explicitFilename)
618 {
619   EnableAsciiImpl (Ptr<OutputStreamWrapper> (), prefix, nodeid, deviceid, explicitFilename);
620 }
621 
622 //
623 // Private API
624 //
625 void
EnableAsciiImpl(Ptr<OutputStreamWrapper> stream,std::string prefix,uint32_t nodeid,uint32_t deviceid,bool explicitFilename)626 AsciiTraceHelperForDevice::EnableAsciiImpl (
627   Ptr<OutputStreamWrapper> stream,
628   std::string prefix,
629   uint32_t nodeid,
630   uint32_t deviceid,
631   bool explicitFilename)
632 {
633   NodeContainer n = NodeContainer::GetGlobal ();
634 
635   for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i)
636     {
637       Ptr<Node> node = *i;
638       if (node->GetId () != nodeid)
639         {
640           continue;
641         }
642 
643       NS_ABORT_MSG_IF (deviceid >= node->GetNDevices (),
644                        "AsciiTraceHelperForDevice::EnableAscii(): Unknown deviceid = " << deviceid);
645 
646       Ptr<NetDevice> nd = node->GetDevice (deviceid);
647 
648       EnableAsciiInternal (stream, prefix, nd, explicitFilename);
649       return;
650     }
651 }
652 
653 } // namespace ns3
654 
655