Support non-blocking accept()

This commit is contained in:
Kirigaya Kazuto 2018-09-10 01:35:48 +08:00
parent 0213119ad8
commit 014e216301
2 changed files with 151 additions and 11 deletions

132
gsock.cpp
View File

@ -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;

30
gsock.h
View File

@ -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;