-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Refactor Drv::Ip::UdpSocket to clean up state members and remove dependency on dynamic memory #3728
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
Conversation
…argument validation. Adding some better logging.
LeStarch
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot more here than I expected. Also, it seems that many asserts have been changed to if-checks. The general rule is:
- If it is clearly a coding error, assert. (e.g. a char* was passed in as nullptr, or
bindwas called beforeopen) - Use an
ifto check for things that could be a error with the run.
Drv/Ip/UdpSocket.hpp
Outdated
| #ifdef TGT_OS_TYPE_VXWORKS | ||
| #include <socket.h> | ||
| #include <inetLib.h> | ||
| #elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should just have the else clause and VXWORKS. Most patforms will put the headers as UNIX does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move the #include for linux/darwin into else?
LeStarch
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few more cleanup items.
Drv/Ip/UdpSocket.hpp
Outdated
| #ifdef TGT_OS_TYPE_VXWORKS | ||
| #include <socket.h> | ||
| #include <inetLib.h> | ||
| #elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move the #include for linux/darwin into else?
…ementation of send and recv to properly handle 0-length datagrams
|
@LeStarch The latest check-ins include a fix for a latent bug in the UdpSocket implementation for the handling of 0-length datagrams that you pointed out. Due to UDP supporting 0-length data and TCP not technically supporting 0-length data it required a little bit more refactoring to properly detangle the send/recv implementation in IpSocket and allow UdpSocket to override these commands. |
Drv/Ip/test/ut/TestUdp.cpp
Outdated
| ASSERT_EQ(receiver.configureRecv("127.0.0.1", port), Drv::SOCK_SUCCESS); | ||
| ASSERT_EQ(receiver.open(recv_fd), Drv::SOCK_SUCCESS); | ||
|
|
||
| // Set a custom, longer receive timeout for this specific test to 500ms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious as to why....
Drv/Ip/test/ut/SocketTestHelper.cpp
Outdated
|
|
||
| if (status == Drv::SOCK_SUCCESS) { | ||
| received_size += bytes_actually_received; | ||
| } else if (status == Drv::SOCK_NO_DATA_AVAILABLE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of this method is to wait (even if no data is available) until such a time as the whole message received (in that the message might span multiple timeouts).
Thus I am confused why this is being commuted to a failure.
Drv/Ip/IpSocket.cpp
Outdated
| return SOCK_NO_DATA_AVAILABLE; | ||
| } else if (errno == EINTR) { | ||
| // Interrupted system call. Retry if not the last iteration. | ||
| if (i == (SOCKET_MAX_ITERATIONS - 1)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doe we need both this and the check at the end? Can't we just continue again?
| } | ||
|
|
||
| SocketIpStatus UdpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) { | ||
| // Note: socketDescriptor.fd can be -1 in some test cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? How could this ever be -1?
| return received; | ||
| } | ||
|
|
||
| SocketIpStatus UdpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a special send? Can we not just update the send method on the IpSocket?
It seems odd that:
- We fixed asserts in the send in IpSocket to allow size==0, but also override the method
recvis updated to respect 0 length, in Ip, but send is done in UDP.
| // Nothing to be received | ||
| if ((size == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) { | ||
| // Loop primarily for EINTR. Other conditions should lead to an earlier exit. | ||
| for (U32 i = 0; i < SOCKET_MAX_ITERATIONS; i++) { |
Check warning
Code scanning / CodeQL
Comparison result is always the same Warning
| SocketIpStatus IpSocket::handleZeroReturn() { | ||
| // For TCP (which IpSocket primarily serves as a base for, or when not overridden), | ||
| // a return of 0 from ::recv means the peer has performed an orderly shutdown. | ||
| return SOCK_DISCONNECTED; |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
| } | ||
|
|
||
| // For non-zero-length data, delegate to the base class implementation | ||
| return IpSocket::send(socketDescriptor, data, size); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
| } | ||
|
|
||
| // For non-zero-length data, delegate to the base class implementation | ||
| return IpSocket::send(socketDescriptor, data, size); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
LeStarch
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to understand this comment
//TODO: Uncomment FW_ASSERT for socketDescriptor.fd once we fix TcpClientTester to not pass in uninitialized socketDescriptor
Change Description
This change cleans up Drv::Ip::UdpSocket to remove the members
m_state,m_recv_port, andm_recv_hostnamein favour of two new membersm_addr_sendandm_addr_recv. As part of this change we are also removing the dependency on dynamic memory for storing state.This change also improved error handling, edge case handling, and memory safety.
Rationale
Simplifies code and fixes bug of having duplicate data structures storing the same state.
Testing/Review Recommendations
Existing UTs cover the changes made except for handling 0-length datagrams. A new UT was added specifically to test the behaviour of 0-length datagrams.
Future Work
None