diff --git a/src/internet-node/tcp-socket.cc b/src/internet-node/tcp-socket.cc index a350476e0..5f8e0d195 100644 --- a/src/internet-node/tcp-socket.cc +++ b/src/internet-node/tcp-socket.cc @@ -378,11 +378,12 @@ int TcpSocket::Send (const uint8_t* buf, uint32_t size) { NS_LOG_FUNCTION (this << buf << size); if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) - { // Ok to buffer some data to send + { if (size > GetTxAvailable ()) { - size = std::min(size, GetTxAvailable() ); //only buffer what can fit m_wouldBlock = true; + m_errno = ERROR_MSGSIZE; + return -1; } if (!m_pendingData) { diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 5670aa8fc..c7c87900e 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -37,6 +37,8 @@ NS_LOG_COMPONENT_DEFINE ("UdpSocket"); namespace ns3 { +static const uint32_t MAX_IPV4_UDP_DATAGRAM_SIZE = 65507; + TypeId UdpSocket::GetTypeId (void) { @@ -302,6 +304,12 @@ UdpSocket::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) return -1; } + if (p->GetSize () > GetTxAvailable () ) + { + m_errno = ERROR_MSGSIZE; + return -1; + } + uint32_t localIfIndex; Ptr ipv4 = m_node->GetObject (); @@ -344,12 +352,15 @@ UdpSocket::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) return 0; } +// XXX maximum message size for UDP broadcast is limited by MTU +// size of underlying link; we are not checking that now. uint32_t UdpSocket::GetTxAvailable (void) const { NS_LOG_FUNCTION_NOARGS (); - // No finite send buffer is modelled - return std::numeric_limits::max (); + // No finite send buffer is modelled, but we must respect + // the maximum size of an IP datagram (65535 bytes - headers). + return MAX_IPV4_UDP_DATAGRAM_SIZE; } int diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index d04ef5dc2..8ebe8748a 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -240,11 +240,12 @@ PacketSocket::Send (Ptr p) return SendTo (p, m_destAddr); } +// XXX must limit it to interface MTU uint32_t PacketSocket::GetTxAvailable (void) const { - // No finite send buffer is modelled - return 0xffffffff; + // Use 65536 for now + return 0xffff; } int @@ -277,6 +278,11 @@ PacketSocket::SendTo(Ptr p, const Address &address) m_errno = ERROR_AFNOSUPPORT; return -1; } + if (p->GetSize () > GetTxAvailable ()) + { + m_errno = ERROR_MSGSIZE; + return -1; + } ad = PacketSocketAddress::ConvertFrom (address); bool error = false; diff --git a/src/node/socket.h b/src/node/socket.h index 0d879e74d..c78970af6 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -257,15 +257,50 @@ public: /** * \brief Send data (or dummy data) to the remote host - * \param p packet to send - * \returns -1 in case of error or the number of bytes copied in the - * internal buffer and accepted for transmission. + * + * This function matches closely in semantics to the send() function + * call in the standard C library (libc): + * ssize_t send (int s, const void *msg, size_t len, int flags); + * except that the function call is asynchronous. + * + * In a typical blocking sockets model, this call would block upon + * lack of space to hold the message to be sent. In ns-3 at this + * API, the call returns immediately in such a case, but the callback + * registered with SetSendCallback() is invoked when the socket + * has space (when it conceptually unblocks); this is an asynchronous + * I/O model for send(). + * + * This variant of Send() uses class ns3::Packet to encapsulate + * data, rather than providing a raw pointer and length field. + * This allows an ns-3 application to attach tags if desired (such + * as a flow ID) and may allow the simulator to avoid some data + * copies. Despite the appearance of sending Packets on a stream + * socket, just think of it as a fancy byte buffer with streaming + * semantics. + * + * If either the message buffer within the Packet is too long to pass + * atomically through the underlying protocol (for datagram sockets), + * or the message buffer cannot entirely fit in the transmit buffer + * (for stream sockets), -1 is returned and SocketErrno is set + * to ERROR_MSGSIZE. If the packet does not fit, the caller can + * split the Packet (based on information obtained from + * GetTxAvailable) and reattempt to send the data. + * + * \param p ns3::Packet to send + * \returns the number of bytes accepted for transmission if no error + * occurs, and -1 otherwise. */ virtual int Send (Ptr p) = 0; /** - * returns the number of bytes which can be sent in a single call + * \brief Returns the number of bytes which can be sent in a single call * to Send. + * + * For datagram sockets, this returns the number of bytes that + * can be passed atomically through the underlying protocol. + * + * For stream sockets, this returns the available space in bytes + * left in the transmit buffer. */ virtual uint32_t GetTxAvailable (void) const = 0;