THRIFT-3080: fix connection leak of C++ Nonblocking Server while huge number connections are accepted and unix socket stream fd is busy.
Project: http://git-wip-us.apache.org/repos/asf/thrift/repo Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/38772c9c Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/38772c9c Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/38772c9c Branch: refs/heads/master Commit: 38772c9c8d2eeb43fcf11ff2bff7729b8d76f431 Parents: 9226590 Author: abadcafe <[email protected]> Authored: Fri Apr 3 22:23:04 2015 +0800 Committer: Roger Meier <[email protected]> Committed: Tue Apr 7 22:38:25 2015 +0200 ---------------------------------------------------------------------- .../src/thrift/server/TNonblockingServer.cpp | 37 ++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/thrift/blob/38772c9c/lib/cpp/src/thrift/server/TNonblockingServer.cpp ---------------------------------------------------------------------- diff --git a/lib/cpp/src/thrift/server/TNonblockingServer.cpp b/lib/cpp/src/thrift/server/TNonblockingServer.cpp index 587560c..31bc34b 100644 --- a/lib/cpp/src/thrift/server/TNonblockingServer.cpp +++ b/lib/cpp/src/thrift/server/TNonblockingServer.cpp @@ -28,6 +28,7 @@ #include <thrift/transport/PlatformSocket.h> #include <iostream> +#include <poll.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> @@ -1393,9 +1394,39 @@ bool TNonblockingIOThread::notify(TNonblockingServer::TConnection* conn) { return false; } - const int kSize = sizeof(conn); - if (send(fd, const_cast_sockopt(&conn), kSize, 0) != kSize) { - return false; + int ret = -1; + struct pollfd pfd = {fd, POLLOUT, 0}; + int kSize = sizeof(conn); + const char * pos = (const char *)const_cast_sockopt(&conn); + + while (kSize > 0) { + pfd.revents = 0; + ret = poll(&pfd, 1, -1); + if (ret < 0) { + return false; + } else if (ret == 0) { + continue; + } + + if (pfd.revents & POLLHUP || pfd.revents & POLLERR) { + ::close(fd); + return false; + } + + if (pfd.revents & POLLOUT) { + ret = send(fd, pos, kSize, 0); + if (ret < 0) { + if (errno == EAGAIN) { + continue; + } + + ::close(fd); + return false; + } + + kSize -= ret; + pos += ret; + } } return true;
