diff --git a/SConstruct b/SConstruct index 46006b023..5aed0cab7 100644 --- a/SConstruct +++ b/SConstruct @@ -200,7 +200,6 @@ node.add_sources ([ 'ipv4.cc', 'ipv4-end-point.cc', 'udp-end-point.cc', - 'datagram-socket.cc', 'udp.cc', 'capability.cc', 'arp-header.cc', @@ -218,13 +217,13 @@ node.add_sources ([ 'channel.cc', 'node-list.cc', 'ascii-trace.cc', + 'socket.cc', + 'udp-socket.cc', ]) node.add_headers ([ 'ipv4-header.h', 'udp-header.h', 'ipv4-checksum.h', - 'udp.h', - 'ipv4-l4-protocol.h', 'application.h', 'application-list.h', 'onoff-application.h', @@ -233,16 +232,15 @@ node.add_headers ([ 'arp.h', 'ipv4-loopback-interface.h', 'l3-demux.h', - 'ipv4-l4-demux.h', 'header-utils.h', 'protocol.h', 'queue.h', 'arp-ipv4-interface.h', + 'udp-socket.h', ]) node.add_inst_headers ([ 'node.h', 'internet-node.h', - 'datagram-socket.h', 'ipv4-address.h', 'net-device.h', 'ipv4-interface.h', @@ -263,6 +261,13 @@ node.add_inst_headers ([ 'application-list.h', 'onoff-application.h', 'ascii-trace.h', + 'socket.h', + 'udp.h', + 'ipv4-l4-protocol.h', + 'ipv4-l4-demux.h', + 'udp-end-point.h', + 'ipv4-end-point-demux.h', + 'ipv4-end-point.h', ]) p2p = build.Ns3Module ('p2p', 'src/devices/p2p') diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index 657e2a890..70858b94e 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -55,7 +55,8 @@ #include "ns3/mac-address.h" #include "ns3/ipv4-address.h" #include "ns3/ipv4.h" -#include "ns3/datagram-socket.h" +#include "ns3/udp.h" +#include "ns3/socket.h" #include "ns3/ipv4-route.h" #include "ns3/drop-tail.h" #include "ns3/node-list.h" diff --git a/samples/main-p2p-net-device-if.cc b/samples/main-p2p-net-device-if.cc index 3908a44bb..7a32c7ea2 100644 --- a/samples/main-p2p-net-device-if.cc +++ b/samples/main-p2p-net-device-if.cc @@ -27,8 +27,9 @@ #include "ns3/p2p-net-device.h" #include "ns3/drop-tail.h" #include "ns3/ipv4.h" +#include "ns3/udp.h" #include "ns3/trace-context.h" -#include "ns3/datagram-socket.h" +#include "ns3/socket.h" #include "ns3/simulator.h" #include "ns3/node-list.h" #include "ns3/trace-root.h" @@ -77,12 +78,12 @@ protected: }; static void -GenerateTraffic (DatagramSocket *socket, uint32_t size) +GenerateTraffic (Socket *socket, uint32_t size) { std::cout << "Node: " << socket->GetNode()->GetId () << " at=" << Simulator::Now ().GetSeconds () << "s," << " tx bytes=" << size << std::endl; - socket->SendDummy (size); + socket->Send (0, size); if (size > 50) { Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); @@ -90,7 +91,7 @@ GenerateTraffic (DatagramSocket *socket, uint32_t size) } static void -DatagramSocketPrinter (DatagramSocket *socket, uint32_t size, Ipv4Address from, uint16_t fromPort) +SocketPrinter (Socket *socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort) { std::cout << "Node: " << socket->GetNode()->GetId () << " at=" << Simulator::Now ().GetSeconds () << "s," @@ -98,9 +99,9 @@ DatagramSocketPrinter (DatagramSocket *socket, uint32_t size, Ipv4Address from, } static void -PrintTraffic (DatagramSocket *socket) +PrintTraffic (Socket *socket) { - socket->SetDummyRxCallback (MakeCallback (&DatagramSocketPrinter)); + socket->RecvDummy (MakeCallback (&SocketPrinter)); } @@ -200,10 +201,10 @@ int main (int argc, char *argv[]) ipb->SetDefaultRoute (Ipv4Address ("10.1.1.1"), 1); - DatagramSocket *source = new DatagramSocket (&a); - DatagramSocket *sink = new DatagramSocket(&b); + Socket *source = a.GetUdp ()->CreateSocket (); + Socket *sink = b.GetUdp ()->CreateSocket (); sink->Bind (80); - source->SetDefaultDestination (Ipv4Address ("10.1.1.2"), 80); + source->Connect (Ipv4Address ("10.1.1.2"), 80); Logger logger("p2p-net-test.log"); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index c41f26630..e28b76926 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -2,7 +2,8 @@ #include "ns3/internet-node.h" #include "ns3/simulator.h" -#include "ns3/datagram-socket.h" +#include "ns3/udp.h" +#include "ns3/socket.h" #include "ns3/nstime.h" using namespace ns3; @@ -31,10 +32,10 @@ SmallTests (void) } static void -GenerateTraffic (DatagramSocket *socket, uint32_t size) +GenerateTraffic (Socket *socket, uint32_t size) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; - socket->SendDummy (size); + socket->Send (0, size); if (size > 0) { Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); @@ -42,15 +43,15 @@ GenerateTraffic (DatagramSocket *socket, uint32_t size) } static void -DatagramSocketPrinter (DatagramSocket *socket, uint32_t size, Ipv4Address from, uint16_t fromPort) +SocketPrinter (Socket *socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl; } static void -PrintTraffic (DatagramSocket *socket) +PrintTraffic (Socket *socket) { - socket->SetDummyRxCallback (MakeCallback (&DatagramSocketPrinter)); + socket->RecvDummy (MakeCallback (&SocketPrinter)); } int main (int argc, char *argv[]) @@ -58,12 +59,12 @@ int main (int argc, char *argv[]) SmallTests (); InternetNode *a = new InternetNode (); - - DatagramSocket *sink = new DatagramSocket (a); + + Socket *sink = a->GetUdp ()->CreateSocket (); sink->Bind (80); - DatagramSocket *source = new DatagramSocket (a); - source->SetDefaultDestination (Ipv4Address::GetLoopback (), 80); + Socket *source = a->GetUdp ()->CreateSocket (); + source->Connect (Ipv4Address::GetLoopback (), 80); GenerateTraffic (source, 500); PrintTraffic (sink); diff --git a/src/node/datagram-socket.cc b/src/node/datagram-socket.cc deleted file mode 100644 index 82cfe0f76..000000000 --- a/src/node/datagram-socket.cc +++ /dev/null @@ -1,173 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * 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: Mathieu Lacage - */ -#include "datagram-socket.h" -#include "udp.h" -#include "udp-end-point.h" -#include "node.h" -#include "ipv4-l4-demux.h" - -namespace ns3 { - -DatagramSocket::DatagramSocket (Node *node) - : m_endPoint (0), - m_node (node) -{ - NS_ASSERT (GetUdp () != 0); -} -DatagramSocket::~DatagramSocket () -{ - delete m_endPoint; -} - -int -DatagramSocket::Bind (void) -{ - m_endPoint = GetUdp ()->Allocate (); - if (m_endPoint == 0) - { - return -1; - } - m_endPoint->SetSocket (this); - return 0; -} -int -DatagramSocket::Bind (Ipv4Address address) -{ - m_endPoint = GetUdp ()->Allocate (address); - if (m_endPoint == 0) - { - return -1; - } - m_endPoint->SetSocket (this); - return 0; -} -int -DatagramSocket::Bind (uint16_t port) -{ - m_endPoint = GetUdp ()->Allocate (port); - if (m_endPoint == 0) - { - return -1; - } - m_endPoint->SetSocket (this); - return 0; -} -int -DatagramSocket::Bind (Ipv4Address address, uint16_t port) -{ - m_endPoint = GetUdp ()->Allocate (address, port); - if (m_endPoint == 0) - { - return -1; - } - m_endPoint->SetSocket (this); - return 0; -} - -void -DatagramSocket::SetDefaultDestination (Ipv4Address daddr, uint16_t dport) -{ - m_defaultAddress = daddr; - m_defaultPort = dport; -} -void -DatagramSocket::SendDummy (uint32_t size) -{ - SendDummyTo (size, m_defaultAddress, m_defaultPort); -} -void -DatagramSocket::SendDummyTo (uint32_t size, Ipv4Address daddr, uint16_t dport) -{ - if (m_endPoint == 0) - { - Bind (); - if (m_endPoint == 0) - { - return; - } - } - Packet p = Packet (size); - GetUdp ()->Send (p, m_endPoint->GetLocalAddress (), daddr, - m_endPoint->GetLocalPort (), dport); -} - -void -DatagramSocket::Send (uint8_t const*buffer, uint32_t size) -{ - SendTo (buffer, size, m_defaultAddress, m_defaultPort); -} -void -DatagramSocket::SendTo (uint8_t const*buffer, uint32_t size, - Ipv4Address daddr, uint16_t dport) -{ - if (m_endPoint == 0) - { - Bind (); - if (m_endPoint == 0) - { - return; - } - } - Packet p = Packet (buffer, size); - GetUdp ()->Send (p, m_endPoint->GetLocalAddress (), daddr, - m_endPoint->GetLocalPort (), dport); -} -void -DatagramSocket::SetDummyRxCallback (Callback cb) -{ - m_dummyRxCallback = cb; -} -void -DatagramSocket::SetRxCallback (Callback cb) -{ - m_rxCallback = cb; -} - -void -DatagramSocket::ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport) -{ - if (!m_dummyRxCallback.IsNull ()) - { - m_dummyRxCallback (this, p.GetSize (), saddr, sport); - } - if (!m_rxCallback.IsNull ()) - { - m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport); - } -} - -Udp * -DatagramSocket::GetUdp (void) const -{ - return m_node->GetUdp (); -} - -Node * -DatagramSocket::GetNode (void) const -{ - return m_node; -} - -}//namespace ns3 diff --git a/src/node/datagram-socket.h b/src/node/datagram-socket.h deleted file mode 100644 index c686b6972..000000000 --- a/src/node/datagram-socket.h +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * 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: Mathieu Lacage - */ -#ifndef UDP_SOCKET_H -#define UDP_SOCKET_H - -#include -#include "ns3/callback.h" -#include "ipv4-address.h" - -namespace ns3 { - -class UdpEndPoint; -class Node; -class Packet; -class Udp; - -/** - * Before any data is sent, the socket must be bound with - * one of the Bind methods. - * If none of these Bind methods are called prior to - * one of the ::Send methods, the socket is implicitely - * bound to a random port and to all interfaces. - */ -class DatagramSocket -{ -public: - /** - * Create an unbound udp socket. - */ - DatagramSocket (Node *node); - ~DatagramSocket (); - - /** - * Allocate a free port number and - * bind this socket to this port number on all - * interfaces of this system. - * - * \returns 0 on success, -1 on failure. - */ - int Bind (void); - /** - * Allocate a free port number and - * bind this socket to this port number on the - * specified interface. - * - * \param address address of interface to bind to. - * \returns 0 on success, -1 on failure. - */ - int Bind (Ipv4Address address); - - /** - * Bind this socket to this port number - * on all interfaces of this system. - * - * \param port port to bind to on all interfaces - * \returns 0 on success, -1 on failure. - */ - int Bind (uint16_t port); - - /** - * Bind this socket to this port number - * on the interface specified by address. - * - * \param address address of interface to bind to. - * \param port port to bind to on specified interface - * \returns 0 on success, -1 on failure. - */ - int Bind (Ipv4Address address, uint16_t port); - - - /** - * \param daddr destination address - * \param dport destination port - * - * Set the default destination address and port - * number for all packets outgoing from this socket. - */ - void SetDefaultDestination (Ipv4Address daddr, uint16_t dport); - - /** - * \param size size of dummy data to send. - * - * Send dummy data to default destination - */ - void SendDummy (uint32_t size); - /** - * \param size size of dummy data to send - * \param daddr destination address of dummy data - * \param dport destination port of dummy data - * - * Send dummy data to specified destination, ignore any default - * destination specified with DatagramSocket::SetDefaultDestination - */ - void SendDummyTo (uint32_t size, Ipv4Address daddr, uint16_t dport); - - /** - * \param buffer data buffer to send - * \param size size of data buffer to send - */ - void Send (uint8_t const*buffer, uint32_t size); - /** - * \param buffer data buffer to send - * \param size size of data buffer to send - * \param daddr destination address - * \param dport destination port - * - * Send data to specified destination, ignore any default - * destination specified with DatagramSocket::SetDefaultDestination - */ - void SendTo (uint8_t const*buffer, uint32_t size, - Ipv4Address daddr, uint16_t dport); - - /** - * \param cb callback to invoke - * - * When a packet is received by this socket, it invokes the "dummy callback" which - * forwards to the application the number of bytes received and from who they - * were received. - */ - void SetDummyRxCallback (Callback cb); - /** - * \param cb callback to invoke - * - * When a packet is received by this socket, it invokes the "normal callback" which - * forwards to the application the buffer of bytes received and from who they - * were received. The application is responsible for copying that buffer if it wants - * to keep track of it. - */ - void SetRxCallback (Callback cb); - /** - * \returns pointer to node - */ - Node* GetNode(void) const; - -private: - friend class Udp; - // invoked by Udp class - void ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport); - Udp *GetUdp (void) const; - - UdpEndPoint *m_endPoint; - Node *m_node; - Ipv4Address m_defaultAddress; - uint16_t m_defaultPort; - Callback m_dummyRxCallback; - Callback m_rxCallback; -}; - -}//namespace ns3 - -#endif /* UDP_SOCKET_H */ diff --git a/src/node/onoff-application.cc b/src/node/onoff-application.cc index d3b11cbba..50cbca38f 100644 --- a/src/node/onoff-application.cc +++ b/src/node/onoff-application.cc @@ -29,8 +29,9 @@ #include "ns3/data-rate.h" #include "onoff-application.h" #include "ns3/random-variable.h" -#include "datagram-socket.h" +#include "socket.h" #include "ns3/simulator.h" +#include "udp.h" using namespace std; @@ -157,8 +158,8 @@ void OnOffApplication::StartApplication() // Called at time specified by Star MakeCallback(&OnOffApplication::ConnectionFailed, this)); #endif - m_socket = new DatagramSocket (GetNode()); - m_socket->SetDefaultDestination(m_peerIP, m_peerPort); + m_socket = GetNode ()->GetUdp ()->CreateSocket (); + m_socket->Connect (m_peerIP, m_peerPort); } StopApplication(); // Insure no pending event // If we are not yet connected, there is nothing to do here @@ -238,7 +239,7 @@ void OnOffApplication::ScheduleStopEvent() void OnOffApplication::SendPacket() { m_sendScheduled = false; - m_socket->SendDummy(m_pktSize); + m_socket->Send(0, m_pktSize); #ifdef NOTYET m_socket->Send(0, m_pktSize); // Send the packet #endif @@ -248,13 +249,13 @@ void OnOffApplication::SendPacket() ScheduleNextTx(); } -void OnOffApplication::ConnectionSucceeded(DatagramSocket*) +void OnOffApplication::ConnectionSucceeded(Socket*) { m_connected = true; ScheduleStartEvent(); } -void OnOffApplication::ConnectionFailed(DatagramSocket*) +void OnOffApplication::ConnectionFailed(Socket*) { cout << "OnOffApplication, Connection Failed" << endl; } diff --git a/src/node/onoff-application.h b/src/node/onoff-application.h index 7f7783586..46a5bc534 100644 --- a/src/node/onoff-application.h +++ b/src/node/onoff-application.h @@ -36,7 +36,7 @@ namespace ns3 { class Ipv4Address; class RandomVariable; -class DatagramSocket; +class Socket; class DataRate; class OnOffApplication : public Application { @@ -69,7 +69,7 @@ public: // Static methods static void DefaultSize(uint32_t s) { g_defaultSize = s;} public: - DatagramSocket* m_socket; // Associated socket + Socket * m_socket; // Associated socket Ipv4Address m_peerIP; // Peer IP address uint16_t m_peerPort; // Peer port bool m_connected; // True if connected @@ -95,9 +95,9 @@ private: void ScheduleNextTx(); void ScheduleStartEvent(); void ScheduleStopEvent(); - void ConnectionSucceeded(DatagramSocket*); - void ConnectionFailed(DatagramSocket*); - void Ignore(DatagramSocket*); + void ConnectionSucceeded(Socket*); + void ConnectionFailed(Socket*); + void Ignore(Socket*); protected: }; diff --git a/src/node/socket.cc b/src/node/socket.cc new file mode 100644 index 000000000..577bb8bae --- /dev/null +++ b/src/node/socket.cc @@ -0,0 +1,81 @@ +#include "socket.h" + +namespace ns3 { + +Socket::~Socket () +{} + +void +Socket::Close(Callback closeCompleted) +{ + DoClose (closeCompleted); +} + +void +Socket::Connect(const Ipv4Address & address, + uint16_t portNumber, + Callback connectionSucceeded, + Callback connectionFailed, + Callback halfClose) +{ + DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose); +} +int +Socket::Accept(Callback connectionRequest, + Callback newConnectionCreated, + Callback closeRequested) +{ + return DoAccept (connectionRequest, newConnectionCreated, closeRequested); +} +int +Socket::Send (const uint8_t* buffer, + uint32_t size, + Callback dataSent) +{ + return DoSend (buffer, size, dataSent); +} +int +Socket::SendTo(const Ipv4Address &address, + uint16_t port, + const uint8_t *buffer, + uint32_t size, + Callback dataSent) +{ + return DoSendTo (address, port, buffer, size, dataSent); +} +void +Socket::Recv(Callback callback) +{ + DoRecv (callback); +} +void +Socket::RecvDummy(Callback callback) +{ + DoRecvDummy (callback); +} + + +bool +Socket::RefuseAllConnections (Socket* socket, const Ipv4Address& address, uint16_t port) +{ + return false; +} +void +Socket::DummyCallbackVoidSocket (Socket *socket) +{} +void +Socket::DummyCallbackVoidSocketUi32 (Socket *socket, uint32_t) +{} +void +Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Socket *socket, uint32_t, const Ipv4Address &, uint16_t) +{} +void +Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Socket *socket, const uint8_t *, uint32_t, + const Ipv4Address &, uint16_t) +{} +void +Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Socket *socket, const Ipv4Address &, uint16_t) +{} + + +}//namespace ns3 diff --git a/src/node/socket.h b/src/node/socket.h index 1782c1e5a..f5a1b20a3 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -18,187 +18,244 @@ // Author: George F. Riley // -// Define the Sockets API for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - -// The Socket class defines an API based on the well-known -// BSD sockets. However, in a simulation environment, it is difficult -// to implement the semantics "blocking" calls, such as recv. -// The ns3 API will always return immediately from the blocking calls, -// with an upcall at a later time when the call would unblock. -// All blocking calls have a parameters with callbacks -// to the desired upcall. However, the design supports the upcall -// even if the owner of the socket has not posted the corresponding -// blocking call, which eases implementation slightly. -// -// The ns3 class "Process"is anticipated to be a common way to create -// and manipulate sockets, so a set of member functions are provided -// in class Process to give a syntactically easy way to access the -// sockets with default upcall virtual functions for each of the -// defined blocking calls. See the definition and implementation -// Process in process.h for details. -// -// As designed, the Socket class is a virtual base class, which defines -// the services that each layer 4 protocol must provide. - #ifndef __SOCKET_H__ #define __SOCKET_H__ #include "ns3/callback.h" -#include "protocol.h" +#include "ipv4-address.h" +#include -namespace ns3{ +namespace ns3 { -class IPAddr; -class L4Protocol; -class Process; +class Node; -// \brief Define the BSD Sockets API +/** + * \brief Define a Socket API based on the BSD Socket API. + * + * Contrary to the original BSD socket API, this API is asynchronous: + * it does not contain blocking calls. This API also does not use + * the dreaded BSD sockaddr_t type. Other than that, it tries to stick + * to the BSD API to make it easier those who know the BSD API to use + * this API. + */ class Socket { public: - Socket(); // Constructor - virtual ~Socket() {} -private: - // These static methods are default, do-nothing callbacks. They are - // provided as default arguments to the various socket calls, so callers who - // are not interested in a particular callback can ignore the - // parameters. Since these are used as formal parameters to MakeCallbac, - // each must have a unique name (they can't be disambiguated by argument - // list). The naming convention is a single letter indicating the - // return type (V = void for example) and a single letter for each - // argument type (S = Socket for exampls). - static void CBIgnoreVS(Socket*) {} - static void CBIgnoreVSIP(Socket*, const IPAddr&, PortId_t) {} - static void CBIgnoreVSU(Socket*, uint32_t) {} - static void CBIgnoreVSCU(Socket*, char*, uint32_t) {} - static bool CBIgnoreBSIP(Socket*, const IPAddr&, PortId_t){ return true;} - static void CBIgnoreVSCUIP(Socket*, char*, uint32_t, const IPAddr&, PortId_t); + virtual ~Socket(); + + enum SocketErrno { + ENOTERROR, + EISCONN, + ENOTCONN, + EMSGSIZE, + EAGAIN, + ESHUTDOWN, + EOPNOTSUPP, + SOCKET_ERRNO_LAST + }; + + /** + * \return the errno associated to the last call which failed in this + * socket. Each socket's errno is initialized to zero + * when the socket is created. + */ + virtual enum Socket::SocketErrno GetErrno (void) const = 0; + + /** + * \returns the node this socket is associated with. + */ + virtual Node *GetNode (void) const = 0; + + /** + * Allocate a free port number and + * bind this socket to this port number on all + * interfaces of this system. + * + * \returns 0 on success, -1 on failure. + */ + virtual int Bind (void) = 0; + + /** + * Allocate a free port number and + * bind this socket to this port number on the + * specified interface. + * + * \param address address of interface to bind to. + * \returns 0 on success, -1 on failure. + */ + virtual int Bind (Ipv4Address address) = 0; + + /** + * Bind this socket to this port number + * on all interfaces of this system. + * + * \param port port to bind to on all interfaces + * \returns 0 on success, -1 on failure. + */ + virtual int Bind (uint16_t port) = 0; + + /** + * Bind this socket to this port number + * on the interface specified by address. + * + * \param address address of interface to bind to. + * \param port port to bind to on specified interface + * \returns 0 on success, -1 on failure. + */ + virtual int Bind (Ipv4Address address, uint16_t port) = 0; + + /** + * \brief Close a socket. + * \param closeCompleted Callback invoked when the close operation is + * completed. + * + * After the Close call, the socket is no longer valid, and cannot + * safely be used for subsequent operations. + */ + void Close(Callback closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket)); + + /** + * \returns zero on success, -1 on failure. + * + * Do not allow any further Send calls. This method is typically + * implemented for Tcp sockets by a half close. + */ + virtual int ShutdownSend (void) = 0; + + /** + * \returns zero on success, -1 on failure. + * + * Do not allow any further Recv calls. This method is typically + * implemented for Tcp sockets by a half close. + */ + virtual int ShutdownRecv (void) = 0; + + /** + * \brief Initiate a connection to a remote host + * \param address IP Address of remote. + * \param portNumber Port number of remote + * \param connectionSucceeded this callback is invoked when the connection request + * initiated by the user is successfully completed. The callback is passed + * back a pointer to the same socket object. + * \param connectionFailed this callback is invoked when the connection request + * initiated by the user is unsuccessfully completed. The callback is passed + * back a pointer to the same socket object. + * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the + * other side closes the connection ? Or when I call Close ? + */ + void Connect(const Ipv4Address & address, + uint16_t portNumber, + Callback connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket), + Callback connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket), + Callback halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket)); + + /** + * \brief Accept connection requests from remote hosts + * \param connectionRequest Callback for connection request from peer. + * This user callback is passed a pointer to this socket, the + * ip address and the port number of the connection originator. + * This callback must return true to accept the incoming connection, + * false otherwise. If the connection is accepted, the + * "newConnectionCreated" callback will be invoked later to give access + * to the user to the socket created to match this new connection. If the + * user does not explicitely specify this callback, all incoming + * connections will be refused. + * \param newConnectionCreated Callback for new connection: when a new + * is accepted, it is created and the corresponding socket is passed + * back to the user through this callback. This user callback is passed + * a pointer to the new socket, and the ip address and port number + * of the connection originator. + * \param closeRequested Callback for connection close request from peer. + * XXX: when is this callback invoked ? + */ + int Accept(Callback connectionRequest = + MakeCallback(&Socket::RefuseAllConnections), + Callback newConnectionCreated = + MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16), + Callback closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket)); + + /** + * \brief Send data (or dummy data) to the remote host + * \param buffer Data to send (nil if dummy data). + * \param size Number of bytes to send. + * \param dataSent Data sent callback. + * \returns -1 in case of error or the number of bytes copied in the + * internal buffer and accepted for transmission. + */ + int Send (const uint8_t* buffer, + uint32_t size, + Callback dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32)); -public: - // Define the BSD Socket API, with some slight variations. - - // \brief Bind the socket to a particular port number - // \param Port number to bind. If zero is specified, an available - // transient port is assigned. - // \return Port number assigned, or -1 if port already in use. - - virtual PortId_t Bind(PortId_t = 0); - - // \brief Close a socket. - // After the Close call, the socket is no longer valid, and cannot - // safely be used for subsequent operations. - // \param Callback for close completed. - virtual void Close(ns3::Callback - = MakeCallback(&Socket::CBIgnoreVS)); - - // \brief Initiate a connection to a remote host - // \param IP Address of remote. - // \param Port number of remote - // \param Callback for connection succeeded - // \param Callback for connection failed - // \param Callback for connection close requested by peer - virtual void Connect(const IPAddr&, // IPAddress of peer - PortId_t, // Port number - ns3::Callback = // COnnection succeeded callback, - MakeCallback(&Socket::CBIgnoreVS), - ns3::Callback = // Connection failed callback - MakeCallback(&Socket::CBIgnoreVS), - ns3::Callback = // CloseRequested callback - MakeCallback(&Socket::CBIgnoreVS)); + /** + * \brief Send data to a specified peer. + * \param address IP Address of remote host + * \param port port number + * \param buffer Data to send (nil if dummy data). + * \param size Number of bytes to send. + * \param dataSent Data sent callback. + * \returns -1 in case of error or the number of bytes copied in the + * internal buffer and accepted for transmission. + */ + int SendTo(const Ipv4Address &address, + uint16_t port, + const uint8_t *buffer, + uint32_t size, + Callback dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32)); - // \brief Specify the number of pending connections to buffer - // while not blocked on accept. We include this for completeness, - // but with the callback approach to connection acceptance this - // does nothing. - virtual void Listen(uint32_t); + /** + * \brief Receive data + * \param Received data callback. Invoked whenever new data is received. + * + * If you wish to transport only dummy packets, this method is not a very + * efficient way to receive these dummy packets: it will trigger a memory + * allocation to hold the dummy memory into a buffer which can be passed + * to the user. Instead, consider using the RecvDummy method. + */ + void Recv(Callback = + MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16)); - // \brief Accept connection requests from remote hosts - // \param Callback for connection request from peer - // \param Callback for new connection - // \param Callback for connection close request from peer - virtual void Accept( - // Connection request callback - ns3::Callback = - MakeCallback(&Socket::CBIgnoreBSIP), - // New connection callback - ns3::Callback = - MakeCallback(&Socket::CBIgnoreVSIP), - // CloseRequested callback - ns3::Callback = - MakeCallback(&Socket::CBIgnoreVS)); - - // \brief Send data (or dummy data) to the remote host - // \param Data to send (nil if dummy data). - // NOTE. The data (if any) is copied by this call, so pointers - // to local data is allowed and processed correctly. - // \param Number of bytes to send. - // \param Data sent callback. A suitable "ignore" callback - // is used if not specified. - virtual void Send(char*, // Data to send - uint32_t, // Number of bytes - ns3::Callback = - MakeCallback(&CBIgnoreVSU)); // Sent cb - - // \brief Send data to a specified peer. - // \param IP Address of remote host - // \param port number - // \param Data to send (nil if dummy data). - // NOTE. The data (if any) is copied by this call, so pointers - // to local data is allowed and processed correctly. - // \param Number of bytes to send. - // \param Data sent callback - virtual void SendTo(const IPAddr&, // IP Address of remote peer - PortId_t, // Port number of remote peer - char*, // Data to send - uint32_t, // Number of bytes - ns3::Callback = - MakeCallback(&Socket::CBIgnoreVSU)); // Sent cb - - // \brief Receive data - // Note that due to the callback nature of the ns3 implementation, - // there is no data pointer provided here. Rather, the callback - // will specify where the data can be found, and the callback should - // copy it to a local buffer if needed at that time. - // \param Received data callback. - virtual void Recv(ns3::Callback = - MakeCallback(&Socket::CBIgnoreVSCUIP)); + /** + * \brief Receive data + * \param Received data callback. Invoked whenever new data is received. + * + * This method is included because it is vastly more efficient than the + * Recv method when you use dummy payload. + */ + void RecvDummy(Callback = + MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16)); private: -// upcalls -// The members below are all callbacks, created with MakeCallback, - ns3::Callback m_cbCloseComplete; // Socket Closed upcall - ns3::Callback m_cbCloseRequested; // Close req by peer - ns3::Callback m_cbConnectionSucceeded;// Connection successful - ns3::Callback m_cbConnectionFailed; // Connection failed + virtual void DoClose(Callback closeCompleted) = 0; + virtual void DoConnect(const Ipv4Address & address, + uint16_t portNumber, + Callback connectionSucceeded, + Callback connectionFailed, + Callback halfClose) = 0; + virtual int DoAccept(Callback connectionRequest, + Callback newConnectionCreated, + Callback closeRequested) = 0; + virtual int DoSend (const uint8_t* buffer, + uint32_t size, + Callback dataSent) = 0; + virtual int DoSendTo(const Ipv4Address &address, + uint16_t port, + const uint8_t *buffer, + uint32_t size, + Callback dataSent) = 0; + virtual void DoRecv(Callback receive) = 0; + virtual void DoRecvDummy(Callback) = 0; - // \brief For TCP sockets, the cbSent upcall call is made when the data packet - // is sent, but not acknowledged. For UDP sockets, it is called - // immediately. - ns3::Callback m_cbSent; // Data delivered - - // \brief For the cbRecv callback, the char* to the data may be nil if - // no actual data is present. - ns3::Callback m_cbRecv; - - // \brief The cbConnectionRequest callback is called when a socket has - // called Listen, and indicates a remote peer has sent a connection - // request. The callback can return false to indicate the connection - // is to be rejected, for example in a peer-to-peer application that - // wants to limit the number of connections at any one time. - ns3::Callback m_cbConnectionRequest; - - // \brief The cbNewConnection callback is called when a connection request - // from a peer has been received and accepted by the process owning - // this socket. Note the Socket* passed to the upcall is a new - // socket. The original socket using accept is still accepting connections. - ns3::Callback m_cbNewConnection; + static bool RefuseAllConnections (Socket* socket, const Ipv4Address& address, uint16_t port); + static void DummyCallbackVoidSocket (Socket *socket); + static void DummyCallbackVoidSocketUi32 (Socket *socket, uint32_t); + static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Socket *socket, uint32_t, const Ipv4Address &, uint16_t); + static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Socket *socket, const uint8_t *, uint32_t, + const Ipv4Address &, uint16_t); + static void DummyCallbackVoidSocketIpv4AddressUi16 (Socket *socket, const Ipv4Address &, uint16_t); }; } //namespace ns3 -#endif +#endif /* SOCKET_H */ diff --git a/src/node/udp-end-point.cc b/src/node/udp-end-point.cc index c7ac63a5a..48adb3661 100644 --- a/src/node/udp-end-point.cc +++ b/src/node/udp-end-point.cc @@ -28,11 +28,11 @@ UdpEndPoint::UdpEndPoint (Ipv4Address address, uint16_t port) {} void -UdpEndPoint::SetSocket (DatagramSocket *socket) +UdpEndPoint::SetSocket (UdpSocket *socket) { m_socket = socket; } -DatagramSocket * +UdpSocket * UdpEndPoint::GetSocket (void) const { return m_socket; diff --git a/src/node/udp-end-point.h b/src/node/udp-end-point.h index bdfc1430f..b0d745ce7 100644 --- a/src/node/udp-end-point.h +++ b/src/node/udp-end-point.h @@ -27,17 +27,17 @@ namespace ns3 { -class DatagramSocket; +class UdpSocket; class UdpEndPoint : public Ipv4EndPoint { public: UdpEndPoint (Ipv4Address address, uint16_t port); - void SetSocket (DatagramSocket *socket); - DatagramSocket *GetSocket (void) const; + void SetSocket (UdpSocket *socket); + UdpSocket *GetSocket (void) const; private: - DatagramSocket *m_socket; + UdpSocket *m_socket; }; }//namespace ns3 diff --git a/src/node/udp-socket.cc b/src/node/udp-socket.cc new file mode 100644 index 000000000..211e8371f --- /dev/null +++ b/src/node/udp-socket.cc @@ -0,0 +1,251 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * 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: Mathieu Lacage + */ +#include "udp-socket.h" +#include "udp.h" +#include "udp-end-point.h" +#include "node.h" +#include "ipv4-l4-demux.h" + +namespace ns3 { + +UdpSocket::UdpSocket (Node *node) + : m_endPoint (0), + m_node (node), + m_errno (ENOTERROR), + m_shutdownSend (false), + m_shutdownRecv (false), + m_connected (false) +{ + NS_ASSERT (GetUdp () != 0); +} +UdpSocket::~UdpSocket () +{ + delete m_endPoint; +} + +Node * +UdpSocket::GetNode (void) const +{ + return m_node; +} + +int +UdpSocket::Bind (void) +{ + m_endPoint = GetUdp ()->Allocate (); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetSocket (this); + return 0; +} +int +UdpSocket::Bind (Ipv4Address address) +{ + m_endPoint = GetUdp ()->Allocate (address); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetSocket (this); + return 0; +} +int +UdpSocket::Bind (uint16_t port) +{ + m_endPoint = GetUdp ()->Allocate (port); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetSocket (this); + return 0; +} +int +UdpSocket::Bind (Ipv4Address address, uint16_t port) +{ + m_endPoint = GetUdp ()->Allocate (address, port); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetSocket (this); + return 0; +} + +enum Socket::SocketErrno +UdpSocket::GetErrno (void) const +{ + return m_errno; +} +int +UdpSocket::ShutdownSend (void) +{ + m_shutdownSend = true; + return 0; +} +int +UdpSocket::ShutdownRecv (void) +{ + m_shutdownRecv = false; + return 0; +} + +void +UdpSocket::DoClose(ns3::Callback closeCompleted) +{ + // XXX: we should set the close state and check it in all API methods. + if (!closeCompleted.IsNull ()) + { + closeCompleted (this); + } +} +void +UdpSocket::DoConnect(const Ipv4Address & address, + uint16_t portNumber, + ns3::Callback connectionSucceeded, + ns3::Callback connectionFailed, + ns3::Callback halfClose) +{ + m_defaultAddress = address; + m_defaultPort = portNumber; + if (!connectionSucceeded.IsNull ()) + { + connectionSucceeded (this); + } + m_connected = true; +} +int +UdpSocket::DoAccept(ns3::Callback connectionRequest, + ns3::Callback newConnectionCreated, + ns3::Callback closeRequested) +{ + // calling accept on a udp socket is a programming error. + m_errno = EOPNOTSUPP; + return -1; +} +int +UdpSocket::DoSend (const uint8_t* buffer, + uint32_t size, + ns3::Callback dataSent) +{ + if (!m_connected) + { + m_errno = ENOTCONN; + return -1; + } + Packet p; + if (buffer == 0) + { + p = Packet (size); + } + else + { + p = Packet (buffer, size); + } + return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent); +} +int +UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, + ns3::Callback dataSent) +{ + if (m_endPoint == 0) + { + if (Bind () == -1) + { + NS_ASSERT (m_endPoint == 0); + return -1; + } + NS_ASSERT (m_endPoint != 0); + } + if (m_shutdownSend) + { + m_errno = ESHUTDOWN; + return -1; + } + GetUdp ()->Send (p, m_endPoint->GetLocalAddress (), daddr, + m_endPoint->GetLocalPort (), dport); + if (!dataSent.IsNull ()) + { + dataSent (this, p.GetSize ()); + } + return 0; +} +int +UdpSocket::DoSendTo(const Ipv4Address &address, + uint16_t port, + const uint8_t *buffer, + uint32_t size, + ns3::Callback dataSent) +{ + if (m_connected) + { + m_errno = EISCONN; + return -1; + } + Packet p; + if (buffer == 0) + { + p = Packet (size); + } + else + { + p = Packet (buffer, size); + } + return DoSendPacketTo (p, address, port, dataSent); +} +void +UdpSocket::DoRecv(ns3::Callback callback) +{ + m_rxCallback = callback; +} +void +UdpSocket::DoRecvDummy(ns3::Callback callback) +{ + m_dummyRxCallback = callback; +} + +void +UdpSocket::ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport) +{ + if (m_shutdownRecv) + { + return; + } + if (!m_dummyRxCallback.IsNull ()) + { + m_dummyRxCallback (this, p.GetSize (), saddr, sport); + } + if (!m_rxCallback.IsNull ()) + { + m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport); + } +} + +Udp * +UdpSocket::GetUdp (void) const +{ + return m_node->GetUdp (); +} + + +}//namespace ns3 diff --git a/src/node/udp-socket.h b/src/node/udp-socket.h new file mode 100644 index 000000000..5eae43bd8 --- /dev/null +++ b/src/node/udp-socket.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * 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: Mathieu Lacage + */ +#ifndef UDP_SOCKET_H +#define UDP_SOCKET_H + +#include +#include "ns3/callback.h" +#include "socket.h" + +namespace ns3 { + +class UdpEndPoint; +class Node; +class Packet; +class Udp; + +class UdpSocket : public Socket +{ +public: + /** + * Create an unbound udp socket. + */ + UdpSocket (Node *node); + virtual ~UdpSocket (); + + virtual enum SocketErrno GetErrno (void) const; + virtual Node *GetNode (void) const; + virtual int Bind (void); + virtual int Bind (Ipv4Address address); + virtual int Bind (uint16_t port); + virtual int Bind (Ipv4Address address, uint16_t port); + virtual int ShutdownSend (void); + virtual int ShutdownRecv (void); + +private: + virtual void DoClose(ns3::Callback closeCompleted); + virtual void DoConnect(const Ipv4Address & address, + uint16_t portNumber, + ns3::Callback connectionSucceeded, + ns3::Callback connectionFailed, + ns3::Callback halfClose); + virtual int DoAccept(ns3::Callback connectionRequest, + ns3::Callback newConnectionCreated, + ns3::Callback closeRequested); + virtual int DoSend (const uint8_t* buffer, + uint32_t size, + ns3::Callback dataSent); + virtual int DoSendTo(const Ipv4Address &address, + uint16_t port, + const uint8_t *buffer, + uint32_t size, + ns3::Callback dataSent); + virtual void DoRecv(ns3::Callback); + virtual void DoRecvDummy(ns3::Callback); + +private: + friend class Udp; + // invoked by Udp class + void ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport); + Udp *GetUdp (void) const; + int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, + ns3::Callback dataSent); + + UdpEndPoint *m_endPoint; + Node *m_node; + Ipv4Address m_defaultAddress; + uint16_t m_defaultPort; + Callback m_dummyRxCallback; + Callback m_rxCallback; + enum SocketErrno m_errno; + bool m_shutdownSend; + bool m_shutdownRecv; + bool m_connected; +}; + +}//namespace ns3 + +#endif /* UDP_SOCKET_H */ diff --git a/src/node/udp.cc b/src/node/udp.cc index 6e89695a5..0f6f6faea 100644 --- a/src/node/udp.cc +++ b/src/node/udp.cc @@ -27,10 +27,10 @@ #include "udp-header.h" #include "ipv4-end-point-demux.h" #include "udp-end-point.h" -#include "datagram-socket.h" #include "node.h" #include "ipv4.h" #include "l3-demux.h" +#include "udp-socket.h" namespace ns3 { @@ -54,6 +54,12 @@ Udp::CreateTraceResolver (TraceContext const &context) return new EmptyTraceResolver (context); } +Socket * +Udp::CreateSocket (void) +{ + return new UdpSocket (m_node); +} + UdpEndPoint * Udp::Allocate (void) { @@ -102,7 +108,7 @@ Udp::Receive(Packet& packet, { return; } - DatagramSocket *socket = endPoint->GetSocket (); + UdpSocket *socket = endPoint->GetSocket (); socket->ForwardUp (packet, source, udpHeader.GetSource ()); NS_ASSERT (socket != 0); } diff --git a/src/node/udp.h b/src/node/udp.h index ba6c1dbb0..9f3ea3bb4 100644 --- a/src/node/udp.h +++ b/src/node/udp.h @@ -35,6 +35,7 @@ namespace ns3 { class Node; class TraceResolver; class TraceContext; +class Socket; class Udp : public Ipv4L4Protocol { public: @@ -45,6 +46,8 @@ public: virtual TraceResolver *CreateTraceResolver (TraceContext const &context); + Socket *CreateSocket (void); + UdpEndPoint *Allocate (void); UdpEndPoint *Allocate (Ipv4Address address); UdpEndPoint *Allocate (uint16_t port);