A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
config.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2008 INRIA
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  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "config.h"
21 #include "singleton.h"
22 #include "object.h"
23 #include "global-value.h"
24 #include "object-ptr-container.h"
25 #include "names.h"
26 #include "pointer.h"
27 #include "log.h"
28 
29 #include <sstream>
30 
31 NS_LOG_COMPONENT_DEFINE ("Config");
32 
33 namespace ns3 {
34 
35 namespace Config {
36 
38 {
39 }
40 MatchContainer::MatchContainer (const std::vector<Ptr<Object> > &objects,
41  const std::vector<std::string> &contexts,
42  std::string path)
43  : m_objects (objects),
44  m_contexts (contexts),
45  m_path (path)
46 {
47 }
50 {
51  return m_objects.begin ();
52 }
54 MatchContainer::End (void) const
55 {
56  return m_objects.end ();
57 }
58 uint32_t
60 {
61  return m_objects.size ();
62 }
64 MatchContainer::Get (uint32_t i) const
65 {
66  return m_objects[i];
67 }
68 std::string
70 {
71  return m_contexts[i];
72 }
73 std::string
75 {
76  return m_path;
77 }
78 
79 void
80 MatchContainer::Set (std::string name, const AttributeValue &value)
81 {
82  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
83  {
84  Ptr<Object> object = *tmp;
85  object->SetAttribute (name, value);
86  }
87 }
88 void
89 MatchContainer::Connect (std::string name, const CallbackBase &cb)
90 {
91  NS_ASSERT (m_objects.size () == m_contexts.size ());
92  for (uint32_t i = 0; i < m_objects.size (); ++i)
93  {
94  Ptr<Object> object = m_objects[i];
95  std::string ctx = m_contexts[i] + name;
96  object->TraceConnect (name, ctx, cb);
97  }
98 }
99 void
101 {
102  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
103  {
104  Ptr<Object> object = *tmp;
105  object->TraceConnectWithoutContext (name, cb);
106  }
107 }
108 void
109 MatchContainer::Disconnect (std::string name, const CallbackBase &cb)
110 {
111  NS_ASSERT (m_objects.size () == m_contexts.size ());
112  for (uint32_t i = 0; i < m_objects.size (); ++i)
113  {
114  Ptr<Object> object = m_objects[i];
115  std::string ctx = m_contexts[i] + name;
116  object->TraceDisconnect (name, ctx, cb);
117  }
118 }
119 void
121 {
122  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
123  {
124  Ptr<Object> object = *tmp;
125  object->TraceDisconnectWithoutContext (name, cb);
126  }
127 }
128 
129 } // namespace Config
130 
132 {
133 public:
134  ArrayMatcher (std::string element);
135  bool Matches (uint32_t i) const;
136 private:
137  bool StringToUint32 (std::string str, uint32_t *value) const;
138  std::string m_element;
139 };
140 
141 
142 ArrayMatcher::ArrayMatcher (std::string element)
143  : m_element (element)
144 {
145 }
146 bool
147 ArrayMatcher::Matches (uint32_t i) const
148 {
149  if (m_element == "*")
150  {
151  NS_LOG_DEBUG ("Array "<<i<<" matches *");
152  return true;
153  }
154  std::string::size_type tmp;
155  tmp = m_element.find ("|");
156  if (tmp != std::string::npos)
157  {
158  std::string left = m_element.substr (0, tmp-0);
159  std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
160  ArrayMatcher matcher = ArrayMatcher (left);
161  if (matcher.Matches (i))
162  {
163  NS_LOG_DEBUG ("Array "<<i<<" matches "<<left);
164  return true;
165  }
166  matcher = ArrayMatcher (right);
167  if (matcher.Matches (i))
168  {
169  NS_LOG_DEBUG ("Array "<<i<<" matches "<<right);
170  return true;
171  }
172  NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
173  return false;
174  }
175  std::string::size_type leftBracket = m_element.find ("[");
176  std::string::size_type rightBracket = m_element.find ("]");
177  std::string::size_type dash = m_element.find ("-");
178  if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
179  dash > leftBracket && dash < rightBracket)
180  {
181  std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
182  std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
183  uint32_t min;
184  uint32_t max;
185  if (StringToUint32 (lowerBound, &min) &&
186  StringToUint32 (upperBound, &max) &&
187  i >= min && i <= max)
188  {
189  NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
190  return true;
191  }
192  else
193  {
194  NS_LOG_DEBUG ("Array "<<i<<" does not "<<m_element);
195  return false;
196  }
197  }
198  uint32_t value;
199  if (StringToUint32 (m_element, &value) &&
200  i == value)
201  {
202  NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
203  return true;
204  }
205  NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
206  return false;
207 }
208 
209 bool
210 ArrayMatcher::StringToUint32 (std::string str, uint32_t *value) const
211 {
212  std::istringstream iss;
213  iss.str (str);
214  iss >> (*value);
215  return !iss.bad () && !iss.fail ();
216 }
217 
218 
219 class Resolver
220 {
221 public:
222  Resolver (std::string path);
223  virtual ~Resolver ();
224 
225  void Resolve (Ptr<Object> root);
226 private:
227  void Canonicalize (void);
228  void DoResolve (std::string path, Ptr<Object> root);
229  void DoArrayResolve (std::string path, const ObjectPtrContainerValue &vector);
230  void DoResolveOne (Ptr<Object> object);
231  std::string GetResolvedPath (void) const;
232  virtual void DoOne (Ptr<Object> object, std::string path) = 0;
233  std::vector<std::string> m_workStack;
234  std::string m_path;
235 };
236 
237 Resolver::Resolver (std::string path)
238  : m_path (path)
239 {
240  Canonicalize ();
241 }
243 {
244 }
245 void
247 {
248  // ensure that we start and end with a '/'
249  std::string::size_type tmp = m_path.find ("/");
250  if (tmp != 0)
251  {
252  // no slash at start
253  m_path = "/" + m_path;
254  }
255  tmp = m_path.find_last_of ("/");
256  if (tmp != (m_path.size () - 1))
257  {
258  // no slash at end
259  m_path = m_path + "/";
260  }
261 }
262 
263 void
265 {
266  DoResolve (m_path, root);
267 }
268 
269 std::string
271 {
272  std::string fullPath = "/";
273  for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
274  {
275  fullPath += *i + "/";
276  }
277  return fullPath;
278 }
279 
280 void
282 {
283  NS_LOG_DEBUG ("resolved="<<GetResolvedPath ());
284  DoOne (object, GetResolvedPath ());
285 }
286 
287 void
288 Resolver::DoResolve (std::string path, Ptr<Object> root)
289 {
290  NS_LOG_FUNCTION (path << root);
291  NS_ASSERT ((path.find ("/")) == 0);
292  std::string::size_type next = path.find ("/", 1);
293 
294  if (next == std::string::npos)
295  {
296  //
297  // If root is zero, we're beginning to see if we can use the object name
298  // service to resolve this path. It is impossible to have a object name
299  // associated with the root of the object name service since that root
300  // is not an object. This path must be referring to something in another
301  // namespace and it will have been found already since the name service
302  // is always consulted last.
303  //
304  if (root)
305  {
306  DoResolveOne (root);
307  }
308  return;
309  }
310  std::string item = path.substr (1, next-1);
311  std::string pathLeft = path.substr (next, path.size ()-next);
312 
313  //
314  // If root is zero, we're beginning to see if we can use the object name
315  // service to resolve this path. In this case, we must see the name space
316  // "/Names" on the front of this path. There is no object associated with
317  // the root of the "/Names" namespace, so we just ignore it and move on to
318  // the next segment.
319  //
320  if (root == 0)
321  {
322  std::string::size_type offset = path.find ("/Names");
323  if (offset == 0)
324  {
325  m_workStack.push_back (item);
326  DoResolve (pathLeft, root);
327  m_workStack.pop_back ();
328  return;
329  }
330  }
331 
332  //
333  // We have an item (possibly a segment of a namespace path. Check to see if
334  // we can determine that this segment refers to a named object. If root is
335  // zero, this means to look in the root of the "/Names" name space, otherwise
336  // it refers to a name space context (level).
337  //
338  Ptr<Object> namedObject = Names::Find<Object> (root, item);
339  if (namedObject)
340  {
341  NS_LOG_DEBUG ("Name system resolved item = " << item << " to " << namedObject);
342  m_workStack.push_back (item);
343  DoResolve (pathLeft, namedObject);
344  m_workStack.pop_back ();
345  return;
346  }
347 
348  //
349  // We're done with the object name service hooks, so proceed down the path
350  // of types and attributes; but only if root is nonzero. If root is zero
351  // and we find ourselves here, we are trying to check in the namespace for
352  // a path that is not in the "/Names" namespace. We will have previously
353  // found any matches, so we just bail out.
354  //
355  if (root == 0)
356  {
357  return;
358  }
359  std::string::size_type dollarPos = item.find ("$");
360  if (dollarPos == 0)
361  {
362  // This is a call to GetObject
363  std::string tidString = item.substr (1, item.size () - 1);
364  NS_LOG_DEBUG ("GetObject="<<tidString<<" on path="<<GetResolvedPath ());
365  TypeId tid = TypeId::LookupByName (tidString);
366  Ptr<Object> object = root->GetObject<Object> (tid);
367  if (object == 0)
368  {
369  NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath ());
370  return;
371  }
372  m_workStack.push_back (item);
373  DoResolve (pathLeft, object);
374  m_workStack.pop_back ();
375  }
376  else
377  {
378  // this is a normal attribute.
379  TypeId tid = root->GetInstanceTypeId ();
380  bool foundMatch = false;
381  for (uint32_t i = 0; i < tid.GetAttributeN(); i++)
382  {
383  struct TypeId::AttributeInformation info;
384  info = tid.GetAttribute(i);
385  if (info.name != item && item != "*")
386  {
387  continue;
388  }
389  // attempt to cast to a pointer checker.
390  const PointerChecker *ptr = dynamic_cast<const PointerChecker *> (PeekPointer (info.checker));
391  if (ptr != 0)
392  {
393  NS_LOG_DEBUG ("GetAttribute(ptr)="<<info.name<<" on path="<<GetResolvedPath ());
394  PointerValue ptr;
395  root->GetAttribute (info.name, ptr);
396  Ptr<Object> object = ptr.Get<Object> ();
397  if (object == 0)
398  {
399  NS_LOG_ERROR ("Requested object name=\""<<item<<
400  "\" exists on path=\""<<GetResolvedPath ()<<"\""
401  " but is null.");
402  continue;
403  }
404  foundMatch = true;
405  m_workStack.push_back (info.name);
406  DoResolve (pathLeft, object);
407  m_workStack.pop_back ();
408  }
409  // attempt to cast to an object vector.
410  const ObjectPtrContainerChecker *vectorChecker =
411  dynamic_cast<const ObjectPtrContainerChecker *> (PeekPointer (info.checker));
412  if (vectorChecker != 0)
413  {
414  NS_LOG_DEBUG ("GetAttribute(vector)="<<info.name<<" on path="<<GetResolvedPath () << pathLeft);
415  foundMatch = true;
417  root->GetAttribute (info.name, vector);
418  m_workStack.push_back (info.name);
419  DoArrayResolve (pathLeft, vector);
420  m_workStack.pop_back ();
421  }
422  // this could be anything else and we don't know what to do with it.
423  // So, we just ignore it.
424  }
425  if (!foundMatch)
426  {
427  NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath ());
428  return;
429  }
430  }
431 }
432 
433 void
434 Resolver::DoArrayResolve (std::string path, const ObjectPtrContainerValue &container)
435 {
436  NS_LOG_FUNCTION(this << path);
437  NS_ASSERT (path != "");
438  NS_ASSERT ((path.find ("/")) == 0);
439  std::string::size_type next = path.find ("/", 1);
440  if (next == std::string::npos)
441  {
442  return;
443  }
444  std::string item = path.substr (1, next-1);
445  std::string pathLeft = path.substr (next, path.size ()-next);
446 
447  ArrayMatcher matcher = ArrayMatcher (item);
449  for (it = container.Begin (); it != container.End (); ++it)
450  {
451  if (matcher.Matches ((*it).first))
452  {
453  std::ostringstream oss;
454  oss << (*it).first;
455  m_workStack.push_back (oss.str ());
456  DoResolve (pathLeft, (*it).second);
457  m_workStack.pop_back ();
458  }
459  }
460 }
461 
462 
464 {
465 public:
466  void Set (std::string path, const AttributeValue &value);
467  void ConnectWithoutContext (std::string path, const CallbackBase &cb);
468  void Connect (std::string path, const CallbackBase &cb);
469  void DisconnectWithoutContext (std::string path, const CallbackBase &cb);
470  void Disconnect (std::string path, const CallbackBase &cb);
471  Config::MatchContainer LookupMatches (std::string path);
472 
475 
476  uint32_t GetRootNamespaceObjectN (void) const;
477  Ptr<Object> GetRootNamespaceObject (uint32_t i) const;
478 
479 private:
480  void ParsePath (std::string path, std::string *root, std::string *leaf) const;
481  typedef std::vector<Ptr<Object> > Roots;
483 };
484 
485 void
486 ConfigImpl::ParsePath (std::string path, std::string *root, std::string *leaf) const
487 {
488  std::string::size_type slash = path.find_last_of ("/");
489  NS_ASSERT (slash != std::string::npos);
490  *root = path.substr (0, slash);
491  *leaf = path.substr (slash+1, path.size ()-(slash+1));
492  NS_LOG_FUNCTION (path << *root << *leaf);
493 }
494 
495 void
496 ConfigImpl::Set (std::string path, const AttributeValue &value)
497 {
498  std::string root, leaf;
499  ParsePath (path, &root, &leaf);
500  Config::MatchContainer container = LookupMatches (root);
501  container.Set (leaf, value);
502 }
503 void
504 ConfigImpl::ConnectWithoutContext (std::string path, const CallbackBase &cb)
505 {
506  std::string root, leaf;
507  ParsePath (path, &root, &leaf);
508  Config::MatchContainer container = LookupMatches (root);
509  container.ConnectWithoutContext (leaf, cb);
510 }
511 void
513 {
514  std::string root, leaf;
515  ParsePath (path, &root, &leaf);
516  Config::MatchContainer container = LookupMatches (root);
517  container.DisconnectWithoutContext (leaf, cb);
518 }
519 void
520 ConfigImpl::Connect (std::string path, const CallbackBase &cb)
521 {
522  std::string root, leaf;
523  ParsePath (path, &root, &leaf);
524  Config::MatchContainer container = LookupMatches (root);
525  container.Connect (leaf, cb);
526 }
527 void
528 ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
529 {
530  std::string root, leaf;
531  ParsePath (path, &root, &leaf);
532  Config::MatchContainer container = LookupMatches (root);
533  container.Disconnect (leaf, cb);
534 }
535 
537 ConfigImpl::LookupMatches (std::string path)
538 {
539  NS_LOG_FUNCTION (path);
540  class LookupMatchesResolver : public Resolver
541  {
542  public:
543  LookupMatchesResolver (std::string path)
544  : Resolver (path)
545  {}
546  virtual void DoOne (Ptr<Object> object, std::string path) {
547  m_objects.push_back (object);
548  m_contexts.push_back (path);
549  }
550  std::vector<Ptr<Object> > m_objects;
551  std::vector<std::string> m_contexts;
552  } resolver = LookupMatchesResolver (path);
553  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
554  {
555  resolver.Resolve (*i);
556  }
557 
558  //
559  // See if we can do something with the object name service. Starting with
560  // the root pointer zeroed indicates to the resolver that it should start
561  // looking at the root of the "/Names" namespace during this go.
562  //
563  resolver.Resolve (0);
564 
565  return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
566 }
567 
568 void
570 {
571  m_roots.push_back (obj);
572 }
573 
574 void
576 {
577  for (std::vector<Ptr<Object> >::iterator i = m_roots.begin (); i != m_roots.end (); i++)
578  {
579  if (*i == obj)
580  {
581  m_roots.erase (i);
582  return;
583  }
584  }
585 }
586 
587 uint32_t
589 {
590  return m_roots.size ();
591 }
594 {
595  return m_roots[i];
596 }
597 
598 namespace Config {
599 
600 void Reset (void)
601 {
602  // First, let's reset the initial value of every attribute
603  for (uint32_t i = 0; i < TypeId::GetRegisteredN (); i++)
604  {
605  TypeId tid = TypeId::GetRegistered (i);
606  for (uint32_t j = 0; j < tid.GetAttributeN (); j++)
607  {
608  struct TypeId::AttributeInformation info = tid.GetAttribute (j);
610  }
611  }
612  // now, let's reset the initial value of every global value.
614  {
615  (*i)->ResetInitialValue ();
616  }
617 }
618 
619 void Set (std::string path, const AttributeValue &value)
620 {
621  Singleton<ConfigImpl>::Get ()->Set (path, value);
622 }
623 void SetDefault (std::string name, const AttributeValue &value)
624 {
625  if (!SetDefaultFailSafe(name, value))
626  {
627  NS_FATAL_ERROR ("Could not set default value for " << name);
628  }
629 }
630 bool SetDefaultFailSafe (std::string fullName, const AttributeValue &value)
631 {
632  std::string::size_type pos = fullName.rfind ("::");
633  if (pos == std::string::npos)
634  {
635  return false;
636  }
637  std::string tidName = fullName.substr (0, pos);
638  std::string paramName = fullName.substr (pos+2, fullName.size () - (pos+2));
639  TypeId tid;
640  bool ok = TypeId::LookupByNameFailSafe (tidName, &tid);
641  if (!ok)
642  {
643  return false;
644  }
645  for (uint32_t j = 0; j < tid.GetAttributeN (); j++)
646  {
647  struct TypeId::AttributeInformation tmp = tid.GetAttribute(j);
648  if (tmp.name == paramName)
649  {
651  if (v == 0)
652  {
653  return false;
654  }
655  tid.SetAttributeInitialValue (j, v);
656  return true;
657  }
658  }
659  return false;
660 }
661 void SetGlobal (std::string name, const AttributeValue &value)
662 {
663  GlobalValue::Bind (name, value);
664 }
665 bool SetGlobalFailSafe (std::string name, const AttributeValue &value)
666 {
667  return GlobalValue::BindFailSafe (name, value);
668 }
669 void ConnectWithoutContext (std::string path, const CallbackBase &cb)
670 {
671  Singleton<ConfigImpl>::Get ()->ConnectWithoutContext (path, cb);
672 }
673 void DisconnectWithoutContext (std::string path, const CallbackBase &cb)
674 {
675  Singleton<ConfigImpl>::Get ()->DisconnectWithoutContext (path, cb);
676 }
677 void
678 Connect (std::string path, const CallbackBase &cb)
679 {
680  Singleton<ConfigImpl>::Get ()->Connect (path, cb);
681 }
682 void
683 Disconnect (std::string path, const CallbackBase &cb)
684 {
685  Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
686 }
688 {
689  return Singleton<ConfigImpl>::Get ()->LookupMatches (path);
690 }
691 
693 {
694  Singleton<ConfigImpl>::Get ()->RegisterRootNamespaceObject (obj);
695 }
696 
698 {
699  Singleton<ConfigImpl>::Get ()->UnregisterRootNamespaceObject (obj);
700 }
701 
702 uint32_t GetRootNamespaceObjectN (void)
703 {
704  return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObjectN ();
705 }
706 
708 {
709  return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObject (i);
710 }
711 
712 } // namespace Config
713 
714 } // namespace ns3