-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
syscall: refactor address APIs for deeper errno latching #3897
syscall: refactor address APIs for deeper errno latching #3897
Conversation
The errno set by a syscall can be overwritten by code (e.g. logging) as it propagates up through the call stack. This commit refactors the bind and connect methods in the address API to allow for returning the errno from deeper down the call stack i.e. as soon as a syscall is performed. Signed-off-by: Venil Noronha <veniln@vmware.com>
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.
Cool - safer and safer :-)
test/test_common/network_utility.cc
Outdated
if (fd < 0) { | ||
err = errno; |
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 think it'd be nice to have socket return a tuple for consistency.
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.
Will do.
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.
Addressed in 6c65b13.
This commit ensures that address implementations return the errno along with the file descriptor in socket method calls. Signed-off-by: Venil Noronha <veniln@vmware.com>
include/envoy/network/address.h
Outdated
*/ | ||
virtual int bind(int fd) const PURE; | ||
virtual std::tuple<int, int> bind(int fd) const PURE; |
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.
would absl::optional be a better return type? (ditto for connect)
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.
@alyssawilk thoughts?
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.
Would it be better to have a custom type with rc
(or fd
) and the errno
instead? Or, maybe, a generic for the first value?
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 would prefer a struct
for socket
rather than a tuple, it is clearer which field is fd or errno.
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.
+1 for a struct instead of tuple, for all of these.
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.
Single struct
or multiple? As, the returned values could be rc
or fd
depending on the call.
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 think a single struct is fine, with members rc
and errno
. It's always up to the caller to know what the function is returning and how to interpret it.
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.
Will do.
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.
Addressed in 36c81e5.
This commit adds a struct named Result which holds the rc and errno values resulting from a syscall. Also, the address API is refactored to use the new Result struct instead of std::tuple<int, int>. Signed-off-by: Venil Noronha <veniln@vmware.com>
include/envoy/network/address.h
Outdated
/** | ||
* The return code from the system call. | ||
*/ | ||
int rc; |
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.
Struct/Class member variables have a _ postfix (e.g., int foo_;).
https://github.com/envoyproxy/envoy/blob/master/STYLE.md
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.
Addressed in bb2841e.
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.
Thanks for switching this over to a struct. I prefer this also.
include/envoy/network/address.h
Outdated
/** | ||
* Result holds the rc and errno values resulting from a system call. | ||
*/ | ||
struct Result { |
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.
Q: Is this really address specific? Should we potentially put this in https://github.com/envoyproxy/envoy/blob/master/include/envoy/api/os_sys_calls.h as SyscalResult or something like that? I don't feel that strongly but throwing it out there.
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.
That makes perfect sense. I wanted to use this struct
in other places (buffer
, etc.) anyway.
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.
Addressed in bb2841e.
Result Ipv4Instance::bind(int fd) const { | ||
return {::bind(fd, reinterpret_cast<const sockaddr*>(&ip_.ipv4_.address_), | ||
sizeof(ip_.ipv4_.address_)), | ||
errno}; |
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.
It's quite possible that C++ guarantees that the ::bind call happens first, and then errno is captured, but TBH it's not very obvious to me that is the case. I would prefer that we do the call into a local variable and then return the result and errno. Same elsewhere. Thoughts?
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.
You're right. The c++14 documentation states:
The order of evaluation of function arguments is unspecified.
I'll fix this.
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.
@venilnoronha You're referring to function arguments, but this is list-initialization, and C++14 guarantees the order:
https://timsong-cpp.github.io/cppwp/n4140/dcl.init.list#4
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), are evaluated in the order in which they appear.
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.
@lizan my bad, I just realized that we switched over to a struct
. Thanks for sharing!
I think I'd still have it explicit, at least for readability.
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.
Addressed in 7e05d55.
* Fixes struct styling * Moves address/Result to os_sys_calls/SysCallResult Signed-off-by: Venil Noronha <veniln@vmware.com>
737eabf
to
bb2841e
Compare
Signed-off-by: Venil Noronha <veniln@vmware.com>
@@ -168,7 +168,7 @@ int InstanceBase::socketFromSocketType(SocketType socketType) const { | |||
RELEASE_ASSERT(fcntl(fd, F_SETFL, O_NONBLOCK) != -1, ""); | |||
#endif | |||
|
|||
return fd; | |||
return {fd, errno}; |
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.
In the __APPLE__
case, I think that fcntl could be resetting errno, so you need to latch it earlier.
On the other hand, there's already a RELEASE_ASSERT that an error did not occur (fd != -1). So should this function even return errno?
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.
@ggreenway good catch! What do you suggest? Should we still keep the function return type as Api::SysCallResult
for consistency, and to provide a way for future error handling?
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'd say leave this function as returning an int, and make sure the docs mention that this will never fail.
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.
Addressed in dc0c613.
RELEASE_ASSERT statements in the socket implementation ensure that the routine returns only on success. This commit does the following: * Revert function return type to int * Update socket documentation * Remove redundant error handling Signed-off-by: Venil Noronha <veniln@vmware.com>
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.
LGTM, nice. Will defer to @ggreenway for final review.
@@ -551,10 +551,10 @@ ClientConnectionImpl::ClientConnectionImpl( | |||
} | |||
|
|||
if (source_address != nullptr) { | |||
const int rc = source_address->bind(fd()); | |||
if (rc < 0) { | |||
Api::SysCallResult result = source_address->bind(fd()); |
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.
nit: result here and below can be const.
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.
Addressed in 42d0771.
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.
This is looking good. After fixing the one small comment from me, and the one from Matt, I think this is ready.
@@ -23,7 +23,7 @@ Writer::Writer(Network::Address::InstanceConstSharedPtr address) { | |||
fd_ = address->socket(Network::Address::SocketType::Datagram); | |||
ASSERT(fd_ != -1); | |||
|
|||
int rc = address->connect(fd_); | |||
const int rc = address->connect(fd_).rc_; |
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'd prefer to keep the SysCallResult instead of an int, so that if the assert fires in a test it's easier in a debugger to see the value of errno.
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.
Addressed in 42d0771.
* Use const Api::SysCallResult in connection_impl.cc * Capture result value in place of rc_ for better debugging Signed-off-by: Venil Noronha <veniln@vmware.com>
@mattklein123 @ggreenway @alyssawilk @lizan thanks for reviewing/merging! |
Description:
The
errno
set by a syscall can be overwritten by code (e.g. logging) as it propagates up through the call stack. This PR refactors thebind
,connect
andsocket
methods in theaddress
API to allow for returning theerrno
from deeper down the call stack i.e. as soon as a syscall is performed. See #3819 for more information.Signed-off-by: Venil Noronha veniln@vmware.com
Risk Level: Low
Testing: Existing tests suffice
Docs Changes: N/A
Release Notes: N/A
/cc @alyssawilk @mattklein123