ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
utils.cc
Go to the documentation of this file.
1 #include "utils.h"
2 #include "dce-manager.h"
3 #include "unix-fd.h"
4 #include "process.h"
5 #include "task-manager.h"
6 #include "ns3/node.h"
7 #include "ns3/log.h"
8 #include <sstream>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <dirent.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <list>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include "file-usage.h"
18 #include "ns3/global-value.h"
19 #include "ns3/uinteger.h"
20 
21 NS_LOG_COMPONENT_DEFINE ("ProcessUtils");
22 
23 namespace ns3 {
24 
25 GlobalValue g_timeBase = GlobalValue ("SimulationTimeBase",
26  "The timebase for this simulation",
27  // January 1st, 2010, 00:00:00
28  UintegerValue (1262304000),
29  MakeUintegerChecker<uint32_t> ());
30  // unsigned long secondsSinceEpochOnFridayApril042008 = 1207284276;
31  // return secondsSinceEpochOnFridayApril042008;
32 
33 uint32_t UtilsGetNodeId (void)
34 {
36  {
38  }
39  return Simulator::GetContext ();
40 }
41 static std::string UtilsGetRealFilePath (uint32_t node)
42 {
43  std::ostringstream oss;
44  oss << "files-" << node;
45  return oss.str ();
46 }
47 static std::string UtilsGetRealFilePath (void)
48 {
50 }
51 
52 std::string UtilsGetAbsRealFilePath (uint32_t node, std::string path)
53 {
54  NS_LOG_FUNCTION (Current () << path);
55 
56  std::string nodeDir = UtilsGetRealFilePath (node);
58  return nodeDir + path;
59 }
60 
61 std::string
62 UtilsGetRealFilePath (std::string path)
63 {
64  NS_LOG_FUNCTION (Current () << path);
65 
66  std::string nodeDir = UtilsGetRealFilePath ();
68  return nodeDir + UtilsGetVirtualFilePath (path);
69 }
70 
71 void
72 UtilsEnsureAllDirectoriesExist (std::string realPath)
73 {
74  int idx = 0;
75 
76  while ((idx = realPath.find ('/', idx)) >= 0)
77  {
78  UtilsEnsureDirectoryExists (realPath.substr (0, idx + 1));
79  idx++;
80  }
81 }
82 
83 void UtilsEnsureDirectoryExists (std::string realPath)
84 {
85  ::DIR *dir = ::opendir (realPath.c_str ());
86  if (dir != 0)
87  {
88  ::closedir (dir);
89  }
90  else if (errno == ENOENT)
91  {
92  int status = ::mkdir (realPath.c_str (), S_IRWXU | S_IRWXG);
93  if (status == -1)
94  {
95  NS_FATAL_ERROR ("Could not create directory " << realPath <<
96  ": " << strerror (errno));
97  }
98  }
99 }
100 
101 std::string UtilsGetVirtualFilePath (std::string path)
102 {
103  NS_LOG_FUNCTION (Current () << path);
104 
105  std::string::size_type slash = path.find ("/");
106  if (slash == 0)
107  {
108  // path relative to root of node.
109  return path;
110  }
111  else
112  {
113  NS_ASSERT (Current () != 0);
114  Thread *current = Current ();
115  // path relative to cwd in node
116  return current->process->cwd + "/" + path;
117  }
118 }
120 
121 Thread * Current (void)
122 {
124  {
126  }
127 
128  TaskManager *manager = TaskManager::Current ();
129  if (manager == 0)
130  {
131  return 0;
132  }
133  return (struct Thread *)manager->CurrentTask ()->GetContext ();
134 }
135 bool HasPendingSignal (void)
136 {
137  bool isPending = sigisemptyset (&(Current ()->process->pendingSignals)) == 0;
138  return isPending;
139 }
140 struct timeval UtilsTimeToTimeval (Time time)
141 {
142  struct timeval tv;
143  int64_t m = time.GetMicroSeconds ();
144  tv.tv_sec = m / 1000000L;
145  tv.tv_usec = m % 1000000L;
146  return tv;
147 }
148 struct timespec UtilsTimeToTimespec (Time time)
149 {
150  struct timespec tv;
151  int64_t n = time.GetNanoSeconds ();
152  tv.tv_sec = (time_t)(n / 1000000000L);
153  tv.tv_nsec = n % 1000000000;
154  return tv;
155 }
157 {
158  UintegerValue uintegerValue;
159  GlobalValue::GetValueByName ("SimulationTimeBase", uintegerValue);
160  return time + Seconds (uintegerValue.Get ());
161 }
163 {
164  UintegerValue uintegerValue;
165  GlobalValue::GetValueByName ("SimulationTimeBase", uintegerValue);
166  return time - Seconds (uintegerValue.Get ());
167 }
168 Time UtilsTimevalToTime (struct timeval tv)
169 {
170  Time time = Seconds (tv.tv_sec);
171  time += MicroSeconds (tv.tv_usec);
172  return time;
173 }
174 Time UtilsTimevalToTime (const struct timeval *tv)
175 {
176  if (tv == 0)
177  {
178  return Seconds (0.0);
179  }
180  return UtilsTimevalToTime (*tv);
181 }
182 Time UtilsTimespecToTime (struct timespec tm)
183 {
184  Time time = Seconds (tm.tv_sec);
185  time += NanoSeconds (tm.tv_nsec);
186  return time;
187 }
188 void
189 UtilsSendSignal (Process *process, int signum)
190 {
191  sigaddset (&process->pendingSignals, signum);
192  for (std::vector<Thread *>::iterator i = process->threads.begin ();
193  i != process->threads.end (); ++i)
194  {
195  Thread *thread = *i;
196  if (sigismember (&thread->signalMask, signum) == 0)
197  {
198  // signal not blocked by thread.
199  if (thread->task->IsBlocked ())
200  {
201  process->manager->Wakeup (thread);
202  return;
203  }
204  }
205  }
206  // Could not find any candidate thread to receive signal.
207  // signal pending until a thread unblocks it.
208 }
209 void UtilsDoSignal (void)
210 {
211  Thread *current = Current ();
212  if (!current)
213  {
214  return;
215  }
216 
217  // we try to check if we
218  // have pending signals and we deliver them if we have any.
219  for (std::vector<SignalHandler>::iterator i = current->process->signalHandlers.begin ();
220  i != current->process->signalHandlers.end (); ++i)
221  {
222  if (sigismember (&current->signalMask, i->signal) == 1
223  && i->signal != SIGKILL
224  && i->signal != SIGSTOP)
225  {
226  // don't deliver signals which are masked
227  // ignore the signal mask for SIGKILL and SIGSTOP
228  // though.
229  continue;
230  }
231  if (sigismember (&current->pendingSignals, i->signal) == 1)
232  {
233  NS_LOG_DEBUG ("deliver signal=" << i->signal);
234  // the signal is pending so, we try to deliver it.
235  if (i->flags & SA_SIGINFO)
236  {
237  siginfo_t info;
238  ucontext_t ctx;
239  i->sigaction (i->signal, &info, &ctx);
240  }
241  else
242  {
243  i->handler (i->signal);
244  }
245  sigdelset (&current->pendingSignals, i->signal);
246  }
247  if (sigismember (&current->process->pendingSignals, i->signal) == 1)
248  {
249  NS_LOG_DEBUG ("deliver signal=" << i->signal);
250  // the signal is pending so, we try to deliver it.
251  if (i->flags & SA_SIGINFO)
252  {
253  siginfo_t info;
254  ucontext_t ctx;
255  i->sigaction (i->signal, &info, &ctx);
256  }
257  else
258  {
259  i->handler (i->signal);
260  }
261  sigdelset (&current->process->pendingSignals, i->signal);
262  }
263  }
264 }
265 int UtilsAllocateFd (void)
266 {
267  Thread *current = Current ();
268  NS_LOG_FUNCTION (current);
269  NS_ASSERT (current != 0);
270  std::map<int,FileUsage *>::iterator end = current->process->openFiles.end ();
271  std::map<int,FileUsage *>::iterator it = end;
272 
273  for (int fd = 0; fd < MAX_FDS; fd++)
274  {
275  it = current->process->openFiles.find (fd);
276  if (it == end)
277  {
278  NS_LOG_DEBUG ("Allocated fd=" << fd);
279  return fd;
280  }
281  }
282  return -1;
283 }
284 // Little hack to advance time when detecting a possible infinite loop.
285 void UtilsAdvanceTime (Thread *current)
286 {
287  Time now = Now ();
288 
289  if (now == current->lastTime)
290  {
291 // NS_LOG_DEBUG ("UtilsAdvanceTime current thread wait 1ms.");
292  //current->process->manager->Wait (Time (MilliSeconds (1)));
293  NS_LOG_DEBUG ("UtilsAdvanceTime current thread wait 1µs.");
294  current->process->manager->Wait (Time (MicroSeconds (1)));
295  }
296 
297  current->lastTime = Now ();
298 }
299 
300 std::string
302 {
303  Time now = Now ();
304  time_t realnow = time (0);
305  std::ostringstream oss;
306  oss << ((long)now.GetSeconds ());
307  std::string sec = oss.str ();
308  uint32_t indent = 10;
309  std::string padding = "";
310  if (sec.length () < indent)
311  {
312  padding = std::string (indent - sec.length (), ' ');
313  }
314  sec = padding + sec;
315  padding = "";
316  oss.str ("");
317  oss.clear ();
318  oss << now;
319  indent = 25;
320  std::string ns = oss.str ();
321  if (ns.length () < indent)
322  {
323  padding = std::string (indent - ns.length (), ' ');
324  }
325  ns = padding + ns;
326  padding = "";
327  oss.str ("");
328  oss.clear ();
329  oss << "NS3 Time: " << sec << "s (" << ns << ") , REAL Time: " << realnow;
330  return oss.str ();
331 }
332 
333 std::list<std::string>
334 Split (std::string input, std::string sep)
335 {
336  std::list<std::string> retval;
337  std::string::size_type cur = 0, next;
338  while (true)
339  {
340  next = input.find (sep, cur);
341  if (next == cur)
342  {
343  cur++;
344  continue;
345  }
346  else if (next == std::string::npos)
347  {
348  if (input.size () != cur)
349  {
350  retval.push_back (input.substr (cur, input.size () - cur));
351  }
352  break;
353  }
354  retval.push_back (input.substr (cur, next - cur));
355  cur = next + 1;
356  }
357  return retval;
358 }
359 
360 std::string
361 FindExecFile (std::string root, std::string envPath, std::string fileName, uid_t uid, gid_t gid, int *errNo)
362 {
363  struct stat st;
364  std::string found = "";
365  *errNo = ENOENT;
366 
367  int idx = fileName.find ('/', 0);
368 
369  if (idx >= 0) // fileName contain a '/'
370  {
371  std::string vFile = UtilsGetRealFilePath (fileName);
372  if (0 == ::stat (vFile.c_str (), &st))
373  {
374  if (((uid) && CheckExeMode (&st, uid, gid)) || (!uid))
375  {
376  return vFile;
377  }
378  }
379  if (0 == ::stat (fileName.c_str (), &st))
380  {
381  if (((uid) && CheckExeMode (&st, uid, gid)) || (!uid))
382  {
383  return fileName;
384  }
385  }
386  }
387  else
388  {
389  std::list<std::string> paths = Split (envPath, ":");
390  for (std::list<std::string>::const_iterator i = paths.begin (); i != paths.end (); i++)
391  {
392  std::string test = root + "/" + *i + "/" + fileName;
393  if (0 == ::stat (test.c_str (), &st))
394  {
395  if (((uid) && CheckExeMode (&st, uid, gid)) || (!uid))
396  {
397  found = test;
398  break;
399  }
400  else
401  {
402  *errNo = EACCES;
403  }
404  }
405  }
406  }
407  return found;
408 }
409 
410 bool
411 CheckExeMode (struct stat *st, uid_t uid, gid_t gid)
412 {
413  return ((gid != st->st_gid) && (uid != st->st_uid) && ((st->st_mode & (S_IROTH | S_IXOTH)) == (S_IROTH | S_IXOTH)))
414  || ((gid == st->st_gid) && (uid != st->st_uid) && ((st->st_mode & (S_IRGRP | S_IXGRP)) == (S_IRGRP | S_IXGRP)))
415  || ((uid == st->st_uid) && ((st->st_mode & (S_IRUSR | S_IXUSR)) == (S_IRUSR | S_IXUSR)));
416 }
417 void
418 FdDecUsage (int fd)
419 {
420  Thread *current = Current ();
421 
422  FileUsage *fu = current->process->openFiles[fd];
423 
424  if (fu && fu->DecUsage ())
425  {
426  current->process->openFiles.erase (fd);
427  delete fu;
428  fu = 0;
429  }
430 }
431 bool
432 CheckFdExists (Process* const p, int const fd, bool const opened)
433 {
434  std::map<int,FileUsage *>::iterator it = p->openFiles.find (fd);
435 
436  if (it != p->openFiles.end ())
437  {
438  return !opened || (!(*it).second->IsClosed ());
439  }
440 
441  return false;
442 }
443 int getRealFd (int fd, Thread *current)
444 {
445  std::map<int,FileUsage *>::iterator it = current->process->openFiles.find (fd);
446  if (current->process->openFiles.end () == it)
447  {
448  return -1;
449  }
450  FileUsage *fu = it->second;
451  if (fu->IsClosed ())
452  {
453  return -1;
454  }
455  return fu->GetFile ()->GetRealFd ();
456 }
457 std::string PathOfFd (int fd)
458 {
459  char proc[50];
460  char direc[PATH_MAX + 1];
461 
462  sprintf (proc, "/proc/self/fd/%d", fd);
463 
464  memset (direc, 0, PATH_MAX + 1);
465 
466  ssize_t r = readlink (proc, direc, sizeof(direc) - 1);
467 
468  if (r >= 0)
469  {
470  return std::string (direc);
471  }
472  return std::string ("");
473 }
474 bool
475 CheckShellScript (std::string fileName,
476  std::ostringstream &shellName, std::ostringstream &optionalArg)
477 {
478  int fd = open (fileName.c_str (), O_RDONLY);
479 
480  if (fd < 0)
481  {
482  return false;
483  }
484  //A maximum line length of 127 characters is allowed for the first line in a #! executable shell script.
485  char firstLine[128];
486  ssize_t lg = read (fd, firstLine, 127);
487  close (fd);
488  if ((lg <= 2) || ('#' != firstLine [0]) || ('!' != firstLine [1]))
489  {
490  return false;
491  }
492  ssize_t crsr = 2;
493  firstLine [lg] = 0;
494  while (' ' == firstLine [crsr])
495  {
496  crsr++;
497  if (crsr >= lg)
498  {
499  return false;
500  }
501  }
502  ssize_t startShellName = crsr;
503  crsr++;
504  while (firstLine [crsr] && (' ' != firstLine [crsr]) && ('\n' != firstLine [crsr]))
505  {
506  crsr++;
507  if (crsr >= lg)
508  {
509  break;
510  }
511  }
512  ssize_t endShellName = crsr;
513  ssize_t lShellName = endShellName - startShellName;
514  if (lShellName <= 0)
515  {
516  return false;
517  }
518  shellName << std::string (firstLine + startShellName, lShellName);
519  if (crsr >= lg)
520  {
521  return true;
522  }
523  ssize_t startOpt = crsr;
524  while (firstLine[crsr]&&('\n' != firstLine [crsr]))
525  {
526  crsr++;
527  if (crsr >= lg)
528  {
529  break;
530  }
531  }
532  ssize_t lOpt = crsr - startOpt;
533  if (lOpt <= 0)
534  {
535  return true;
536  }
537  optionalArg << std::string (firstLine + startOpt, lOpt);
538 
539  return true;
540 }
541 char * seek_env (const char *name, char **array)
542 {
543  int namelen = strlen (name);
544  char **cur;
545  for (cur = array; cur != 0 && *cur != 0; cur++)
546  {
547  char *equal = strchr (*cur, '=');
548  if (equal == 0)
549  {
550  continue;
551  }
552  if (strncmp (*cur, name, namelen) != 0)
553  {
554  continue;
555  }
556  return equal + 1;
557  }
558  return 0;
559 }
560 std::string UtilsGetCurrentDirName (void)
561 {
562  // DCE and NS3 never change the cwd.
563  static std::string pwd = "";
564  if (pwd.length () > 0)
565  {
566  return pwd;
567  }
568  char *thePwd = get_current_dir_name ();
569  int fd = open (thePwd, O_RDONLY);
570  pwd = PathOfFd (fd);
571  close (fd);
572  free (thePwd);
573  return pwd;
574 }
575 } // namespace ns3