From 014e216301a2acc7edcd300cafeccff3b74ba9d2 Mon Sep 17 00:00:00 2001 From: Kiritow <1362050620@qq.com> Date: Mon, 10 Sep 2018 01:35:48 +0800 Subject: [PATCH] Support non-blocking accept() --- gsock.cpp | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++--- gsock.h | 30 +++++++++++-- 2 files changed, 151 insertions(+), 11 deletions(-) diff --git a/gsock.cpp b/gsock.cpp index 0ebacfc..d5323bb 100644 --- a/gsock.cpp +++ b/gsock.cpp @@ -372,7 +372,7 @@ struct NBConnectResult::_impl // 3: finished, failed. int status; - int errcode; + gerrno errcode; void update(); }; @@ -429,12 +429,12 @@ bool NBConnectResult::isFinished() return (_p->status > 1); } -bool NBConnectResult::isConnected() +bool NBConnectResult::isSuccess() { return (_p->status == 2); } -int NBConnectResult::getErrCode() +gerrno NBConnectResult::getErrCode() { return _p->errcode; } @@ -650,7 +650,7 @@ NBConnectResult sock::connect_nb(const std::string& IPStr, int Port) { // Failed. res._p->status = 3; - res._p->errcode = GSOCK_INVALID_IP; + res._p->errcode = (gerrno)GSOCK_INVALID_IP; return res; } res._p->saddr6.sin6_port = htons(Port); @@ -668,7 +668,7 @@ NBConnectResult sock::connect_nb(const std::string& IPStr, int Port) { // Failed. res._p->status = 3; - res._p->errcode = GSOCK_INVALID_IP; + res._p->errcode = (gerrno)GSOCK_INVALID_IP; return res; } res._p->saddr.sin_port = htons(Port); @@ -687,11 +687,11 @@ NBConnectResult sock::connect_nb(const std::string& IPStr, int Port) { res._p->status = 1; } - else + else // xret is a GSock error { // Failed res._p->status = 3; - res._p->errcode = xret; + res._p->errcode = (gerrno)xret; } return res; } @@ -1000,6 +1000,93 @@ int serversock::listen(int MaxCount) return ::listen(_vp->sfd,MaxCount); } +struct NBAcceptResult::_impl +{ + int sfd; + + // For client use + bool isv4; + sockaddr_in saddr; + sockaddr_in6 saddr6; + socklen_t saddrsz; + + sock* out_binding; + int* out_binding_sfd; + bool* out_binding_created; + + // 0 Not started. + // 1 Accepting + // 2 Accept success. + // 3 Accept failed. + int status; + gerrno errcode; + + void update(); +}; + +void NBAcceptResult::_impl::update() +{ + if (status > 1) return; + + int ret; + if (isv4) + { + ret = accept(sfd, (sockaddr*)&saddr, &saddrsz); + } + else + { + ret = accept(sfd, (sockaddr*)&saddr6, &saddrsz); + } + + if (ret >= 0) + { + *out_binding_sfd = sfd; + *out_binding_created = true; + status = 2; + } + else // ret == -1 + { + gerrno err = TranslateNativeErrToGErr(GetNativeErrCode()); + errcode = err; + if (err == gerrno::InProgress || err == gerrno::WouldBlock || err == gerrno::Already) + { + status = 1; + } + else + { + status = 3; + } + } + + myliblog("NBAcceptResult status updated to %d\n", status); +} + +NBAcceptResult::NBAcceptResult() : _sp(new _impl) +{ + _sp->status = 0; +} + +bool NBAcceptResult::isFinished() +{ + _sp->update(); + return (_sp->status > 1); +} + +bool NBAcceptResult::isSuccess() +{ + return (_sp->status == 2); +} + +sock& NBAcceptResult::get() +{ + return *(_sp->out_binding); +} + +gerrno NBAcceptResult::getErrCode() +{ + return _sp->errcode; +} + int serversock::accept(sock& _out_s) { if( (!_vp->created) || (_out_s._vp->created) ) @@ -1043,6 +1130,37 @@ int serversock::accept(sock& _out_s) } } +NBAcceptResult serversock::accept_nb(sock& _out_s) +{ + NBAcceptResult res; + if ((!_vp->created) || (_out_s._vp->created)) + { + /// _out_s has been connected. + res._sp->status = 3; + res._sp->errcode = (gerrno)GSOCK_INVALID_SOCKET; + return res; + } + + res._sp->sfd = _vp->sfd; + res._sp->out_binding = &_out_s; + res._sp->out_binding_sfd = &(_out_s._vp->sfd); + res._sp->out_binding_created = &(_out_s._vp->created); + if (_pp->protocol == AF_INET) + { + res._sp->isv4 = true; + res._sp->saddrsz = sizeof(res._sp->saddr); + res._sp->update(); + } + else + { + res._sp->isv4 = false; + res._sp->saddrsz = sizeof(res._sp->saddr6); + res._sp->update(); + } + + return res; +} + struct udpsock::_impl { int protocol; diff --git a/gsock.h b/gsock.h index 15e171e..52dd537 100644 --- a/gsock.h +++ b/gsock.h @@ -29,11 +29,11 @@ enum }; // Internal Socket Call Errcode +// Values of all errors are positive number. enum gerrno { - UnknownError = -1, OK = 0, - // Values of all known errors are positive number. + UnknownError, WouldBlock, InProgress, Already, @@ -78,9 +78,9 @@ public: bool isFinished(); // Wait until the connection is finished. (via while loop) void wait(); - bool isConnected(); + bool isSuccess(); // ErrCode is only usable when the connection is finished and failed. - int getErrCode(); + gerrno getErrCode(); private: struct _impl; std::shared_ptr<_impl> _p; @@ -179,6 +179,24 @@ private: struct _impl; }; +class NBAcceptResult +{ +public: + NBAcceptResult(); + + bool isFinished(); + bool isSuccess(); + + sock& get(); + + gerrno getErrCode(); +private: + struct _impl; + std::shared_ptr<_impl> _sp; + + friend class serversock; +}; + class serversock : public vsock { public: @@ -189,6 +207,7 @@ public: serversock(int use_family=0); ~serversock(); + // Notice that bind() should be called before setNonblocking() // Return: // GSOCK_OK: Bind Succeed. No Error. // GSOCK_API_ERROR: bind() call error. See errno. @@ -202,6 +221,7 @@ public: // GSOCK_API_ERROR: setsockopt() call error. int set_reuse(); + // Notice that listen() should be called before setNonblocking() // Return: // GSOCK_OK // GSOCK_API_ERROR: listen() call error. @@ -213,6 +233,8 @@ public: // GSOCK_API_ERROR: accept() call error. See errno. // GSOCK_INVALID_SOCKET: _out_s is not an empty socket, which should not be passed in. int accept(sock& _out_s); + // Notice that bind() and listen() should be called before setNonBlocking() + NBAcceptResult accept_nb(sock& _out_s); private: struct _impl; _impl* _pp;