a packet socket
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Wed, 01 Aug 2007 09:02:03 +0200
changeset 1188 34386185bc1f
parent 1187 8ea0f4d4fd34
child 1189 b4925f17391d
a packet socket
src/node/packet-socket-address.cc
src/node/packet-socket-address.h
src/node/packet-socket-factory.cc
src/node/packet-socket-factory.h
src/node/packet-socket.cc
src/node/packet-socket.h
src/node/wscript
--- a/src/node/packet-socket-address.cc	Wed Aug 01 09:01:54 2007 +0200
+++ b/src/node/packet-socket-address.cc	Wed Aug 01 09:02:03 2007 +0200
@@ -35,6 +35,18 @@
   m_device = index;
 }
 void 
+PacketSocketAddress::SetDevice (Ptr<NetDevice> device)
+{
+  if (device == 0)
+    {
+      m_device = 0;
+    }
+  else
+    {
+      m_device = device->GetIfIndex ();
+    }
+}
+void 
 PacketSocketAddress::SetPhysicalAddress (const Address address)
 {
   m_address = address;
--- a/src/node/packet-socket-address.h	Wed Aug 01 09:01:54 2007 +0200
+++ b/src/node/packet-socket-address.h	Wed Aug 01 09:02:03 2007 +0200
@@ -20,9 +20,11 @@
 #ifndef PACKET_SOCKET_ADDRESS_H
 #define PACKET_SOCKET_ADDRESS_H
 
+#include "ns3/ptr.h"
 #include "address.h"
 #include "eui48-address.h"
 #include "eui64-address.h"
+#include "net-device.h"
 
 namespace ns3 {
 
@@ -33,7 +35,14 @@
  public:
   PacketSocketAddress ();
   void SetProtocol (uint16_t protocol);
+  /**
+   * \param index of NetDevice.
+   *
+   * index zero is reserved to identify _all_
+   * Netdevices.
+   */
   void SetDevice (uint32_t index);
+  void SetDevice (Ptr<NetDevice> device);
   void SetPhysicalAddress (const Address address);
 
   uint16_t GetProtocol (void) const;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.cc	Wed Aug 01 09:02:03 2007 +0200
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#include "packet-socket-factory.h"
+#include "node.h"
+
+namespace ns3 {
+
+const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet", 
+                                                              SocketFactory::iid);
+
+PacketSocketFactory::PacketSocketFactory ()
+{
+  SetInterfaceId (PacketSocketFactory::iid);
+}
+
+Ptr<Socket> PacketSocketFactory::CreateSocket (void)
+{
+  Ptr<Node> node = QueryInterface<Node> (Node::iid);
+  Ptr<PacketSocket> socket = Create<PacketSocket> (node);
+  return socket;
+} 
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.h	Wed Aug 01 09:02:03 2007 +0200
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#ifndef PACKET_SOCKET_FACTORY_H
+#define PACKET_SOCKET_FACTORY_H
+
+#include "socket-factory.h"
+#include "packet-socket.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate PacketSockets that can connect to net devices.
+ */
+class PacketSocketFactory : public SocketFactory
+{
+public:
+  static const InterfaceId iid; /// Interface identifier
+
+  PacketSocketFactory ();
+
+  /**
+   * Creates a PacketSocket and returns a pointer to it.
+   *
+   * \return a pointer to the created socket
+   */
+  virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.cc	Wed Aug 01 09:02:03 2007 +0200
@@ -0,0 +1,332 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-socket.h"
+#include "packet-socket-address.h"
+#include "ns3/debug.h"
+#include "ns3/node.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("PacketSocket");
+
+namespace ns3 {
+
+PacketSocket::PacketSocket (Ptr<Node> node)
+  : m_node (node)
+{
+  Init();
+}
+
+void 
+PacketSocket::Init()
+{
+  m_state = STATE_OPEN;
+  m_shutdownSend = false;
+  m_shutdownRecv = false;
+  m_errno = ERROR_NOTERROR;
+}
+
+PacketSocket::~PacketSocket ()
+{}
+
+void 
+PacketSocket::DoDispose (void)
+{
+  m_device = 0;
+}
+
+Ptr<Node>
+PacketSocket::GetNode (void) const
+{
+  return m_node;
+}
+
+
+int
+PacketSocket::Bind (void)
+{
+  PacketSocketAddress address;
+  address.SetProtocol (0);
+  address.SetDevice (0);
+  return DoBind (address);
+}
+int
+PacketSocket::Bind (const Address &address)
+{
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
+  return DoBind (ad);
+}
+
+int
+PacketSocket::DoBind (const PacketSocketAddress &address)
+{
+  if (m_state == STATE_BOUND ||
+      m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  Ptr<NetDevice> dev = m_node->GetDevice (address.GetDevice ());
+  m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
+                                   address.GetProtocol (), dev);
+  m_state = STATE_BOUND;
+  m_protocol = address.GetProtocol ();
+  m_device = address.GetDevice ();
+  return 0;
+}
+
+enum Socket::SocketErrno
+PacketSocket::GetErrno (void) const
+{
+  return m_errno;
+}
+int
+PacketSocket::ShutdownSend (void)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownSend = true;
+  return 0;
+}
+int
+PacketSocket::ShutdownRecv (void)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownRecv = false;
+  return 0;
+}
+int
+PacketSocket::DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  if (!closeCompleted.IsNull ())
+    {
+      closeCompleted (this);
+    }
+  m_state = STATE_CLOSED;
+  return 0;
+}
+
+int
+PacketSocket::DoConnect(const Address &ad,
+                        ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
+                        ns3::Callback<void, Ptr<Socket> > connectionFailed,
+                        ns3::Callback<void, Ptr<Socket> > halfClose)
+{
+  PacketSocketAddress address;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      goto error;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // connect should happen _after_ bind.
+      m_errno = ERROR_INVAL; // generic error condition.
+      goto error;
+    }
+  if (m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_ISCONN;
+      goto error;
+    }
+  if (!PacketSocketAddress::IsMatchingType (ad))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      goto error;
+    }
+  m_destAddr = ad;
+  m_state = STATE_CONNECTED;
+  if (!connectionSucceeded.IsNull ())
+    {
+      connectionSucceeded (this);
+    }
+  return 0;
+ error:
+  if (!connectionFailed.IsNull ())
+    {
+      connectionFailed (this);
+    }
+  return -1;
+}
+
+int
+PacketSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+                       ns3::Callback<void, Ptr<Socket>, const Address &> newConnectionCreated,
+                       ns3::Callback<void, Ptr<Socket> > closeRequested)
+{
+  // calling accept on a packet socket is a programming error.
+  m_errno = ERROR_OPNOTSUPP;
+  return -1;
+}
+
+int
+PacketSocket::DoSend (const uint8_t* buffer,
+                      uint32_t size,
+                      ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+  if (m_state == STATE_OPEN ||
+      m_state == STATE_BOUND)
+    {
+      m_errno = ERROR_NOTCONN;
+      return -1;
+    }
+  return DoSendTo (m_destAddr, buffer, size, dataSent);
+}
+
+int
+PacketSocket::DoSendTo(const Address &address,
+                       const uint8_t *buffer,
+                       uint32_t size,
+                       Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+  PacketSocketAddress ad;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // XXX should return another error here.
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_shutdownSend)
+    {
+      m_errno = ERROR_SHUTDOWN;
+      return -1;
+    }
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      return -1;
+    }
+  ad = PacketSocketAddress::ConvertFrom (address);
+
+  Packet p;
+  if (buffer == 0)
+    {
+      p = Packet (size);
+    }
+  else
+    {
+      p = Packet (buffer, size);
+    }
+  
+  bool error = false;
+  Address dest = ad.GetPhysicalAddress ();
+  if (ad.GetDevice () == 0)
+    {
+      for (uint32_t i = 1; i <= m_node->GetNDevices (); i++)
+        {
+          Ptr<NetDevice> device = m_node->GetDevice (i);
+          if (!device->Send (p, dest, ad.GetProtocol ()))
+            {
+              error = true;
+            }
+        }
+    }
+  else
+    {
+      Ptr<NetDevice> device = m_node->GetDevice (ad.GetDevice ());
+      if (!device->Send (p, dest, ad.GetProtocol ()))
+        {
+          error = true;
+        }
+    }
+  if (!error && !dataSent.IsNull ())
+    {
+      dataSent (this, p.GetSize ());
+    }
+
+  if (error)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+void 
+PacketSocket::DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Address &> callback)
+{
+  m_rxCallback = callback;
+}
+
+void 
+PacketSocket::DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t, const Address &> callback)
+{
+  m_dummyRxCallback = callback;
+}
+
+void 
+PacketSocket::ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                         uint16_t protocol, const Address &from)
+{
+  if (m_shutdownRecv)
+    {
+      return;
+    }
+
+  Packet p = packet;
+
+  PacketSocketAddress address;
+  address.SetPhysicalAddress (from);
+  address.SetDevice (device->GetIfIndex ());
+  address.SetProtocol (protocol);
+
+  NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid()
+            << " PacketSocket " << this);
+  if (!m_dummyRxCallback.IsNull ())
+    {
+      m_dummyRxCallback (this, p.GetSize (), address.ConvertTo ());
+    }
+  if (!m_rxCallback.IsNull ())
+    {
+      m_rxCallback (this, p.PeekData (), p.GetSize (), address.ConvertTo ());
+    }
+}
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.h	Wed Aug 01 09:02:03 2007 +0200
@@ -0,0 +1,132 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>,
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_H
+#define PACKET_SOCKET_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/socket.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetDevice;
+class PacketSocketAddress;
+
+/**
+ * \brief A PacketSocket is a link between an application and a net device.
+ *
+ * A PacketSocket can be used to connect an application to a net
+ * device. The application provides the buffers of data, the socket
+ * conserts them to a raw packet and the net device then adds the
+ * protocol specific headers and trailers. This socket type
+ * is very similar to the linux and BSD "packet" sockets.
+ *
+ * Here is a summary of the semantics of this class:
+ * - Bind: Bind uses only the protocol and device fields of the 
+ *       PacketSocketAddress. If none are provided, Bind uses 
+ *       zero for both, which means that the socket is bound
+ *       to all protocols on all devices on the node.
+ *
+ * - Connect: uses only the protocol, device and "physical address" 
+ *       field of the PacketSocketAddress. It is used to set the default
+ *       destination address for outgoing packets.
+ *
+ * - Send: send the input packet to the underlying NetDevices
+ *       with the default destination address. The socket must
+ *       be bound and connected.
+ *
+ * - SendTo: uses the protocol, device, and "physical address" 
+ *       fields of the PacketSocketAddress. The device value is 
+ *       used to specialize the packet transmission to a single 
+ *       device, the protocol value specifies the protocol of this
+ *       packet only and the "physical address" field is used to override the 
+ *       default destination address. The socket must be bound.
+ *
+ * - Recv: The address represents the address of the packer originator.
+ *       The fields "physical address", device, and protocol are filled.
+ *
+ * - Accept: not allowed
+ */
+class PacketSocket : public Socket
+{
+public:
+  PacketSocket (Ptr<Node> node);
+  virtual ~PacketSocket ();
+
+  virtual enum SocketErrno GetErrno (void) const;
+  virtual Ptr<Node> GetNode (void) const;
+  virtual int Bind (void);
+  virtual int Bind (const Address & address);
+  virtual int ShutdownSend (void);
+  virtual int ShutdownRecv (void);
+
+private:
+  virtual int DoClose(Callback<void, Ptr<Socket> > closeCompleted);
+  virtual int DoConnect(const Address & address,
+                        Callback<void, Ptr<Socket> > connectionSucceeded,
+                        Callback<void, Ptr<Socket> > connectionFailed,
+                        Callback<void, Ptr<Socket> > halfClose);
+  virtual int DoAccept(Callback<bool, Ptr<Socket>, const Address&> connectionRequest,
+                       Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+                       Callback<void, Ptr<Socket> > closeRequested);
+  virtual int DoSend (const uint8_t* buffer,
+                      uint32_t size,
+                      Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  virtual int DoSendTo(const Address &address,
+                       const uint8_t *buffer,
+                       uint32_t size,
+                       Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  virtual void DoRecv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Address&> receive);
+  virtual void DoRecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Address&>);
+
+private:
+  void Init (void);
+  void ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                  uint16_t protocol, const Address &from);
+  int DoBind (const PacketSocketAddress &address);
+  virtual void DoDispose (void);
+
+  enum State {
+    STATE_OPEN,
+    STATE_BOUND,     // open and bound
+    STATE_CONNECTED, // open, bound and connected
+    STATE_CLOSED
+  };
+  Ptr<Node> m_node;
+  Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
+  Callback<void,Ptr<Socket>,uint8_t const*,uint32_t, const Address &> m_rxCallback;
+  enum SocketErrno m_errno;
+  bool m_shutdownSend;
+  bool m_shutdownRecv;
+  enum State m_state;
+  uint16_t m_protocol;
+  uint32_t m_device;
+  Address m_destAddr; /// Default destination address
+};
+
+}//namespace ns3
+
+#endif /* PACKET_SOCKET_H */
+
+
--- a/src/node/wscript	Wed Aug 01 09:01:54 2007 +0200
+++ b/src/node/wscript	Wed Aug 01 09:02:03 2007 +0200
@@ -8,7 +8,9 @@
     node.source = [
         'address.cc',
         'eui48-address.cc',
+        'eui64-address.cc',
         'inet-socket-address.cc',
+        'packet-socket-address.cc',
         'node.cc',
         'ipv4-address.cc',
         'net-device.cc',
@@ -23,6 +25,8 @@
         'node-list.cc',
         'socket.cc',
         'socket-factory.cc',
+        'packet-socket-factory.cc',
+        'packet-socket.cc',
         'udp.cc',
         'ipv4.cc',
         'application.cc',
@@ -32,7 +36,9 @@
     headers.source = [
         'address.h',
         'eui48-address.h',
+        'eui64-address.h',
         'inet-socket-address.h',
+        'packet-socket-address.h',
         'node.h',
         'ipv4-address.h',
         'net-device.h',
@@ -47,6 +53,7 @@
         'node-list.h',
         'socket.h',
         'socket-factory.h',
+        'packet-socket-factory.h',
         'udp.h',
         'ipv4.h',
         'application.h',