Skip to content

IoSocketHandleImpl::close()#5171

Merged
mattklein123 merged 41 commits intoenvoyproxy:masterfrom
danzh2010:fdwrapperinterface
Feb 21, 2019
Merged

IoSocketHandleImpl::close()#5171
mattklein123 merged 41 commits intoenvoyproxy:masterfrom
danzh2010:fdwrapperinterface

Conversation

@danzh2010
Copy link
Copy Markdown
Contributor

@danzh2010 danzh2010 commented Nov 30, 2018

Implement IoSocketHandleImpl::close(). And replace the use of ::close(int fd) with it everywhere.
Risk Level: low.
Test: Rely on existing tests. If there are ::close(fd) left out, ~IoHandle() should have caused double close on same fd in tests.
Part of #4546 #2557

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>

Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010 danzh2010 force-pushed the fdwrapperinterface branch 2 times, most recently from c9a3af8 to 4b1c922 Compare November 30, 2018 21:47
@venilnoronha
Copy link
Copy Markdown
Member

/retest

@repokitteh-read-only
Copy link
Copy Markdown

🔨 rebuilding ci/circleci: ipv6_tests (failed build)

🐱

Caused by: a #5171 (comment) was created by @venilnoronha.

see: more, trace.

* @see man 2 connect
*/
virtual SysCallIntResult connect(int sockfd, const struct sockaddr* serv_addr,
socklen_t addrlen) PURE;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you plan to send in a follow-up PR that updates existing calls to ::getsockname, ::getpeername, ::connect, etc.?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Either me or @sbelair2 will do, but yes, there will be follow-up pr's to use IoHandle interface instead of operating on fd directly.

}

SysCallIntResult FdIoHandleImpl::getSocketName(sockaddr* addr, socklen_t* addr_len) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: remove extra line break.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done in io_socket_handle_impl.cc

namespace Envoy {
namespace Network {

class FdIoHandleImpl : public virtual IoHandle {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: I think we can skip the virtual keyword.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done in io_socket_handle_impl.cc

@mattklein123
Copy link
Copy Markdown
Member

@danzh2010 how does this relate to #5128? Is this a separate implementation? Can you please sync up with @sbelair2 to reconcile? I would like to only review a single sequence of changes on this topic. Thank you!

@mattklein123 mattklein123 self-assigned this Dec 1, 2018
@danzh2010
Copy link
Copy Markdown
Contributor Author

I originally mean to only send this PR to sbelair2 for discussion about the interface and the fd specific implementation. I think he can either merge mine into his current PR or submitting his as is and I can extend it with this one. We will definitely sync up on slack. Sorry for the confusion.

@jmarantz
Copy link
Copy Markdown
Contributor

jmarantz commented Dec 5, 2018

/sub

@danzh2010
Copy link
Copy Markdown
Contributor Author

I'm going on vacation for 4 weeks. How can I prevent this PR from becoming stale and closed?

@dnoe
Copy link
Copy Markdown
Contributor

dnoe commented Dec 12, 2018

You can just re-open it when you return, come back to this page and comment and click "Reopen and comment".

@sbelair2
Copy link
Copy Markdown
Contributor

sbelair2 commented Dec 12, 2018 via email

@jmarantz
Copy link
Copy Markdown
Contributor

I think only maintainers get a "re-open" button. But one of us can do that for you.

One concern I have with this family of PRs is that I feel a holistic design incorporating abstraction of libevent is needed. It is hard for me to evaluate any of these PRs if ultimately they still have to interface with libevent, which exposes FDs at the interface.

@mattklein123
Copy link
Copy Markdown
Member

@jmarantz I think we have a good handle on how to proceed re: libevent, at least in the short term. Let's chat offline. @sbelair2 I'm sorry you are having a hard time with unique_ptr. If you can't figure it out we can have someone take over the PR. Thanks!

IoHandlePtr FdIoHandleImpl::socket(int domain, int type, int protocol) {
SysCallIntResult result = Api::OsSysCallsSingleton::get().socket(domain, type, protocol);
RELEASE_ASSERT(result.rc_ != -1, "");
return IoHandlePtr(new FdIoHandleImpl(result.rc_));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

make_unique<>() would be easier on the eye.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done in io_socket_handle_impl.cc


Api::SysCallIntResult close() override;

bool isClosed() override;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

count be bool isClosed() const override;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Technically, most methods (all that do not change the fd_) could be marked const, but maybe should do so only on methods that do not modify the underlying socket.

Obviously this change should be made on the base class first.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done in io_socket_handle_impl.* and io_handle.h

@stale
Copy link
Copy Markdown

stale bot commented Dec 19, 2018

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label Dec 19, 2018
@stale
Copy link
Copy Markdown

stale bot commented Dec 27, 2018

This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot closed this Dec 27, 2018
@danzh2010 danzh2010 changed the title Add an IoHandle interface Extend IoHandle interface Jan 28, 2019
@danzh2010
Copy link
Copy Markdown
Contributor Author

/assign @sbelair2

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks I think this approach is great. A few small comments.

/wait

// frequent memory allocation of IoError instance.
// If this is used, IoHandleCallResult has to be instantiated with a deleter that does not
// deallocate memory for this error.
#define ENVOY_ERROR_AGAIN reinterpret_cast<IoError*>(1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Is it possible to use a constexpr here vs. a define?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

not done. constexpr doesn't like reinterpret_cast.

// Map platform specific error into IoErrorCode.
// Needed to hide errorCode() in case of ENVOY_ERROR_AGAIN.
static IoErrorCode getErrorCode(const IoError* err) {
ASSERT(err != nullptr);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Can we just make this function take a reference to avoid this assert? Same elsewhere in similar cases?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think *ENVOY_ERROR_AGAIN will cause crash.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It won't crash actually, from the computer perspective a pointer and reference are the same thing, it won't crash until you actually try to access the memory (I'm 99% sure). I would go ahead and switch to a reference assuming it works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right. I switched to use reference here.
If the caller try to dereference a nullptr, we will have seg fault. Is this more preferred than ASSERT?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah in general we prefer references for things that can't be null. In this case, I don't consider ENVOY_ERROR_AGAIN to be null.

IoError::IoErrorCode IoSocketError::errorCode() const {
switch (errno_) {
case EAGAIN:
RELEASE_ASSERT(false, "EAGAIN should use specific error ENVOY_ERROR_AGAIN");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we just swap with NOT_REACHED?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

const int rc = ::close(fd_);
fd_ = -1;
IoErrorPtr err(nullptr, deleteIoError);
if (rc == -1) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can this ever actually fail? It definitely can't return EAGAIN I don't think. Can we just RELEASE_ASSERT that is doesn't fail instead of having this code?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, it couldn't be EAGAIN for sure. But it can fail according t linux man.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it can only fail if passed a bad handle though, which should never happen. I would just RELEASE_ASSERT it personally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

RELEASE_ASSERT will fail test/common/network/connection_impl_test.cc because most of the io_handle objects in the test are initialized manually with invalid fd like 0 or 1.
I removed the if (rc == -1 ) block and return rc as is.

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

🔨 rebuilding ci/circleci: mac (failed build)

🐱

Caused by: a #5171 (comment) was created by @danzh2010.

see: more, trace.

@danzh2010
Copy link
Copy Markdown
Contributor Author

mac build failure: ERROR: /Users/distiller/project/test/common/upstream/BUILD:167:1: Linking of rule '//test/common/upstream:load_stats_reporter_test' failed (Exit 1) cc_wrapper.sh failed: error executing command ...
ld: not enough disk space for writing 'bazel-out/darwin-fastbuild/bin/test/common/upstream/load_stats_reporter_test' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation).

This seems unrelated to this PR

@mattklein123
Copy link
Copy Markdown
Member

@danzh2010 don't worry about it, but if you need more changes merge master and I think it will go away.

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

LGTM, let's see if we can shift pointers to references, if not we can ship! Thank you!

// Map platform specific error into IoErrorCode.
// Needed to hide errorCode() in case of ENVOY_ERROR_AGAIN.
static IoErrorCode getErrorCode(const IoError* err) {
ASSERT(err != nullptr);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It won't crash actually, from the computer perspective a pointer and reference are the same thing, it won't crash until you actually try to access the memory (I'm 99% sure). I would go ahead and switch to a reference assuming it works.

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Nice!

@mattklein123 mattklein123 merged commit b2149d1 into envoyproxy:master Feb 21, 2019
@danzh2010
Copy link
Copy Markdown
Contributor Author

I'm wondering if it might make sense to skip routing everything through os_sys_calls here, and just have the IoHandle implementations make the necessary syscalls directly. While it's fine here where the FdIoHandleImpl is wrapping an integer file descriptor, I think it may cause issues with a Windows implementation where the IoHandle is wrapping a SOCKET. Either os_sys_calls would have to be updated such that close / bind / connect etc. take the appropriate socket descriptor on each platform (int vs SOCKET), or the Windows IoHandle would just not use os_sys_calls, which could lead to drift down the line

This is hard to achieve in #6037, given that os_sys_calls is used by the caller, and the readv/writev interface already diverged from syscall's interface.

@sesmith177
Copy link
Copy Markdown
Member

I'm wondering if it might make sense to skip routing everything through os_sys_calls here, and just have the IoHandle implementations make the necessary syscalls directly. While it's fine here where the FdIoHandleImpl is wrapping an integer file descriptor, I think it may cause issues with a Windows implementation where the IoHandle is wrapping a SOCKET. Either os_sys_calls would have to be updated such that close / bind / connect etc. take the appropriate socket descriptor on each platform (int vs SOCKET), or the Windows IoHandle would just not use os_sys_calls, which could lead to drift down the line

This is hard to achieve in #6037, given that os_sys_calls is used by the caller, and the readv/writev interface already diverged from syscall's interface.

thanks, I'll take a look

cc @yaelharel

fredlas pushed a commit to fredlas/envoy that referenced this pull request Mar 5, 2019
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Fred Douglas <fredlas@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.