blob: 5c752066c7130116aed9446c7f7b804904f97583 [file] [log] [blame]
San Mehat168415b2009-05-06 11:14:21 -07001/*
Mark Salyzyn23f04102012-01-24 20:30:10 -08002 * Copyright (C) 2008-2014 The Android Open Source Project
San Mehat168415b2009-05-06 11:14:21 -07003 *
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>
San Mehat168415b2009-05-06 11:14:21 -070027#include <cutils/sockets.h>
28
29#include <sysutils/SocketListener.h>
San Mehatfa644ff2009-05-08 11:15:53 -070030#include <sysutils/SocketClient.h>
San Mehat168415b2009-05-06 11:14:21 -070031
Mark Salyzyn44b99c22014-01-08 12:44:23 -080032#define CtrlPipe_Shutdown 0
33#define CtrlPipe_Wakeup 1
34
San Mehatfa644ff2009-05-08 11:15:53 -070035SocketListener::SocketListener(const char *socketName, bool listen) {
Robert Greenwalt8702bb12012-02-07 12:23:14 -080036 init(socketName, -1, listen, false);
San Mehat168415b2009-05-06 11:14:21 -070037}
38
San Mehatfa644ff2009-05-08 11:15:53 -070039SocketListener::SocketListener(int socketFd, bool listen) {
Robert Greenwalt8702bb12012-02-07 12:23:14 -080040 init(NULL, socketFd, listen, false);
41}
42
43SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
44 init(socketName, -1, listen, useCmdNum);
45}
46
47void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
San Mehatfa644ff2009-05-08 11:15:53 -070048 mListen = listen;
Robert Greenwalt8702bb12012-02-07 12:23:14 -080049 mSocketName = socketName;
San Mehat168415b2009-05-06 11:14:21 -070050 mSock = socketFd;
Robert Greenwalt8702bb12012-02-07 12:23:14 -080051 mUseCmdNum = useCmdNum;
San Mehatfa644ff2009-05-08 11:15:53 -070052 pthread_mutex_init(&mClientsLock, NULL);
53 mClients = new SocketClientCollection();
San Mehat168415b2009-05-06 11:14:21 -070054}
55
San Mehatc4a895b2009-06-23 21:10:57 -070056SocketListener::~SocketListener() {
57 if (mSocketName && mSock > -1)
58 close(mSock);
59
60 if (mCtrlPipe[0] != -1) {
61 close(mCtrlPipe[0]);
62 close(mCtrlPipe[1]);
63 }
64 SocketClientCollection::iterator it;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +010065 for (it = mClients->begin(); it != mClients->end();) {
Brad Fitzpatrick13aa8ad2011-03-17 15:41:20 -070066 (*it)->decRef();
San Mehatc4a895b2009-06-23 21:10:57 -070067 it = mClients->erase(it);
68 }
69 delete mClients;
70}
71
San Mehatfa644ff2009-05-08 11:15:53 -070072int SocketListener::startListener() {
San Mehat168415b2009-05-06 11:14:21 -070073
74 if (!mSocketName && mSock == -1) {
San Mehat7e8529a2010-03-25 09:31:42 -070075 SLOGE("Failed to start unbound listener");
San Mehat168415b2009-05-06 11:14:21 -070076 errno = EINVAL;
77 return -1;
78 } else if (mSocketName) {
79 if ((mSock = android_get_control_socket(mSocketName)) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070080 SLOGE("Obtaining file descriptor socket '%s' failed: %s",
San Mehat168415b2009-05-06 11:14:21 -070081 mSocketName, strerror(errno));
82 return -1;
83 }
Robert Greenwalt8702bb12012-02-07 12:23:14 -080084 SLOGV("got mSock = %d for %s", mSock, mSocketName);
San Mehat168415b2009-05-06 11:14:21 -070085 }
86
San Mehatfa644ff2009-05-08 11:15:53 -070087 if (mListen && listen(mSock, 4) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070088 SLOGE("Unable to listen on socket (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070089 return -1;
San Mehatdf6c1b92009-05-13 08:58:43 -070090 } else if (!mListen)
Robert Greenwalt8702bb12012-02-07 12:23:14 -080091 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
San Mehat168415b2009-05-06 11:14:21 -070092
San Mehatc4a895b2009-06-23 21:10:57 -070093 if (pipe(mCtrlPipe)) {
San Mehat7e8529a2010-03-25 09:31:42 -070094 SLOGE("pipe failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070095 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -070096 }
San Mehatfa644ff2009-05-08 11:15:53 -070097
San Mehatc4a895b2009-06-23 21:10:57 -070098 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
San Mehat7e8529a2010-03-25 09:31:42 -070099 SLOGE("pthread_create (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700100 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -0700101 }
San Mehatfa644ff2009-05-08 11:15:53 -0700102
103 return 0;
104}
105
106int SocketListener::stopListener() {
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800107 char c = CtrlPipe_Shutdown;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100108 int rc;
San Mehatfa644ff2009-05-08 11:15:53 -0700109
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100110 rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
111 if (rc != 1) {
San Mehat7e8529a2010-03-25 09:31:42 -0700112 SLOGE("Error writing to control pipe (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700113 return -1;
114 }
115
San Mehatfa644ff2009-05-08 11:15:53 -0700116 void *ret;
117 if (pthread_join(mThread, &ret)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700118 SLOGE("Error joining to listener thread (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700119 return -1;
120 }
San Mehatdbdb0db2009-05-12 15:50:26 -0700121 close(mCtrlPipe[0]);
122 close(mCtrlPipe[1]);
San Mehatc4a895b2009-06-23 21:10:57 -0700123 mCtrlPipe[0] = -1;
124 mCtrlPipe[1] = -1;
125
126 if (mSocketName && mSock > -1) {
127 close(mSock);
128 mSock = -1;
129 }
130
131 SocketClientCollection::iterator it;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100132 for (it = mClients->begin(); it != mClients->end();) {
San Mehatc4a895b2009-06-23 21:10:57 -0700133 delete (*it);
134 it = mClients->erase(it);
135 }
San Mehatfa644ff2009-05-08 11:15:53 -0700136 return 0;
137}
138
139void *SocketListener::threadStart(void *obj) {
140 SocketListener *me = reinterpret_cast<SocketListener *>(obj);
141
142 me->runListener();
San Mehatfa644ff2009-05-08 11:15:53 -0700143 pthread_exit(NULL);
144 return NULL;
145}
146
147void SocketListener::runListener() {
148
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800149 SocketClientCollection pendingList;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100150
San Mehat168415b2009-05-06 11:14:21 -0700151 while(1) {
San Mehatfa644ff2009-05-08 11:15:53 -0700152 SocketClientCollection::iterator it;
San Mehat168415b2009-05-06 11:14:21 -0700153 fd_set read_fds;
San Mehat168415b2009-05-06 11:14:21 -0700154 int rc = 0;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100155 int max = -1;
San Mehatfa644ff2009-05-08 11:15:53 -0700156
San Mehat168415b2009-05-06 11:14:21 -0700157 FD_ZERO(&read_fds);
158
San Mehatfa644ff2009-05-08 11:15:53 -0700159 if (mListen) {
San Mehat168415b2009-05-06 11:14:21 -0700160 max = mSock;
San Mehatfa644ff2009-05-08 11:15:53 -0700161 FD_SET(mSock, &read_fds);
San Mehat168415b2009-05-06 11:14:21 -0700162 }
163
San Mehatfa644ff2009-05-08 11:15:53 -0700164 FD_SET(mCtrlPipe[0], &read_fds);
165 if (mCtrlPipe[0] > max)
166 max = mCtrlPipe[0];
167
168 pthread_mutex_lock(&mClientsLock);
169 for (it = mClients->begin(); it != mClients->end(); ++it) {
Mark Salyzyn23f04102012-01-24 20:30:10 -0800170 // NB: calling out to an other object with mClientsLock held (safe)
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100171 int fd = (*it)->getSocket();
172 FD_SET(fd, &read_fds);
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800173 if (fd > max) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100174 max = fd;
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800175 }
San Mehatfa644ff2009-05-08 11:15:53 -0700176 }
177 pthread_mutex_unlock(&mClientsLock);
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800178 SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
San Mehatdf6c1b92009-05-13 08:58:43 -0700179 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100180 if (errno == EINTR)
181 continue;
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800182 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
San Mehatfa644ff2009-05-08 11:15:53 -0700183 sleep(1);
San Mehat168415b2009-05-06 11:14:21 -0700184 continue;
San Mehatdf6c1b92009-05-13 08:58:43 -0700185 } else if (!rc)
San Mehatfa644ff2009-05-08 11:15:53 -0700186 continue;
San Mehat168415b2009-05-06 11:14:21 -0700187
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800188 if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
189 char c = CtrlPipe_Shutdown;
190 TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
191 if (c == CtrlPipe_Shutdown) {
192 break;
193 }
194 continue;
195 }
San Mehatfa644ff2009-05-08 11:15:53 -0700196 if (mListen && FD_ISSET(mSock, &read_fds)) {
197 struct sockaddr addr;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100198 socklen_t alen;
San Mehatfa644ff2009-05-08 11:15:53 -0700199 int c;
200
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100201 do {
202 alen = sizeof(addr);
203 c = accept(mSock, &addr, &alen);
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800204 SLOGV("%s got %d from accept", mSocketName, c);
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100205 } while (c < 0 && errno == EINTR);
206 if (c < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -0700207 SLOGE("accept failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700208 sleep(1);
209 continue;
210 }
San Mehatfa644ff2009-05-08 11:15:53 -0700211 pthread_mutex_lock(&mClientsLock);
Robert Greenwalt8702bb12012-02-07 12:23:14 -0800212 mClients->push_back(new SocketClient(c, true, mUseCmdNum));
San Mehatfa644ff2009-05-08 11:15:53 -0700213 pthread_mutex_unlock(&mClientsLock);
214 }
215
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100216 /* Add all active clients to the pending list first */
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800217 pendingList.clear();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100218 pthread_mutex_lock(&mClientsLock);
219 for (it = mClients->begin(); it != mClients->end(); ++it) {
Mark Salyzyn23f04102012-01-24 20:30:10 -0800220 SocketClient* c = *it;
221 // NB: calling out to an other object with mClientsLock held (safe)
222 int fd = c->getSocket();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100223 if (FD_ISSET(fd, &read_fds)) {
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800224 pendingList.push_back(c);
Mark Salyzyn23f04102012-01-24 20:30:10 -0800225 c->incRef();
San Mehat168415b2009-05-06 11:14:21 -0700226 }
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100227 }
228 pthread_mutex_unlock(&mClientsLock);
229
230 /* Process the pending list, since it is owned by the thread,
231 * there is no need to lock it */
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800232 while (!pendingList.empty()) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100233 /* Pop the first item from the list */
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800234 it = pendingList.begin();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100235 SocketClient* c = *it;
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800236 pendingList.erase(it);
237 /* Process it, if false is returned, remove from list */
238 if (!onDataAvailable(c)) {
239 release(c, false);
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100240 }
Mark Salyzyn23f04102012-01-24 20:30:10 -0800241 c->decRef();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100242 }
San Mehat168415b2009-05-06 11:14:21 -0700243 }
Mark Salyzyn44b99c22014-01-08 12:44:23 -0800244}
245
246bool SocketListener::release(SocketClient* c, bool wakeup) {
247 bool ret = false;
248 /* if our sockets are connection-based, remove and destroy it */
249 if (mListen && c) {
250 /* Remove the client from our array */
251 SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
252 pthread_mutex_lock(&mClientsLock);
253 SocketClientCollection::iterator it;
254 for (it = mClients->begin(); it != mClients->end(); ++it) {
255 if (*it == c) {
256 mClients->erase(it);
257 ret = true;
258 break;
259 }
260 }
261 pthread_mutex_unlock(&mClientsLock);
262 if (ret) {
263 ret = c->decRef();
264 if (wakeup) {
265 char b = CtrlPipe_Wakeup;
266 TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
267 }
268 }
269 }
270 return ret;
San Mehat168415b2009-05-06 11:14:21 -0700271}
272
San Mehatdb017542009-05-20 15:27:14 -0700273void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
Mark Salyzyn23f04102012-01-24 20:30:10 -0800274 SocketClientCollection safeList;
275
276 /* Add all active clients to the safe list first */
277 safeList.clear();
San Mehatd7680662009-05-12 11:16:59 -0700278 pthread_mutex_lock(&mClientsLock);
279 SocketClientCollection::iterator i;
280
281 for (i = mClients->begin(); i != mClients->end(); ++i) {
Mark Salyzyn23f04102012-01-24 20:30:10 -0800282 SocketClient* c = *i;
283 c->incRef();
284 safeList.push_back(c);
Guang Zhua8185a62012-02-07 19:13:28 -0800285 }
286 pthread_mutex_unlock(&mClientsLock);
Mark Salyzyn23f04102012-01-24 20:30:10 -0800287
288 while (!safeList.empty()) {
289 /* Pop the first item from the list */
290 i = safeList.begin();
291 SocketClient* c = *i;
292 safeList.erase(i);
293 // broadcasts are unsolicited and should not include a cmd number
294 if (c->sendMsg(code, msg, addErrno, false)) {
295 SLOGW("Error sending broadcast (%s)", strerror(errno));
296 }
297 c->decRef();
298 }
299}
300
301void SocketListener::runOnEachSocket(SocketClientCommand *command) {
302 SocketClientCollection safeList;
303
304 /* Add all active clients to the safe list first */
305 safeList.clear();
306 pthread_mutex_lock(&mClientsLock);
307 SocketClientCollection::iterator i;
308
309 for (i = mClients->begin(); i != mClients->end(); ++i) {
310 SocketClient* c = *i;
311 c->incRef();
312 safeList.push_back(c);
313 }
314 pthread_mutex_unlock(&mClientsLock);
315
316 while (!safeList.empty()) {
317 /* Pop the first item from the list */
318 i = safeList.begin();
319 SocketClient* c = *i;
320 safeList.erase(i);
321 command->runSocketCommand(c);
322 c->decRef();
323 }
Guang Zhua8185a62012-02-07 19:13:28 -0800324}