Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44b99c22 authored by Mark Salyzyn's avatar Mark Salyzyn
Browse files

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.

(cherry picked from commit d7ad4e40)

Change-Id: I70ab37d5c22b02804aa3b4dfb26cc9b75291f8b6
parent 23f04107
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
+50 −26
Original line number Diff line number Diff line
@@ -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,9 +170,10 @@ 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);
        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
@@ -181,8 +185,14 @@ void SocketListener::runListener() {
        } else if (!rc)
            continue;

        if (FD_ISSET(mCtrlPipe[0], &read_fds))
        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) {
            pendingList.erase(it);
            /* Process it, if false is returned, remove from list */
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

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);
                /* Remove our reference to the client */
                c->decRef();
        if (ret) {
            ret = c->decRef();
            if (wakeup) {
                char b = CtrlPipe_Wakeup;
                TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
            }
            c->decRef();
        }
    }
    delete pendingList;
    return ret;
}

void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {