diff -r 867b0ba95374 src/applications/packet-sink/packet-sink.cc --- a/src/applications/packet-sink/packet-sink.cc Mon Sep 28 01:06:47 2009 -0700 +++ b/src/applications/packet-sink/packet-sink.cc Wed Sep 30 13:05:42 2009 -0400 @@ -62,6 +62,7 @@ PacketSink::PacketSink () { NS_LOG_FUNCTION (this); m_socket = 0; + m_totalRx = 0; } PacketSink::~PacketSink() @@ -69,8 +70,12 @@ PacketSink::~PacketSink() NS_LOG_FUNCTION (this); } -void -PacketSink::DoDispose (void) +uint32_t PacketSink::GetTotalRx() const +{ + return m_totalRx; +} + +void PacketSink::DoDispose (void) { NS_LOG_FUNCTION (this); m_socket = 0; @@ -109,6 +114,9 @@ void PacketSink::StartApplication() / m_socket->SetAcceptCallback ( MakeNullCallback, const Address &> (), MakeCallback(&PacketSink::HandleAccept, this)); + m_socket->SetCloseCallbacks ( + MakeCallback(&PacketSink::HandlePeerClose, this), + MakeCallback(&PacketSink::HandlePeerError, this)); } void PacketSink::StopApplication() // Called at time specified by Stop @@ -141,12 +149,25 @@ void PacketSink::HandleRead (Ptr if (InetSocketAddress::IsMatchingType (from)) { InetSocketAddress address = InetSocketAddress::ConvertFrom (from); + m_totalRx += packet->GetSize(); NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << - address.GetIpv4() << " [" << address << "]"); + address.GetIpv4() << " [" << address << "]" + << " total Rx " << m_totalRx); } m_rxTrace (packet, from); } } + +void PacketSink::HandlePeerClose (Ptr socket) +{ + NS_LOG_INFO("PktSink, peerClose"); +} + +void PacketSink::HandlePeerError (Ptr socket) +{ + NS_LOG_INFO("PktSink, peerError"); +} + void PacketSink::HandleAccept (Ptr s, const Address& from) { diff -r 867b0ba95374 src/applications/packet-sink/packet-sink.h --- a/src/applications/packet-sink/packet-sink.h Mon Sep 28 01:06:47 2009 -0700 +++ b/src/applications/packet-sink/packet-sink.h Wed Sep 30 13:05:42 2009 -0400 @@ -73,6 +73,9 @@ public: virtual ~PacketSink (); + // Return the total bytes received in this sink app + uint32_t GetTotalRx() const; + protected: virtual void DoDispose (void); private: @@ -80,15 +83,18 @@ private: virtual void StartApplication (void); // Called at time specified by Start virtual void StopApplication (void); // Called at time specified by Stop - void HandleRead (Ptr socket); + void HandleRead (Ptr); void HandleAccept (Ptr, const Address& from); - + void HandlePeerClose(Ptr); + void HandlePeerError(Ptr); + // In the case of TCP, each socket accept returns a new socket, so the // listening socket is stored seperately from the accepted sockets Ptr m_socket; // Listening socket std::list > m_socketList; //the accepted sockets Address m_local; // Local address to bind to + uint32_t m_totalRx; // Total bytes received TypeId m_tid; // Protocol TypeId TracedCallback, const Address &> m_rxTrace; diff -r 867b0ba95374 src/internet-stack/tcp-socket-impl.cc --- a/src/internet-stack/tcp-socket-impl.cc Mon Sep 28 01:06:47 2009 -0700 +++ b/src/internet-stack/tcp-socket-impl.cc Wed Sep 30 13:05:42 2009 -0400 @@ -198,6 +198,7 @@ TcpSocketImpl::~TcpSocketImpl () m_tcp = 0; delete m_pendingData; //prevents leak m_pendingData = 0; + CancelAllTimers(); } void @@ -329,14 +330,28 @@ TcpSocketImpl::Close (void) TcpSocketImpl::Close (void) { NS_LOG_FUNCTION_NOARGS (); - if (m_pendingData && m_pendingData->Size() != 0) + // First we check to see if there is any unread rx data + // Bug number 426 claims we should send reset in this case. + if (!m_bufferedData.empty()) + { + SendRST(); + return 0; + } + + uint32_t remainingData = 0; + if (m_pendingData) + { + remainingData = m_pendingData->SizeFromSeq (m_firstPendingSequence, + m_nextTxSequence); + } + + if (remainingData != 0) { // App close with pending data must wait until all data transmitted m_closeOnEmpty = true; NS_LOG_LOGIC("Socket " << this << " deferring close, state " << m_state); return 0; } - Actions_t action = ProcessEvent (APP_CLOSE); ProcessAction (action); return 0; @@ -460,9 +475,12 @@ int TcpSocketImpl::DoSendTo (Ptr m_errno = ERROR_SHUTDOWN; return -1; } + // Get the size before sending to tcp, as the sent callback cares + // about payload sent, not with headers + uint32_t sentSize = p->GetSize(); m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4, m_endPoint->GetLocalPort (), port); - NotifyDataSent (p->GetSize ()); + NotifyDataSent (sentSize); return 0; } @@ -638,6 +656,16 @@ TcpSocketImpl::ForwardUp (Ptr pa TcpHeader tcpHeader; packet->RemoveHeader (tcpHeader); + if (tcpHeader.GetFlags () & TcpHeader::RST) + { // Got an RST, just shut everything down + NotifyErrorClose(); + CancelAllTimers(); + m_endPoint->SetDestroyCallback(MakeNullCallback()); + m_tcp->DeAllocate (m_endPoint); + m_endPoint = 0; + return; + } + if (tcpHeader.GetFlags () & TcpHeader::ACK) { Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () ); @@ -677,6 +705,8 @@ Actions_t TcpSocketImpl::ProcessEvent (E { NS_LOG_LOGIC ("TcpSocketImpl " << this << " sending RST from state " << saveState << " event " << e); + SendRST(); + return NO_ACT; } bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED && e != TIMEOUT); @@ -692,7 +722,6 @@ Actions_t TcpSocketImpl::ProcessEvent (E // the handshaking { Simulator::ScheduleNow(&TcpSocketImpl::ConnectionSucceeded, this); - //NotifyConnectionSucceeded (); m_connected = true; m_endPoint->SetPeer (m_remoteAddress, m_remotePort); NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); @@ -708,6 +737,7 @@ Actions_t TcpSocketImpl::ProcessEvent (E NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " << m_state << " event " << e << " closeNot " << m_closeNotified << " action " << stateAction.action); + NotifyNormalClose(); m_closeNotified = true; NS_LOG_LOGIC ("TcpSocketImpl " << this << " calling Closed from PE" << " origState " << saveState @@ -732,6 +762,7 @@ Actions_t TcpSocketImpl::ProcessEvent (E m_endPoint->SetDestroyCallback(MakeNullCallback()); m_tcp->DeAllocate (m_endPoint); m_endPoint = 0; + CancelAllTimers(); } return stateAction.action; @@ -776,6 +807,18 @@ void TcpSocketImpl::SendEmptyPacket (uin } } +// This function closes the endpoint completely +void TcpSocketImpl::SendRST() +{ + SendEmptyPacket(TcpHeader::RST); + NotifyErrorClose(); + CancelAllTimers(); + m_endPoint->SetDestroyCallback(MakeNullCallback()); + m_tcp->DeAllocate (m_endPoint); + m_endPoint = 0; +} + + bool TcpSocketImpl::ProcessAction (Actions_t a) { // These actions do not require a packet or any TCP Headers NS_LOG_FUNCTION (this << a); @@ -976,6 +1019,7 @@ bool TcpSocketImpl::ProcessPacketAction break; case PEER_CLOSE: { + NS_LOG_LOGIC("Got Peer Close"); // First we have to be sure the FIN packet was not received // out of sequence. If so, note pending close and process // new sequence rx @@ -1002,6 +1046,7 @@ bool TcpSocketImpl::ProcessPacketAction { NS_LOG_LOGIC ("TCP " << this << " calling AppCloseRequest"); + NotifyNormalClose(); m_closeRequestNotified = true; } NS_LOG_LOGIC ("TcpSocketImpl " << this @@ -1132,8 +1177,8 @@ bool TcpSocketImpl::SendPendingData (boo m_endPoint->GetLocalAddress (), m_remoteAddress); m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT - // Notify the application - Simulator::ScheduleNow(&TcpSocketImpl::NotifyDataSent, this, p->GetSize ()); + // Notify the application of the data being sent + Simulator::ScheduleNow(&TcpSocketImpl::NotifyDataSent, this, sz); nPacketsSent++; // Count sent this loop m_nextTxSequence += sz; // Advance next tx sequence // Note the high water mark @@ -1406,7 +1451,6 @@ void TcpSocketImpl::CommonNewAck (Sequen // and MUST be called by any subclass, from the NewAck function // Always cancel any pending re-tx timer on new acknowledgement NS_LOG_FUNCTION (this << ack << skipTimer); - //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl)); if (!skipTimer) { NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " @@ -1465,6 +1509,14 @@ void TcpSocketImpl::CommonNewAck (Sequen SendPendingData (m_connected); } +void TcpSocketImpl::CancelAllTimers() +{ + m_retxEvent.Cancel (); + m_persistEvent.Cancel (); + m_delAckEvent.Cancel(); + m_lastAckEvent.Cancel (); +} + Ptr TcpSocketImpl::Copy () { return CopyObject (this); diff -r 867b0ba95374 src/internet-stack/tcp-socket-impl.h --- a/src/internet-stack/tcp-socket-impl.h Mon Sep 28 01:06:47 2009 -0700 +++ b/src/internet-stack/tcp-socket-impl.h Wed Sep 30 13:05:42 2009 -0400 @@ -105,6 +105,8 @@ private: int DoSendTo (Ptr p, const Address &daddr); int DoSendTo (Ptr p, Ipv4Address daddr, uint16_t dport); void SendEmptyPacket(uint8_t flags); + void SendRST(); + //methods for state bool ProcessAction (Actions_t a); bool ProcessAction (Actions_t a, const TcpHeader& tcpHeader, @@ -130,18 +132,18 @@ private: // Manage data tx/rx void NewRx (Ptr, const TcpHeader&, const Address&); void RxBufFinishInsert (SequenceNumber); - // XXX This should be virtual and overridden Ptr Copy (); - void NewAck (SequenceNumber seq); - // XXX This should be virtual and overridden - void DupAck (const TcpHeader& t, uint32_t count); - void ReTxTimeout (); + virtual void NewAck (SequenceNumber seq); + virtual void DupAck (const TcpHeader& t, uint32_t count); + virtual void ReTxTimeout (); void DelAckTimeout (); void LastAckTimeout (); void PersistTimeout (); void Retransmit (); void CommonNewAck (SequenceNumber seq, bool skipTimer = false); - + // All timers are cancelled when the endpoint is deleted, to insure + // we don't have additional activity + void CancelAllTimers(); // attribute related virtual void SetSndBufSize (uint32_t size); virtual uint32_t GetSndBufSize (void) const; diff -r 867b0ba95374 src/node/socket.cc --- a/src/node/socket.cc Mon Sep 28 01:06:47 2009 -0700 +++ b/src/node/socket.cc Wed Sep 30 13:05:43 2009 -0400 @@ -62,6 +62,16 @@ Socket::SetConnectCallback ( } void +Socket::SetCloseCallbacks ( + Callback > normalClose, + Callback > errorClose) +{ + NS_LOG_FUNCTION_NOARGS (); + m_normalClose = normalClose; + m_errorClose = errorClose; +} + +void Socket::SetAcceptCallback ( Callback, const Address &> connectionRequest, Callback, const Address&> newConnectionCreated) @@ -191,6 +201,26 @@ Socket::NotifyConnectionFailed (void) if (!m_connectionFailed.IsNull ()) { m_connectionFailed (this); + } +} + +void +Socket::NotifyNormalClose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (!m_normalClose.IsNull ()) + { + m_normalClose (this); + } +} + +void +Socket::NotifyErrorClose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (!m_errorClose.IsNull ()) + { + m_errorClose (this); } } diff -r 867b0ba95374 src/node/socket.h --- a/src/node/socket.h Mon Sep 28 01:06:47 2009 -0700 +++ b/src/node/socket.h Wed Sep 30 13:05:43 2009 -0400 @@ -103,6 +103,8 @@ public: */ virtual Ptr GetNode (void) const = 0; /** + * \brief Specify callbacks to allow the caller to determine if + * the connection succeeds of fails. * \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 @@ -114,6 +116,23 @@ public: */ void SetConnectCallback (Callback > connectionSucceeded, Callback > connectionFailed); + /** + * \brief Detect socket recv() events such as graceful shutdown or error. + * + * For connection-oriented sockets, the first callback is used to signal + * that the remote side has gracefully shut down the connection, and the + * second callback denotes an error corresponding to cases in which + * a traditional recv() socket call might return -1 (error), such + * as a connection reset. For datagram sockets, these callbacks may + * never be invoked. + * + * \param normalClose this callback is invoked when the + * peer closes the connection gracefully + * \param errorClose this callback is invoked when the + * connection closes abnormally + */ + void SetCloseCallbacks (Callback > normalClose, + Callback > errorClose); /** * \brief Accept connection requests from remote hosts * \param connectionRequest Callback for connection request from peer. @@ -496,6 +515,8 @@ protected: protected: void NotifyConnectionSucceeded (void); void NotifyConnectionFailed (void); + void NotifyNormalClose(void); + void NotifyErrorClose(void); bool NotifyConnectionRequest (const Address &from); void NotifyNewConnectionCreated (Ptr socket, const Address &from); void NotifyDataSent (uint32_t size); @@ -503,13 +524,15 @@ protected: void NotifyDataRecv (void); virtual void DoDispose (void); private: - Callback > m_connectionSucceeded; - Callback > m_connectionFailed; + Callback > m_connectionSucceeded; + Callback > m_connectionFailed; + Callback > m_normalClose; + Callback > m_errorClose; Callback, const Address &> m_connectionRequest; Callback, const Address&> m_newConnectionCreated; Callback, uint32_t> m_dataSent; Callback, uint32_t > m_sendCb; - Callback > m_receivedData; + Callback > m_receivedData; };