libsysutils: SocketListener export release
* Foreground thread (legacy) closes connection by reporting false return value for onDataAvailable. * Background thread can choose instead to close the connection asynchronously by calling release, must return true for the onDataAvailable method. Change-Id: I70ab37d5c22b02804aa3b4dfb26cc9b75291f8b6
This commit is contained in:
parent
a6e965578e
commit
d7ad4e409e
|
@ -44,10 +44,13 @@ public:
|
|||
|
||||
void runOnEachSocket(SocketClientCommand *command);
|
||||
|
||||
bool release(SocketClient *c) { return release(c, true); }
|
||||
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient *c) = 0;
|
||||
|
||||
private:
|
||||
bool release(SocketClient *c, bool wakeup);
|
||||
static void *threadStart(void *obj);
|
||||
void runListener();
|
||||
void init(const char *socketName, int socketFd, bool listen, bool useCmdNum);
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include <sysutils/SocketListener.h>
|
||||
#include <sysutils/SocketClient.h>
|
||||
|
||||
#define CtrlPipe_Shutdown 0
|
||||
#define CtrlPipe_Wakeup 1
|
||||
|
||||
SocketListener::SocketListener(const char *socketName, bool listen) {
|
||||
init(socketName, -1, listen, false);
|
||||
}
|
||||
|
@ -101,7 +104,7 @@ int SocketListener::startListener() {
|
|||
}
|
||||
|
||||
int SocketListener::stopListener() {
|
||||
char c = 0;
|
||||
char c = CtrlPipe_Shutdown;
|
||||
int rc;
|
||||
|
||||
rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
|
||||
|
@ -143,7 +146,7 @@ void *SocketListener::threadStart(void *obj) {
|
|||
|
||||
void SocketListener::runListener() {
|
||||
|
||||
SocketClientCollection *pendingList = new SocketClientCollection();
|
||||
SocketClientCollection pendingList;
|
||||
|
||||
while(1) {
|
||||
SocketClientCollection::iterator it;
|
||||
|
@ -167,8 +170,9 @@ void SocketListener::runListener() {
|
|||
// NB: calling out to an other object with mClientsLock held (safe)
|
||||
int fd = (*it)->getSocket();
|
||||
FD_SET(fd, &read_fds);
|
||||
if (fd > max)
|
||||
if (fd > max) {
|
||||
max = fd;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mClientsLock);
|
||||
SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
|
||||
|
@ -181,8 +185,14 @@ void SocketListener::runListener() {
|
|||
} else if (!rc)
|
||||
continue;
|
||||
|
||||
if (FD_ISSET(mCtrlPipe[0], &read_fds))
|
||||
break;
|
||||
if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
|
||||
char c = CtrlPipe_Shutdown;
|
||||
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
|
||||
if (c == CtrlPipe_Shutdown) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mListen && FD_ISSET(mSock, &read_fds)) {
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
|
@ -204,14 +214,14 @@ void SocketListener::runListener() {
|
|||
}
|
||||
|
||||
/* Add all active clients to the pending list first */
|
||||
pendingList->clear();
|
||||
pendingList.clear();
|
||||
pthread_mutex_lock(&mClientsLock);
|
||||
for (it = mClients->begin(); it != mClients->end(); ++it) {
|
||||
SocketClient* c = *it;
|
||||
// NB: calling out to an other object with mClientsLock held (safe)
|
||||
int fd = c->getSocket();
|
||||
if (FD_ISSET(fd, &read_fds)) {
|
||||
pendingList->push_back(c);
|
||||
pendingList.push_back(c);
|
||||
c->incRef();
|
||||
}
|
||||
}
|
||||
|
@ -219,31 +229,45 @@ void SocketListener::runListener() {
|
|||
|
||||
/* Process the pending list, since it is owned by the thread,
|
||||
* there is no need to lock it */
|
||||
while (!pendingList->empty()) {
|
||||
while (!pendingList.empty()) {
|
||||
/* Pop the first item from the list */
|
||||
it = pendingList->begin();
|
||||
it = pendingList.begin();
|
||||
SocketClient* c = *it;
|
||||
pendingList->erase(it);
|
||||
/* Process it, if false is returned and our sockets are
|
||||
* connection-based, remove and destroy it */
|
||||
if (!onDataAvailable(c) && mListen) {
|
||||
/* Remove the client from our array */
|
||||
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
|
||||
pthread_mutex_lock(&mClientsLock);
|
||||
for (it = mClients->begin(); it != mClients->end(); ++it) {
|
||||
if (*it == c) {
|
||||
mClients->erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mClientsLock);
|
||||
/* Remove our reference to the client */
|
||||
c->decRef();
|
||||
pendingList.erase(it);
|
||||
/* Process it, if false is returned, remove from list */
|
||||
if (!onDataAvailable(c)) {
|
||||
release(c, false);
|
||||
}
|
||||
c->decRef();
|
||||
}
|
||||
}
|
||||
delete pendingList;
|
||||
}
|
||||
|
||||
bool SocketListener::release(SocketClient* c, bool wakeup) {
|
||||
bool ret = false;
|
||||
/* if our sockets are connection-based, remove and destroy it */
|
||||
if (mListen && c) {
|
||||
/* Remove the client from our array */
|
||||
SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
|
||||
pthread_mutex_lock(&mClientsLock);
|
||||
SocketClientCollection::iterator it;
|
||||
for (it = mClients->begin(); it != mClients->end(); ++it) {
|
||||
if (*it == c) {
|
||||
mClients->erase(it);
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mClientsLock);
|
||||
if (ret) {
|
||||
ret = c->decRef();
|
||||
if (wakeup) {
|
||||
char b = CtrlPipe_Wakeup;
|
||||
TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
|
||||
|
|
Loading…
Reference in New Issue