1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
|
2 /* |
|
3 * This program is free software; you can redistribute it and/or modify |
|
4 * it under the terms of the GNU General Public License version 2 as |
|
5 * published by the Free Software Foundation; |
|
6 * |
|
7 * This program is distributed in the hope that it will be useful, |
|
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
10 * GNU General Public License for more details. |
|
11 * |
|
12 * You should have received a copy of the GNU General Public License |
|
13 * along with this program; if not, write to the Free Software |
|
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
15 * |
|
16 * Author: George F. Riley<riley@ece.gatech.edu> |
|
17 */ |
|
18 |
|
19 // Interface between ns3 and the network animator |
|
20 |
|
21 #include <stdio.h> |
|
22 #include <sstream> |
|
23 |
|
24 #include "ns3/net-anim-config.h" |
|
25 |
|
26 // Socket related includes |
|
27 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) |
|
28 # include <sys/socket.h> |
|
29 # include <netinet/in.h> |
|
30 #else |
|
31 #include <fcntl.h> |
|
32 #endif |
|
33 |
|
34 // ns3 includes |
|
35 #include "ns3/animation-interface.h" |
|
36 #include "ns3/channel.h" |
|
37 #include "ns3/config.h" |
|
38 #include "ns3/node.h" |
|
39 #include "ns3/node-location.h" |
|
40 #include "ns3/packet.h" |
|
41 #include "ns3/simulator.h" |
|
42 |
|
43 using namespace std; |
|
44 |
|
45 NS_LOG_COMPONENT_DEFINE ("AnimationInterface"); |
|
46 |
|
47 namespace ns3 { |
|
48 |
|
49 AnimationInterface::AnimationInterface () |
|
50 : m_fHandle (STDOUT_FILENO), m_model (0) |
|
51 { |
|
52 } |
|
53 |
|
54 bool AnimationInterface::SetOutputFile (const std::string& fn) |
|
55 { |
|
56 FILE* f = fopen (fn.c_str (), "w"); |
|
57 if (!f) |
|
58 { |
|
59 return false; // Can't open |
|
60 } |
|
61 m_fHandle = fileno (f); // Set the file handle |
|
62 return true; |
|
63 } |
|
64 |
|
65 bool AnimationInterface::SetServerPort (uint16_t port) |
|
66 { |
|
67 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) |
|
68 int s = socket (AF_INET, SOCK_STREAM, 0); |
|
69 struct sockaddr_in addr; |
|
70 addr.sin_family = AF_INET; |
|
71 addr.sin_port = htons (port); |
|
72 addr.sin_addr.s_addr = htonl (INADDR_ANY); |
|
73 if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0) |
|
74 { |
|
75 NS_LOG_WARN ("Can't bind to port " << port << ", exiting."); |
|
76 return false; |
|
77 } |
|
78 listen (s, 1); |
|
79 NS_LOG_INFO ("Waiting for animator connection"); |
|
80 // Now wait for the animator to connect in |
|
81 m_fHandle = accept (s, 0, 0); |
|
82 NS_LOG_INFO ("Got animator connection from remote"); |
|
83 // set the linger socket option |
|
84 int t = 1; |
|
85 setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t)); |
|
86 return true; |
|
87 #endif |
|
88 return false;//never reached unless the above is disabled |
|
89 } |
|
90 |
|
91 bool AnimationInterface::SetInternalAnimation () |
|
92 { |
|
93 return false; // Not implemented yet |
|
94 } |
|
95 |
|
96 void AnimationInterface::StartAnimation () |
|
97 { |
|
98 // Dump the topology |
|
99 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) |
|
100 { |
|
101 Ptr<Node> n = *i; |
|
102 Ptr<NodeLocation> loc = n->GetObject<NodeLocation> (); |
|
103 if (loc) |
|
104 { |
|
105 // Location exists, dump it |
|
106 Vector v = loc->GetLocation (); |
|
107 ostringstream oss; |
|
108 oss << "0.0 N " << n->GetId () |
|
109 << " " << v.x << " " << v.y << endl; |
|
110 WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); |
|
111 } |
|
112 } |
|
113 // Now dump the p2p links |
|
114 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End(); ++i) |
|
115 { |
|
116 Ptr<Node> n = *i; |
|
117 uint32_t n1Id = n->GetId (); |
|
118 uint32_t nDev = n->GetNDevices (); // Number of devices |
|
119 for (uint32_t i = 0; i < nDev; ++i) |
|
120 { |
|
121 Ptr<NetDevice> dev = n->GetDevice (i); |
|
122 Ptr<Channel> ch = dev->GetChannel (); |
|
123 if (!ch) |
|
124 { |
|
125 continue; // No channel, can't be p2p device |
|
126 } |
|
127 string channelType = ch->GetInstanceTypeId ().GetName (); |
|
128 if (channelType == string ("ns3::PointToPointChannel")) |
|
129 { // Since these are duplex links, we only need to dump |
|
130 // if srcid < dstid |
|
131 uint32_t nChDev = ch->GetNDevices (); |
|
132 for (uint32_t j = 0; j < nChDev; ++j) |
|
133 { |
|
134 Ptr<NetDevice> chDev = ch->GetDevice (j); |
|
135 uint32_t n2Id = chDev->GetNode ()->GetId (); |
|
136 if (n1Id < n2Id) |
|
137 { // ouptut the p2p link |
|
138 ostringstream oss; |
|
139 oss << "0.0 L " << n1Id << " " << n2Id << endl; |
|
140 WriteN (m_fHandle, oss.str ().c_str (), |
|
141 oss.str ().length ()); |
|
142 } |
|
143 } |
|
144 } |
|
145 else |
|
146 { |
|
147 NS_FATAL_ERROR ("Net animation currently only supports point-to-point links."); |
|
148 } |
|
149 } |
|
150 } |
|
151 |
|
152 // Connect the callback for packet tx events |
|
153 Config::Connect ("/ChannelList/*/TxRxPointToPoint", |
|
154 MakeCallback (&AnimationInterface::DevTxTrace, this)); |
|
155 } |
|
156 |
|
157 void AnimationInterface::StopAnimation () |
|
158 { |
|
159 if (m_fHandle > 0) |
|
160 { |
|
161 close (m_fHandle); |
|
162 } |
|
163 } |
|
164 |
|
165 |
|
166 // Private methods |
|
167 int AnimationInterface::WriteN (int h, const char* data, uint32_t count) |
|
168 { // Write count bytes to h from data |
|
169 uint32_t nLeft = count; |
|
170 const char* p = data; |
|
171 uint32_t written = 0; |
|
172 |
|
173 while (nLeft) |
|
174 { |
|
175 int n = write (h, p, nLeft); |
|
176 if (n <= 0) |
|
177 { |
|
178 return written; |
|
179 } |
|
180 written += n; |
|
181 nLeft -= n; |
|
182 p += n; |
|
183 } |
|
184 return written; |
|
185 } |
|
186 |
|
187 void AnimationInterface::DevTxTrace (std::string context, Ptr<const Packet> p, |
|
188 Ptr<NetDevice> tx, Ptr<NetDevice> rx, |
|
189 Time txTime, Time rxTime) |
|
190 { |
|
191 Time now = Simulator::Now (); |
|
192 ostringstream oss; |
|
193 oss << now.GetSeconds() << " P " |
|
194 << tx->GetNode ()->GetId () << " " |
|
195 << rx->GetNode ()->GetId () << " " |
|
196 << (now + txTime).GetSeconds () << " " // last bit tx time |
|
197 << (now + rxTime - txTime).GetSeconds() << " " // first bit rx time |
|
198 << (now + rxTime).GetSeconds () << endl; // last bit rx time |
|
199 WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); |
|
200 } |
|
201 |
|
202 } // namespace ns3 |
|