Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Transport::TCP class for tcp-based communication. #2689

Merged
merged 46 commits into from
Sep 17, 2020

Conversation

andy31415
Copy link
Contributor

Problem

CHIP requires the ability to communicate over TCP (for key negotiations, for faster data transfers when supported (e.g. OTA)).

Summary of Changes

Implements a TCP-based transport, with equivalent functionality as the current Transport::UDP.

fixes #2664

…tion oriented transports need disconnection support
@@ -48,7 +48,7 @@ enum class Type
kUndefined,
kUdp,
kBle,
// More constants to be added later, such as TCP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maintain this comment or is TCP the last constant we plan to add?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not aware of anything else we could add as chip spec. I believe a comment would be 'add more stuff here if needed' however that seems redundant as any enum would be 'add more if needed'.

src/transport/Base.h Outdated Show resolved Hide resolved
src/transport/TCP.h Outdated Show resolved Hide resolved
src/transport/TCP.cpp Show resolved Hide resolved
src/transport/TCP.cpp Show resolved Hide resolved
src/transport/TCP.cpp Show resolved Hide resolved
src/transport/TCP.h Show resolved Hide resolved
// Called when a connection has been completed
static void OnConnectionComplete(Inet::TCPEndPoint * endPoint, INET_ERROR err);

// Called when a connection has been closed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth documenting how this differs from OnPeerClosed...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this mentioning this originates from TCPEndPoint.
That class has two callbacks. I am actually unsure why - peerclosed is on read 0 (peer closed) however I am unclear how this one is called (OnClose and OnAbort actually null-out the callbacks with the comment 'application called close explicitly')

src/transport/Tuple.h Show resolved Hide resolved
src/transport/tests/TestTCP.cpp Show resolved Hide resolved
err = tcp.SendMessage(header, Transport::PeerAddress::TCP(addr), buffer);
if (err == System::MapErrorPOSIX(EADDRNOTAVAIL))
{
// TODO: the underlying system does not support IPV6. This early return should
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please file an issue tracking this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a copy and paste from TestUDP ... at that time we had errors in CI, which should already have tracking issues.
I will update the wording.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an issue after all, since I believe the original issue for CI is already addressed in a curent PR which likely will not touch TestTCP/UDP.

Opened issue is #2698 and is now referenced in the TODO.

@andy31415
Copy link
Contributor Author

andy31415 commented Sep 17, 2020

@bzbarsky-apple I have addressed all comments. Will double check on freeing paths ... I wish we had some 'smart pointer' like constructs instead of raw pointers. Tracking buffer usage manually seems error prone to me. Maybe topic for the future.

@andy31415
Copy link
Contributor Author

@bzbarsky-apple I have addressed all comments. Will double check on freeing paths ... I wish we had some 'smart pointer' like constructs instead of raw pointers. Tracking buffer usage manually seems error prone to me. Maybe topic for the future.

SecureSession does indeed Free the passed in buffer, so right now all our paths seem to behave correctly (after my updates to the test).

{
return (mTransportType == other.mTransportType) && (mIPAddress == other.mIPAddress) && (mPort == other.mPort);
return (mTransportType == other.mTransportType) && (mIPAddress == other.mIPAddress) && (mPort == other.mPort) &&
((mInterface == INET_NULL_INTERFACEID) || (other.mInterface == INET_NULL_INTERFACEID) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this field should be matched exactly.

We shouldn't understand equality of addresses to mean "could these addresses send to the same destination" and we couldn't answer that question in general.

It should just mean "these addresses are identical", including zone identifier.

Weaker matches can be separate functions, not equality.

mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers), mPendingPacketsSize(packetsBuffersSize)
{
PendingPacket emptyPending{
.peerAddress = PeerAddress::Uninitialized(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason it compiles it's been a GNU extension for ages (and we've been compiling with GNU extensions).

@woody-apple
Copy link
Contributor

@saurabhst ?

@bzbarsky-apple
Copy link
Contributor

I wish we had some 'smart pointer' like constructs instead of raw pointers.

Yes, indeed. I filed #2707

VerifyOrExit(buffer->DataLength() >= messageSize, err = CHIP_ERROR_INTERNAL);

err = ProcessSingleMessageFromBufferHead(peerAddress, buffer, messageSize);
buffer->ConsumeHead(messageSize);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. It occurs to me: Should this call to ConsumeHead still happen even if ProcessSingleMessageFromBufferHead failed? We're about to push this buffer back to the endpoint, no? I would not think we want to consume data from it... Though maybe the idea is to push back only the data after the failed message? In that case that should be clearly documented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought to keep it because I alrady skipped over the size. If processsinglemessage fails on a buffer, there seems to be reasonable expectation that it will fail in the future as well. This also guarantees that we empty buffers in time.

I.e. I think this is correct and it would be more work to not consume on error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. That seems fine, but worth a comment explaining why we are doing what we are doing.

if (err != CHIP_NO_ERROR)
{
ChipLogError(Inet, "Connection complete encountered an error: %s", ErrorStr(err));
endPoint->Free();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with making the endpoint count stuff better in a followup. For now, file an issue and add a TODO comment at the member declaration pointing to the issue?

mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers), mPendingPacketsSize(packetsBuffersSize)
{
PendingPacket emptyPending{
.peerAddress = PeerAddress::Uninitialized(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's ok until someone complains that it doesn't compile for their hardware. ;)

uint16_t messageSize);

// Callback handler for TCPEndPoint. TCP message receive handler.
static void OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBuffer * buffer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably document ownership semantics too...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be handled by TCPEndPoint. That documents it as:

     *  A data reception event handler must acknowledge data processed using
     *  the \c AckReceive method. The \c Free method on the data buffer must
     *  also be invoked unless the \c PutBackReceivedData is used instead

I think we should not try to duplicate docs lest they become out of sync.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sounds good! Could add a pointer to the TCPEndPoint documentation from here.

@andy31415
Copy link
Contributor Author

Created #2708 for better active count usage.

@andy31415 andy31415 merged commit d1f0a37 into project-chip:master Sep 17, 2020
@andy31415 andy31415 deleted the 01_implement_tcp_transport branch October 9, 2020 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for TCP communication
6 participants