TCP, UNIX sockets: allow multiple calls to listen

* Subsequent calls to listen on an already-listening socket can resize
  the backlog.
* While not explicitly spelled out by POSIX, this behaviour is
  consistent with FreeBSD and Linux.
This commit is contained in:
Hamish Morrison
2015-01-17 19:51:16 +00:00
parent ba483af7de
commit 64f6fcbccd
2 changed files with 27 additions and 22 deletions
@@ -728,18 +728,20 @@ TCPEndpoint::Listen(int count)
MutexLocker _(fLock); MutexLocker _(fLock);
if (fState != CLOSED) if (fState != CLOSED && fState != LISTEN)
return B_BAD_VALUE; return B_BAD_VALUE;
fAcceptSemaphore = create_sem(0, "tcp accept"); if (fState == CLOSED) {
if (fAcceptSemaphore < B_OK) fAcceptSemaphore = create_sem(0, "tcp accept");
return ENOBUFS; if (fAcceptSemaphore < B_OK)
return ENOBUFS;
status_t status = fManager->SetPassive(this);
if (status != B_OK) { status_t status = fManager->SetPassive(this);
delete_sem(fAcceptSemaphore); if (status != B_OK) {
fAcceptSemaphore = -1; delete_sem(fAcceptSemaphore);
return status; fAcceptSemaphore = -1;
return status;
}
} }
gSocketModule->set_max_backlog(socket, count); gSocketModule->set_max_backlog(socket, count);
@@ -239,22 +239,25 @@ UnixEndpoint::Listen(int backlog)
if (!IsBound()) if (!IsBound())
RETURN_ERROR(EDESTADDRREQ); RETURN_ERROR(EDESTADDRREQ);
if (fState != UNIX_ENDPOINT_NOT_CONNECTED) if (fState != UNIX_ENDPOINT_NOT_CONNECTED
&& fState != UNIX_ENDPOINT_LISTENING)
RETURN_ERROR(EINVAL); RETURN_ERROR(EINVAL);
gSocketModule->set_max_backlog(socket, backlog); gSocketModule->set_max_backlog(socket, backlog);
fAcceptSemaphore = create_sem(0, "unix accept"); if (fState == UNIX_ENDPOINT_NOT_CONNECTED) {
if (fAcceptSemaphore < 0) fAcceptSemaphore = create_sem(0, "unix accept");
RETURN_ERROR(ENOBUFS); if (fAcceptSemaphore < 0)
RETURN_ERROR(ENOBUFS);
_UnsetReceiveFifo();
_UnsetReceiveFifo();
fCredentials.pid = getpid();
fCredentials.uid = geteuid(); fCredentials.pid = getpid();
fCredentials.gid = getegid(); fCredentials.uid = geteuid();
fCredentials.gid = getegid();
fState = UNIX_ENDPOINT_LISTENING;
fState = UNIX_ENDPOINT_LISTENING;
}
RETURN_ERROR(B_OK); RETURN_ERROR(B_OK);
} }