SocketListener.cpp revision dc58e73071aa829a5038caf37211f6b3e2d7b275
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#include <stdio.h> 17#include <errno.h> 18#include <stdlib.h> 19#include <sys/socket.h> 20#include <sys/select.h> 21#include <sys/time.h> 22#include <sys/types.h> 23#include <sys/un.h> 24 25#define LOG_TAG "SocketListener" 26#include <cutils/log.h> 27#include <cutils/sockets.h> 28 29#include <sysutils/SocketListener.h> 30#include <sysutils/SocketClient.h> 31 32#define DBG 0 33 34SocketListener::SocketListener(const char *socketName, bool listen) { 35 mListen = listen; 36 mSocketName = socketName; 37 mSock = -1; 38 pthread_mutex_init(&mClientsLock, NULL); 39 mClients = new SocketClientCollection(); 40} 41 42SocketListener::SocketListener(int socketFd, bool listen) { 43 mListen = listen; 44 mSocketName = NULL; 45 mSock = socketFd; 46 pthread_mutex_init(&mClientsLock, NULL); 47 mClients = new SocketClientCollection(); 48} 49 50SocketListener::~SocketListener() { 51 if (mSocketName && mSock > -1) 52 close(mSock); 53 54 if (mCtrlPipe[0] != -1) { 55 close(mCtrlPipe[0]); 56 close(mCtrlPipe[1]); 57 } 58 SocketClientCollection::iterator it; 59 for (it = mClients->begin(); it != mClients->end();) { 60 (*it)->decRef(); 61 it = mClients->erase(it); 62 } 63 delete mClients; 64} 65 66int SocketListener::startListener() { 67 68 if (!mSocketName && mSock == -1) { 69 SLOGE("Failed to start unbound listener"); 70 errno = EINVAL; 71 return -1; 72 } else if (mSocketName) { 73 if ((mSock = android_get_control_socket(mSocketName)) < 0) { 74 SLOGE("Obtaining file descriptor socket '%s' failed: %s", 75 mSocketName, strerror(errno)); 76 return -1; 77 } 78 if (DBG) SLOGE("got mSock = %d for %s", mSock, mSocketName); 79 } 80 81 if (mListen && listen(mSock, 4) < 0) { 82 SLOGE("Unable to listen on socket (%s)", strerror(errno)); 83 return -1; 84 } else if (!mListen) 85 mClients->push_back(new SocketClient(mSock, false)); 86 87 if (pipe(mCtrlPipe)) { 88 SLOGE("pipe failed (%s)", strerror(errno)); 89 return -1; 90 } 91 92 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { 93 SLOGE("pthread_create (%s)", strerror(errno)); 94 return -1; 95 } 96 97 return 0; 98} 99 100int SocketListener::stopListener() { 101 char c = 0; 102 int rc; 103 104 rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1)); 105 if (rc != 1) { 106 SLOGE("Error writing to control pipe (%s)", strerror(errno)); 107 return -1; 108 } 109 110 void *ret; 111 if (pthread_join(mThread, &ret)) { 112 SLOGE("Error joining to listener thread (%s)", strerror(errno)); 113 return -1; 114 } 115 close(mCtrlPipe[0]); 116 close(mCtrlPipe[1]); 117 mCtrlPipe[0] = -1; 118 mCtrlPipe[1] = -1; 119 120 if (mSocketName && mSock > -1) { 121 close(mSock); 122 mSock = -1; 123 } 124 125 SocketClientCollection::iterator it; 126 for (it = mClients->begin(); it != mClients->end();) { 127 delete (*it); 128 it = mClients->erase(it); 129 } 130 return 0; 131} 132 133void *SocketListener::threadStart(void *obj) { 134 SocketListener *me = reinterpret_cast<SocketListener *>(obj); 135 136 me->runListener(); 137 pthread_exit(NULL); 138 return NULL; 139} 140 141void SocketListener::runListener() { 142 143 SocketClientCollection *pendingList = new SocketClientCollection(); 144 145 while(1) { 146 SocketClientCollection::iterator it; 147 fd_set read_fds; 148 int rc = 0; 149 int max = -1; 150 151 FD_ZERO(&read_fds); 152 153 if (mListen) { 154 max = mSock; 155 FD_SET(mSock, &read_fds); 156 } 157 158 FD_SET(mCtrlPipe[0], &read_fds); 159 if (mCtrlPipe[0] > max) 160 max = mCtrlPipe[0]; 161 162 pthread_mutex_lock(&mClientsLock); 163 for (it = mClients->begin(); it != mClients->end(); ++it) { 164 int fd = (*it)->getSocket(); 165 FD_SET(fd, &read_fds); 166 if (fd > max) 167 max = fd; 168 } 169 pthread_mutex_unlock(&mClientsLock); 170 if (DBG) SLOGE("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); 171 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { 172 if (errno == EINTR) 173 continue; 174 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); 175 sleep(1); 176 continue; 177 } else if (!rc) 178 continue; 179 180 if (FD_ISSET(mCtrlPipe[0], &read_fds)) 181 break; 182 if (mListen && FD_ISSET(mSock, &read_fds)) { 183 struct sockaddr addr; 184 socklen_t alen; 185 int c; 186 187 do { 188 alen = sizeof(addr); 189 c = accept(mSock, &addr, &alen); 190 if (DBG) SLOGE("%s got %d from accept", mSocketName, c); 191 } while (c < 0 && errno == EINTR); 192 if (c < 0) { 193 SLOGE("accept failed (%s)", strerror(errno)); 194 sleep(1); 195 continue; 196 } 197 pthread_mutex_lock(&mClientsLock); 198 mClients->push_back(new SocketClient(c, true)); 199 pthread_mutex_unlock(&mClientsLock); 200 } 201 202 /* Add all active clients to the pending list first */ 203 pendingList->clear(); 204 pthread_mutex_lock(&mClientsLock); 205 for (it = mClients->begin(); it != mClients->end(); ++it) { 206 int fd = (*it)->getSocket(); 207 if (FD_ISSET(fd, &read_fds)) { 208 pendingList->push_back(*it); 209 } 210 } 211 pthread_mutex_unlock(&mClientsLock); 212 213 /* Process the pending list, since it is owned by the thread, 214 * there is no need to lock it */ 215 while (!pendingList->empty()) { 216 /* Pop the first item from the list */ 217 it = pendingList->begin(); 218 SocketClient* c = *it; 219 pendingList->erase(it); 220 /* Process it, if false is returned and our sockets are 221 * connection-based, remove and destroy it */ 222 if (!onDataAvailable(c) && mListen) { 223 /* Remove the client from our array */ 224 if (DBG) SLOGE("going to zap %d for %s", c->getSocket(), mSocketName); 225 pthread_mutex_lock(&mClientsLock); 226 for (it = mClients->begin(); it != mClients->end(); ++it) { 227 if (*it == c) { 228 mClients->erase(it); 229 break; 230 } 231 } 232 pthread_mutex_unlock(&mClientsLock); 233 /* Remove our reference to the client */ 234 c->decRef(); 235 } 236 } 237 } 238 delete pendingList; 239} 240 241void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { 242 pthread_mutex_lock(&mClientsLock); 243 SocketClientCollection::iterator i; 244 245 for (i = mClients->begin(); i != mClients->end(); ++i) { 246 if ((*i)->sendMsg(code, msg, addErrno)) { 247 SLOGW("Error sending broadcast (%s)", strerror(errno)); 248 } 249 } 250 pthread_mutex_unlock(&mClientsLock); 251} 252