View | Details | Raw Unified | Return to bug 903
Collapse All | Expand All

(-)277546e1dc88 (+216 lines)
Added Link Here 
1
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/*
4
 * Copyright (c) 2010 The Boeing Company
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation;
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 * Author: Tom Goff <thomas.goff@boeing.com>
20
 */
21
22
#include <errno.h>
23
#include <string.h>
24
#include <unistd.h>
25
#include <fcntl.h>
26
27
#include "ns3/log.h"
28
#include "ns3/fatal-error.h"
29
#include "ns3/simple-ref-count.h"
30
#include "ns3/system-thread.h"
31
#include "ns3/simulator.h"
32
33
#include "unix-fd-reader.h"
34
35
NS_LOG_COMPONENT_DEFINE ("FdReader");
36
37
namespace ns3 {
38
39
FdReader::FdReader ()
40
  : m_fd (-1), m_readCallback (0), m_readThread (0), m_stop (false),
41
    m_destroyEvent ()
42
{
43
  m_evpipe[0] = -1;
44
  m_evpipe[1] = -1;
45
}
46
47
FdReader::~FdReader ()
48
{
49
  Stop ();
50
}
51
52
void FdReader::Start (int fd, Callback<void, uint8_t *, ssize_t> readCallback)
53
{
54
  int tmp;
55
56
  NS_ASSERT_MSG (m_readThread == 0, "read thread already exists");
57
58
  // create a pipe for inter-thread event notification
59
  tmp = pipe (m_evpipe);
60
  if (tmp == -1)
61
    {
62
      NS_FATAL_ERROR ("pipe() failed: " << strerror (errno));
63
    }
64
65
  // make the read end non-blocking
66
  tmp = fcntl(m_evpipe[0], F_GETFL);
67
  if (tmp == -1)
68
    {
69
      NS_FATAL_ERROR ("fcntl() failed: " << strerror (errno));
70
    }
71
  if (fcntl(m_evpipe[0], F_SETFL, tmp | O_NONBLOCK) == -1)
72
    {
73
      NS_FATAL_ERROR ("fcntl() failed: " << strerror (errno));
74
    }
75
76
  m_fd = fd;
77
  m_readCallback = readCallback;
78
79
  //
80
  // We're going to spin up a thread soon, so we need to make sure we have
81
  // a way to tear down that thread when the simulation stops.  Do this by
82
  // scheduling a "destroy time" method to make sure the thread exits before
83
  // proceeding.
84
  //
85
  if (! m_destroyEvent.IsRunning ())
86
    {
87
      // hold a reference to ensure that this object is not
88
      // deallocated before the destroy-time event fires
89
      this->Ref ();
90
      m_destroyEvent =
91
        Simulator::ScheduleDestroy (&FdReader::DestroyEvent, this);
92
    }
93
94
  //
95
  // Now spin up a thread to read from the fd
96
  //
97
  NS_LOG_LOGIC ("Spinning up read thread");
98
99
  m_readThread = Create<SystemThread> (MakeCallback (&FdReader::Run, this));
100
  m_readThread->Start ();
101
}
102
103
void FdReader::DestroyEvent (void)
104
{
105
  Stop ();
106
  this->Unref ();
107
}
108
109
void FdReader::Stop (void)
110
{
111
  m_stop = true;
112
113
  // signal the read thread and close the write end of the event pipe
114
  if (m_evpipe[1] != -1)
115
    {
116
      char zero = 0;
117
      ssize_t len = write (m_evpipe[1], &zero, sizeof (zero));
118
      if (len != sizeof (zero))
119
        NS_LOG_WARN ("incomplete write(): " << strerror (errno));
120
      close (m_evpipe[1]);
121
      m_evpipe[1] = -1;
122
    }
123
124
  // join the read thread
125
  if (m_readThread != 0)
126
    {
127
      m_readThread->Join ();
128
      m_readThread = 0;
129
    }
130
131
  // close the read end of the event pipe
132
  if (m_evpipe[0] != -1)
133
    {
134
      close (m_evpipe[0]);
135
      m_evpipe[0] = -1;
136
    }
137
138
  // reset everything else
139
  m_fd = -1;
140
  m_readCallback.Nullify ();
141
  m_stop = false;
142
}
143
144
// This runs in a separate thread
145
void FdReader::Run (void)
146
{
147
  int nfds;
148
  fd_set rfds;
149
150
  nfds = (m_fd > m_evpipe[0] ? m_fd : m_evpipe[0]) + 1;
151
152
  FD_ZERO (&rfds);
153
  FD_SET (m_fd, &rfds);
154
  FD_SET (m_evpipe[0], &rfds);
155
156
  for (;;)
157
    {
158
      int r;
159
      fd_set readfds = rfds;
160
161
      r = select (nfds, &readfds, NULL, NULL, NULL);
162
      if (r == -1 && errno != EINTR)
163
        {
164
          NS_FATAL_ERROR ("select() failed: " << strerror (errno));
165
	}
166
167
      if (FD_ISSET (m_evpipe[0], &readfds))
168
        {
169
          // drain the event pipe
170
          ssize_t len;
171
          for (;;)
172
            {
173
              char buf[1024];
174
              len = read (m_evpipe[0], buf, sizeof (buf));
175
              if (len == 0)
176
                {
177
                  NS_FATAL_ERROR ("event pipe closed");
178
                }
179
              if (len < 0)
180
                {
181
                  break;
182
                }
183
            }
184
185
          if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
186
            {
187
              NS_LOG_WARN ("read() failed: " << strerror (errno));
188
              break;
189
            }
190
	}
191
192
      if (m_stop)
193
        {
194
          // this thread is done
195
          break;
196
        }
197
198
      if (FD_ISSET (m_fd, &readfds))
199
        {
200
          struct FdReader::Data data = DoRead ();
201
          // reading stops when m_len is zero
202
          if (data.m_len == 0)
203
            {
204
              break;
205
            }
206
          // the callback is only called when m_len is positive (data
207
          // is ignored if m_len is negative)
208
          else if (data.m_len > 0)
209
            {
210
              m_readCallback (data.m_buf, data.m_len);
211
            }
212
        }
213
    }
214
}
215
216
} // namespace ns3
(-)277546e1dc88 (+113 lines)
Added Link Here 
1
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/*
4
 * Copyright (c) 2010 The Boeing Company
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation;
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 * Author: Tom Goff <thomas.goff@boeing.com>
20
 */
21
22
#ifndef UNIX_FD_READER_H
23
#define UNIX_FD_READER_H
24
25
#include <stdint.h>
26
27
#include "ns3/callback.h"
28
#include "ns3/system-thread.h"
29
#include "ns3/event-id.h"
30
31
namespace ns3 {
32
33
/**
34
 * \brief A class that asynchronously reads from a file descriptor.
35
 *
36
 * This class can be used to start a system thread that reads from a
37
 * given file descriptor and invokes a given callback when data is
38
 * received.  This class handles thread management automatically but
39
 * the \p DoRead() method must be implemented by a subclass.
40
 */
41
class FdReader : public SimpleRefCount<FdReader>
42
{
43
public:
44
  FdReader();
45
  ~FdReader();
46
47
  /**
48
   * Start a new read thread.
49
   *
50
   * \param fd A valid file descriptor open for reading.
51
   *
52
   * \param readCallback A callback to invoke when new data is
53
   * available.
54
   */
55
  void Start (int fd, Callback<void, uint8_t *, ssize_t> readCallback);
56
57
  /**
58
   * Stop the read thread and reset internal state.  This does not
59
   * close the file descriptor used for reading.
60
   */
61
  void Stop (void);
62
63
protected:
64
65
  /**
66
   * \internal
67
   * \brief A structure representing data read.
68
   */
69
  struct Data
70
  {
71
    Data () : m_buf (0), m_len (0) {}
72
    Data (uint8_t *buf, ssize_t len) : m_buf (buf), m_len (len) {}
73
    uint8_t *m_buf;
74
    ssize_t m_len;
75
  };
76
77
  /**
78
   * \internal
79
   * \brief The read implementation.
80
   *
81
   * The value of \p m_len returned controls further processing.  The
82
   * callback function is only invoked when \p m_len is positive; any
83
   * data read is not processed when \p m_len is negative; reading
84
   * stops when \p m_len is zero.
85
   *
86
   * The management of memory associated with \p m_buf must be
87
   * compatible with the read callback.
88
   *
89
   * \return A structure representing what was read.
90
   */
91
  virtual FdReader::Data DoRead (void) = 0;
92
93
  /**
94
   * \internal
95
   * \brief The file descriptor to read from.
96
   */
97
  int m_fd;
98
99
private:
100
101
  void Run (void);
102
  void DestroyEvent (void);
103
104
  Callback<void, uint8_t *, ssize_t> m_readCallback;
105
  Ptr<SystemThread> m_readThread;
106
  int m_evpipe[2];           // pipe used to signal events between threads
107
  bool m_stop;               // true means the read thread should stop
108
  EventId m_destroyEvent;
109
};
110
111
} // namespace ns3
112
113
#endif	// UNIX_FD_READER_H
(-)a/src/core/wscript (+2 lines)
 Lines 146-157    Link Here 
146
            'unix-system-thread.cc',
146
            'unix-system-thread.cc',
147
            'unix-system-mutex.cc',
147
            'unix-system-mutex.cc',
148
            'unix-system-condition.cc',
148
            'unix-system-condition.cc',
149
            'unix-fd-reader.cc',
149
            ])
150
            ])
150
        core.uselib = 'PTHREAD'
151
        core.uselib = 'PTHREAD'
151
        headers.source.extend([
152
        headers.source.extend([
152
                'system-mutex.h',
153
                'system-mutex.h',
153
                'system-thread.h',
154
                'system-thread.h',
154
                'system-condition.h',
155
                'system-condition.h',
156
                'unix-fd-reader.h',
155
                ])
157
                ])
156
158
157
    if bld.env['ENABLE_GSL']:
159
    if bld.env['ENABLE_GSL']:
(-)a/src/devices/tap-bridge/tap-bridge.cc (-42 / +52 lines)
 Lines 32-38    Link Here 
32
#include "ns3/ipv4.h"
32
#include "ns3/ipv4.h"
33
#include "ns3/simulator.h"
33
#include "ns3/simulator.h"
34
#include "ns3/realtime-simulator-impl.h"
34
#include "ns3/realtime-simulator-impl.h"
35
#include "ns3/system-thread.h"
35
#include "ns3/unix-fd-reader.h"
36
#include "ns3/uinteger.h"
36
#include "ns3/uinteger.h"
37
37
38
#include <sys/wait.h>
38
#include <sys/wait.h>
 Lines 65-70    Link Here 
65
65
66
namespace ns3 {
66
namespace ns3 {
67
67
68
FdReader::Data TapBridgeFdReader::DoRead (void)
69
{
70
  NS_LOG_FUNCTION_NOARGS ();
71
72
  uint32_t bufferSize = 65536;
73
  uint8_t *buf = (uint8_t *)malloc (bufferSize);
74
  NS_ABORT_MSG_IF (buf == 0, "malloc() failed");
75
76
  NS_LOG_LOGIC ("Calling read on tap device fd " << m_fd);
77
  ssize_t len = read (m_fd, buf, bufferSize);
78
  if (len <= 0)
79
    {
80
      NS_LOG_INFO ("TapBridgeFdReader::DoRead(): done");
81
      free (buf);
82
      buf = 0;
83
      len = 0;
84
    }
85
86
  return FdReader::Data (buf, len);
87
}
88
68
#define TAP_MAGIC 95549
89
#define TAP_MAGIC 95549
69
90
70
NS_OBJECT_ENSURE_REGISTERED (TapBridge);
91
NS_OBJECT_ENSURE_REGISTERED (TapBridge);
 Lines 135-141    Link Here 
135
  m_sock (-1),
156
  m_sock (-1),
136
  m_startEvent (),
157
  m_startEvent (),
137
  m_stopEvent (),
158
  m_stopEvent (),
138
  m_readThread (0),
159
  m_fdReader (0),
139
  m_ns3AddressRewritten (false)
160
  m_ns3AddressRewritten (false)
140
{
161
{
141
  NS_LOG_FUNCTION_NOARGS ();
162
  NS_LOG_FUNCTION_NOARGS ();
 Lines 147-152    Link Here 
147
{
168
{
148
  NS_LOG_FUNCTION_NOARGS ();
169
  NS_LOG_FUNCTION_NOARGS ();
149
170
171
  StopTapDevice ();
172
150
  delete [] m_packetBuffer;
173
  delete [] m_packetBuffer;
151
  m_packetBuffer = 0;
174
  m_packetBuffer = 0;
152
175
 Lines 235-245    Link Here 
235
  //
258
  //
236
  // Now spin up a read thread to read packets from the tap device.
259
  // Now spin up a read thread to read packets from the tap device.
237
  //
260
  //
238
  NS_ABORT_MSG_IF (m_readThread != 0,"TapBridge::StartTapDevice(): Receive thread is already running");
261
  NS_ABORT_MSG_IF (m_fdReader != 0,"TapBridge::StartTapDevice(): Receive thread is already running");
239
  NS_LOG_LOGIC ("Spinning up read thread");
262
  NS_LOG_LOGIC ("Spinning up read thread");
240
263
241
  m_readThread = Create<SystemThread> (MakeCallback (&TapBridge::ReadThread, this));
264
  m_fdReader = Create<TapBridgeFdReader> ();
242
  m_readThread->Start ();
265
  m_fdReader->Start (m_sock, MakeCallback (&TapBridge::ReadCallback, this));
243
}
266
}
244
267
245
void
268
void
 Lines 247-260    Link Here 
247
{
270
{
248
  NS_LOG_FUNCTION_NOARGS ();
271
  NS_LOG_FUNCTION_NOARGS ();
249
272
250
  close (m_sock);
273
  if (m_fdReader != 0)
251
  m_sock = -1;
274
    {
275
      m_fdReader->Stop ();
276
      m_fdReader = 0;
277
    }
252
278
253
  NS_ASSERT_MSG (m_readThread != 0, "TapBridge::StopTapDevice(): Receive thread is not running");
279
  if (m_sock != -1)
254
280
    {
255
  NS_LOG_LOGIC ("Joining read thread");
281
      close (m_sock);
256
  m_readThread->Join ();
282
      m_sock = -1;
257
  m_readThread = 0;
283
    }
258
}
284
}
259
285
260
void
286
void
 Lines 636-684    Link Here 
636
}
662
}
637
663
638
void
664
void
639
TapBridge::ReadThread (void)
665
TapBridge::ReadCallback (uint8_t *buf, ssize_t len)
640
{
666
{
641
  NS_LOG_FUNCTION_NOARGS ();
667
  NS_LOG_FUNCTION_NOARGS ();
642
668
669
  NS_ASSERT_MSG (buf != 0, "invalid buf argument");
670
  NS_ASSERT_MSG (len > 0, "invalid len argument");
671
643
  //
672
  //
644
  // It's important to remember that we're in a completely different thread 
673
  // It's important to remember that we're in a completely different thread
645
  // than the simulator is running in.  We need to synchronize with that 
674
  // than the simulator is running in.  We need to synchronize with that
646
  // other thread to get the packet up into ns-3.  What we will need to do 
675
  // other thread to get the packet up into ns-3.  What we will need to do
647
  // is to schedule a method to deal with the packet using the multithreaded
676
  // is to schedule a method to deal with the packet using the multithreaded
648
  // simulator we are most certainly running.  However, I just said it -- we
677
  // simulator we are most certainly running.  However, I just said it -- we
649
  // are talking about two threads here, so it is very, very dangerous to do
678
  // are talking about two threads here, so it is very, very dangerous to do
650
  // any kind of reference counting on a shared object.  Just don't do it.
679
  // any kind of reference counting on a shared object.  Just don't do it.
651
  // So what we're going to do is to allocate a buffer on the heap and pass
680
  // So what we're going to do is pass the buffer allocated on the heap
652
  // that buffer into the ns-3 context thread where it will create the packet.
681
  // into the ns-3 context thread where it will create the packet.
653
  //
682
  //
654
  int32_t len = -1;
655
683
656
  for (;;) 
684
  NS_LOG_INFO ("TapBridge::ReadCallback(): Received packet on node " << m_nodeId);
657
    {
685
  NS_LOG_INFO ("TapBridge::ReadCallback(): Scheduling handler");
658
      uint32_t bufferSize = 65536;
686
  NS_ASSERT_MSG (m_rtImpl, "TapBridge::ReadCallback(): Realtime simulator implementation pointer not set");
659
      uint8_t *buf = (uint8_t *)malloc (bufferSize);
687
  m_rtImpl->ScheduleRealtimeNowWithContext (m_nodeId, MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len));
660
      NS_ABORT_MSG_IF (buf == 0, "TapBridge::ReadThread(): malloc packet buffer failed");
661
      NS_LOG_LOGIC ("Calling read on tap device socket fd " << m_sock);
662
      len = read (m_sock, buf, bufferSize);
663
664
      if (len == -1)
665
        {
666
          NS_LOG_INFO ("TapBridge::ReadThread(): Returning");
667
          free (buf);
668
          buf = 0;
669
          return;
670
        }
671
672
      NS_LOG_INFO ("TapBridge::ReadThread(): Received packet on node " << m_nodeId);
673
      NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler");
674
      NS_ASSERT_MSG (m_rtImpl, "EmuNetDevice::ReadThread(): Realtime simulator implementation pointer not set");
675
      m_rtImpl->ScheduleRealtimeNowWithContext (m_nodeId, MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len));
676
      buf = 0;
677
    }
678
}
688
}
679
689
680
void
690
void
681
TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len)
691
TapBridge::ForwardToBridgedDevice (uint8_t *buf, ssize_t len)
682
{
692
{
683
  NS_LOG_FUNCTION (buf << len);
693
  NS_LOG_FUNCTION (buf << len);
684
694
(-)a/src/devices/tap-bridge/tap-bridge.h (-8 / +14 lines)
 Lines 31-41    Link Here 
31
#include "ns3/data-rate.h"
31
#include "ns3/data-rate.h"
32
#include "ns3/ptr.h"
32
#include "ns3/ptr.h"
33
#include "ns3/mac48-address.h"
33
#include "ns3/mac48-address.h"
34
#include "ns3/system-thread.h"
34
#include "ns3/unix-fd-reader.h"
35
#include "ns3/realtime-simulator-impl.h"
35
#include "ns3/realtime-simulator-impl.h"
36
36
37
namespace ns3 {
37
namespace ns3 {
38
38
39
class TapBridgeFdReader : public FdReader
40
{
41
private:
42
  FdReader::Data DoRead (void);
43
};
44
39
class Node;
45
class Node;
40
46
41
/**
47
/**
 Lines 248-256    Link Here 
248
  /**
254
  /**
249
   * \internal
255
   * \internal
250
   *
256
   *
251
   * Loop to read and process packets
257
   * Callback to process packets that are read
252
   */
258
   */
253
  void ReadThread (void);
259
  void ReadCallback (uint8_t *buf, ssize_t len);
254
260
255
  /*
261
  /*
256
   * \internal
262
   * \internal
 Lines 262-268    Link Here 
262
   *            received from the host.
268
   *            received from the host.
263
   * \param buf The length of the buffer.
269
   * \param buf The length of the buffer.
264
   */
270
   */
265
  void ForwardToBridgedDevice (uint8_t *buf, uint32_t len);
271
  void ForwardToBridgedDevice (uint8_t *buf, ssize_t len);
266
272
267
  /**
273
  /**
268
   * \internal
274
   * \internal
 Lines 336-342    Link Here 
336
   * The socket (actually interpreted as fd) to use to talk to the Tap device on
342
   * The socket (actually interpreted as fd) to use to talk to the Tap device on
337
   * the real internet host.
343
   * the real internet host.
338
   */
344
   */
339
  int32_t m_sock;
345
  int m_sock;
340
346
341
  /**
347
  /**
342
   * \internal
348
   * \internal
 Lines 357-366    Link Here 
357
  /**
363
  /**
358
   * \internal
364
   * \internal
359
   *
365
   *
360
   * Used to identify the ns-3 read thread used to do blocking reads on the 
366
   * Includes the ns-3 read thread used to do blocking reads on the fd
361
   * socket (fd) corresponding to the host device.
367
   * corresponding to the host device.
362
   */
368
   */
363
  Ptr<SystemThread> m_readThread;
369
  Ptr<TapBridgeFdReader> m_fdReader;
364
370
365
  /**
371
  /**
366
   * \internal
372
   * \internal

Return to bug 903