diff options
Diffstat (limited to 'libsysutils/src')
-rw-r--r-- | libsysutils/src/NetlinkEvent.cpp | 12 | ||||
-rw-r--r-- | libsysutils/src/SocketClient.cpp | 84 | ||||
-rw-r--r-- | libsysutils/src/SocketListener.cpp | 84 |
3 files changed, 130 insertions, 50 deletions
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index c2ba647..86c1f42 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -93,13 +93,11 @@ bool NetlinkEvent::decode(char *buffer, int size) { } const char *NetlinkEvent::findParam(const char *paramName) { - int i; - - for (i = 0; i < NL_PARAMS_MAX; i++) { - if (!mParams[i]) - break; - if (!strncmp(mParams[i], paramName, strlen(paramName))) - return &mParams[i][strlen(paramName) + 1]; + size_t len = strlen(paramName); + for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) { + const char *ptr = mParams[i] + len; + if (!strncmp(mParams[i], paramName, len) && *ptr == '=') + return ++ptr; } SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index 8e5f154..90ca52e 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -15,8 +15,10 @@ SocketClient::SocketClient(int socket) , mPid(-1) , mUid(-1) , mGid(-1) + , mRefCount(1) { pthread_mutex_init(&mWriteMutex, NULL); + pthread_mutex_init(&mRefCountMutex, NULL); struct ucred creds; socklen_t szCreds = sizeof(creds); @@ -32,14 +34,24 @@ SocketClient::SocketClient(int socket) int SocketClient::sendMsg(int code, const char *msg, bool addErrno) { char *buf; + const char* arg; + const char* fmt; + char tmp[1]; + int len; if (addErrno) { - buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8); - sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno)); + fmt = "%.3d %s (%s)"; + arg = strerror(errno); } else { - buf = (char *) alloca(strlen(msg) + strlen("XXX ")); - sprintf(buf, "%.3d %s", code, msg); + fmt = "%.3d %s"; + arg = NULL; } + /* Measure length of required buffer */ + len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg); + /* Allocate in the stack, then write to it */ + buf = (char*)alloca(len+1); + snprintf(buf, len+1, fmt, code, msg, arg); + /* Send the zero-terminated message */ return sendMsg(buf); } @@ -50,25 +62,65 @@ int SocketClient::sendMsg(const char *msg) { } // Send the message including null character + if (sendData(msg, strlen(msg) + 1) != 0) { + SLOGW("Unable to send msg '%s'", msg); + return -1; + } + return 0; +} + +int SocketClient::sendData(const void* data, int len) { int rc = 0; - const char *p = msg; - int brtw = strlen(msg) + 1; + const char *p = (const char*) data; + int brtw = len; + + if (len == 0) { + return 0; + } pthread_mutex_lock(&mWriteMutex); - while(brtw) { - if ((rc = write(mSocket,p, brtw)) < 0) { - SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno)); - pthread_mutex_unlock(&mWriteMutex); - return -1; - } else if (!rc) { + while (brtw > 0) { + rc = write(mSocket, p, brtw); + if (rc > 0) { + p += rc; + brtw -= rc; + continue; + } + + if (rc < 0 && errno == EINTR) + continue; + + pthread_mutex_unlock(&mWriteMutex); + if (rc == 0) { SLOGW("0 length write :("); errno = EIO; - pthread_mutex_unlock(&mWriteMutex); - return -1; + } else { + SLOGW("write error (%s)", strerror(errno)); } - p += rc; - brtw -= rc; + return -1; } pthread_mutex_unlock(&mWriteMutex); return 0; } + +void SocketClient::incRef() { + pthread_mutex_lock(&mRefCountMutex); + mRefCount++; + pthread_mutex_unlock(&mRefCountMutex); +} + +bool SocketClient::decRef() { + bool deleteSelf = false; + pthread_mutex_lock(&mRefCountMutex); + mRefCount--; + if (mRefCount == 0) { + deleteSelf = true; + } else if (mRefCount < 0) { + SLOGE("SocketClient refcount went negative!"); + } + pthread_mutex_unlock(&mRefCountMutex); + if (deleteSelf) { + delete this; + } + return deleteSelf; +} diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index 1bc06db..fcad624 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -54,8 +54,8 @@ SocketListener::~SocketListener() { close(mCtrlPipe[1]); } SocketClientCollection::iterator it; - for (it = mClients->begin(); it != mClients->end(); ++it) { - delete (*it); + for (it = mClients->begin(); it != mClients->end();) { + (*it)->decRef(); it = mClients->erase(it); } delete mClients; @@ -96,8 +96,10 @@ int SocketListener::startListener() { int SocketListener::stopListener() { char c = 0; + int rc; - if (write(mCtrlPipe[1], &c, 1) != 1) { + rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1)); + if (rc != 1) { SLOGE("Error writing to control pipe (%s)", strerror(errno)); return -1; } @@ -118,7 +120,7 @@ int SocketListener::stopListener() { } SocketClientCollection::iterator it; - for (it = mClients->begin(); it != mClients->end(); ++it) { + for (it = mClients->begin(); it != mClients->end();) { delete (*it); it = mClients->erase(it); } @@ -135,11 +137,13 @@ void *SocketListener::threadStart(void *obj) { void SocketListener::runListener() { + SocketClientCollection *pendingList = new SocketClientCollection(); + while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; - int max = 0; + int max = -1; FD_ZERO(&read_fds); @@ -154,13 +158,16 @@ void SocketListener::runListener() { pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { - FD_SET((*it)->getSocket(), &read_fds); - if ((*it)->getSocket() > max) - max = (*it)->getSocket(); + int fd = (*it)->getSocket(); + FD_SET(fd, &read_fds); + if (fd > max) + max = fd; } pthread_mutex_unlock(&mClientsLock); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { + if (errno == EINTR) + continue; SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; @@ -171,10 +178,14 @@ void SocketListener::runListener() { break; if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; - socklen_t alen = sizeof(addr); + socklen_t alen; int c; - if ((c = accept(mSock, &addr, &alen)) < 0) { + do { + alen = sizeof(addr); + c = accept(mSock, &addr, &alen); + } while (c < 0 && errno == EINTR); + if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; @@ -184,27 +195,46 @@ void SocketListener::runListener() { pthread_mutex_unlock(&mClientsLock); } - do { - pthread_mutex_lock(&mClientsLock); - for (it = mClients->begin(); it != mClients->end(); ++it) { - int fd = (*it)->getSocket(); - if (FD_ISSET(fd, &read_fds)) { - pthread_mutex_unlock(&mClientsLock); - if (!onDataAvailable(*it)) { - close(fd); - pthread_mutex_lock(&mClientsLock); - delete *it; - it = mClients->erase(it); - pthread_mutex_unlock(&mClientsLock); + /* Add all active clients to the pending list first */ + pendingList->clear(); + pthread_mutex_lock(&mClientsLock); + for (it = mClients->begin(); it != mClients->end(); ++it) { + int fd = (*it)->getSocket(); + if (FD_ISSET(fd, &read_fds)) { + pendingList->push_back(*it); + } + } + pthread_mutex_unlock(&mClientsLock); + + /* Process the pending list, since it is owned by the thread, + * there is no need to lock it */ + while (!pendingList->empty()) { + /* Pop the first item from the list */ + 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 */ + pthread_mutex_lock(&mClientsLock); + for (it = mClients->begin(); it != mClients->end(); ++it) { + if (*it == c) { + mClients->erase(it); + break; } - FD_CLR(fd, &read_fds); - pthread_mutex_lock(&mClientsLock); - continue; + } + pthread_mutex_unlock(&mClientsLock); + /* Destroy the client */ + int socket = c->getSocket(); + if (c->decRef()) { + // Note: 'c' is deleted memory at this point. + close(socket); } } - pthread_mutex_unlock(&mClientsLock); - } while (0); + } } + delete pendingList; } void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { |