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 LOG_NDEBUG 0 33 34 SocketListener::SocketListener(const char *socketName, bool listen) { 35 init(socketName, -1, listen, false); 36 } 37 38 SocketListener::SocketListener(int socketFd, bool listen) { 39 init(NULL, socketFd, listen, false); 40 } 41 42 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) { 43 init(socketName, -1, listen, useCmdNum); 44 } 45 46 void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) { 47 mListen = listen; 48 mSocketName = socketName; 49 mSock = socketFd; 50 mUseCmdNum = useCmdNum; 51 pthread_mutex_init(&mClientsLock, NULL); 52 mClients = new SocketClientCollection(); 53 } 54 55 SocketListener::~SocketListener() { 56 if (mSocketName && mSock > -1) 57 close(mSock); 58 59 if (mCtrlPipe[0] != -1) { 60 close(mCtrlPipe[0]); 61 close(mCtrlPipe[1]); 62 } 63 SocketClientCollection::iterator it; 64 for (it = mClients->begin(); it != mClients->end();) { 65 (*it)->decRef(); 66 it = mClients->erase(it); 67 } 68 delete mClients; 69 } 70 71 int SocketListener::startListener() { 72 73 if (!mSocketName && mSock == -1) { 74 SLOGE("Failed to start unbound listener"); 75 errno = EINVAL; 76 return -1; 77 } else if (mSocketName) { 78 if ((mSock = android_get_control_socket(mSocketName)) < 0) { 79 SLOGE("Obtaining file descriptor socket '%s' failed: %s", 80 mSocketName, strerror(errno)); 81 return -1; 82 } 83 SLOGV("got mSock = %d for %s", mSock, mSocketName); 84 } 85 86 if (mListen && listen(mSock, 4) < 0) { 87 SLOGE("Unable to listen on socket (%s)", strerror(errno)); 88 return -1; 89 } else if (!mListen) 90 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); 91 92 if (pipe(mCtrlPipe)) { 93 SLOGE("pipe failed (%s)", strerror(errno)); 94 return -1; 95 } 96 97 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) { 98 SLOGE("pthread_create (%s)", strerror(errno)); 99 return -1; 100 } 101 102 return 0; 103 } 104 105 int SocketListener::stopListener() { 106 char c = 0; 107 int rc; 108 109 rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1)); 110 if (rc != 1) { 111 SLOGE("Error writing to control pipe (%s)", strerror(errno)); 112 return -1; 113 } 114 115 void *ret; 116 if (pthread_join(mThread, &ret)) { 117 SLOGE("Error joining to listener thread (%s)", strerror(errno)); 118 return -1; 119 } 120 close(mCtrlPipe[0]); 121 close(mCtrlPipe[1]); 122 mCtrlPipe[0] = -1; 123 mCtrlPipe[1] = -1; 124 125 if (mSocketName && mSock > -1) { 126 close(mSock); 127 mSock = -1; 128 } 129 130 SocketClientCollection::iterator it; 131 for (it = mClients->begin(); it != mClients->end();) { 132 delete (*it); 133 it = mClients->erase(it); 134 } 135 return 0; 136 } 137 138 void *SocketListener::threadStart(void *obj) { 139 SocketListener *me = reinterpret_cast<SocketListener *>(obj); 140 141 me->runListener(); 142 pthread_exit(NULL); 143 return NULL; 144 } 145 146 void SocketListener::runListener() { 147 148 SocketClientCollection *pendingList = new SocketClientCollection(); 149 150 while(1) { 151 SocketClientCollection::iterator it; 152 fd_set read_fds; 153 int rc = 0; 154 int max = -1; 155 156 FD_ZERO(&read_fds); 157 158 if (mListen) { 159 max = mSock; 160 FD_SET(mSock, &read_fds); 161 } 162 163 FD_SET(mCtrlPipe[0], &read_fds); 164 if (mCtrlPipe[0] > max) 165 max = mCtrlPipe[0]; 166 167 pthread_mutex_lock(&mClientsLock); 168 for (it = mClients->begin(); it != mClients->end(); ++it) { 169 int fd = (*it)->getSocket(); 170 FD_SET(fd, &read_fds); 171 if (fd > max) 172 max = fd; 173 } 174 pthread_mutex_unlock(&mClientsLock); 175 SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); 176 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { 177 if (errno == EINTR) 178 continue; 179 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); 180 sleep(1); 181 continue; 182 } else if (!rc) 183 continue; 184 185 if (FD_ISSET(mCtrlPipe[0], &read_fds)) 186 break; 187 if (mListen && FD_ISSET(mSock, &read_fds)) { 188 struct sockaddr addr; 189 socklen_t alen; 190 int c; 191 192 do { 193 alen = sizeof(addr); 194 c = accept(mSock, &addr, &alen); 195 SLOGV("%s got %d from accept", mSocketName, c); 196 } while (c < 0 && errno == EINTR); 197 if (c < 0) { 198 SLOGE("accept failed (%s)", strerror(errno)); 199 sleep(1); 200 continue; 201 } 202 pthread_mutex_lock(&mClientsLock); 203 mClients->push_back(new SocketClient(c, true, mUseCmdNum)); 204 pthread_mutex_unlock(&mClientsLock); 205 } 206 207 /* Add all active clients to the pending list first */ 208 pendingList->clear(); 209 pthread_mutex_lock(&mClientsLock); 210 for (it = mClients->begin(); it != mClients->end(); ++it) { 211 int fd = (*it)->getSocket(); 212 if (FD_ISSET(fd, &read_fds)) { 213 pendingList->push_back(*it); 214 } 215 } 216 pthread_mutex_unlock(&mClientsLock); 217 218 /* Process the pending list, since it is owned by the thread, 219 * there is no need to lock it */ 220 while (!pendingList->empty()) { 221 /* Pop the first item from the list */ 222 it = pendingList->begin(); 223 SocketClient* c = *it; 224 pendingList->erase(it); 225 /* Process it, if false is returned and our sockets are 226 * connection-based, remove and destroy it */ 227 if (!onDataAvailable(c) && mListen) { 228 /* Remove the client from our array */ 229 SLOGV("going to zap %d for %s", c->getSocket(), mSocketName); 230 pthread_mutex_lock(&mClientsLock); 231 for (it = mClients->begin(); it != mClients->end(); ++it) { 232 if (*it == c) { 233 mClients->erase(it); 234 break; 235 } 236 } 237 pthread_mutex_unlock(&mClientsLock); 238 /* Remove our reference to the client */ 239 c->decRef(); 240 } 241 } 242 } 243 delete pendingList; 244 } 245 246 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { 247 pthread_mutex_lock(&mClientsLock); 248 SocketClientCollection::iterator i; 249 250 for (i = mClients->begin(); i != mClients->end(); ++i) { 251 // broadcasts are unsolicited and should not include a cmd number 252 if ((*i)->sendMsg(code, msg, addErrno, false)) { 253 SLOGW("Error sending broadcast (%s)", strerror(errno)); 254 } 255 } 256 pthread_mutex_unlock(&mClientsLock); 257 } 258