blob: 8f5329cd70f3d7afaa71515603aad53c718161a8 [file] [log] [blame]
San Mehat168415b2009-05-06 11:14:21 -07001/*
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>
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
Robert Greenwaltdc58e732012-02-07 12:23:14 -080032#define DBG 0
33
San Mehatfa644ff2009-05-08 11:15:53 -070034SocketListener::SocketListener(const char *socketName, bool listen) {
35 mListen = listen;
San Mehat168415b2009-05-06 11:14:21 -070036 mSocketName = socketName;
37 mSock = -1;
San Mehatfa644ff2009-05-08 11:15:53 -070038 pthread_mutex_init(&mClientsLock, NULL);
39 mClients = new SocketClientCollection();
San Mehat168415b2009-05-06 11:14:21 -070040}
41
San Mehatfa644ff2009-05-08 11:15:53 -070042SocketListener::SocketListener(int socketFd, bool listen) {
43 mListen = listen;
San Mehat168415b2009-05-06 11:14:21 -070044 mSocketName = NULL;
45 mSock = socketFd;
San Mehatfa644ff2009-05-08 11:15:53 -070046 pthread_mutex_init(&mClientsLock, NULL);
47 mClients = new SocketClientCollection();
San Mehat168415b2009-05-06 11:14:21 -070048}
49
San Mehatc4a895b2009-06-23 21:10:57 -070050SocketListener::~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;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +010059 for (it = mClients->begin(); it != mClients->end();) {
Brad Fitzpatrick13aa8ad2011-03-17 15:41:20 -070060 (*it)->decRef();
San Mehatc4a895b2009-06-23 21:10:57 -070061 it = mClients->erase(it);
62 }
63 delete mClients;
64}
65
San Mehatfa644ff2009-05-08 11:15:53 -070066int SocketListener::startListener() {
San Mehat168415b2009-05-06 11:14:21 -070067
68 if (!mSocketName && mSock == -1) {
San Mehat7e8529a2010-03-25 09:31:42 -070069 SLOGE("Failed to start unbound listener");
San Mehat168415b2009-05-06 11:14:21 -070070 errno = EINVAL;
71 return -1;
72 } else if (mSocketName) {
73 if ((mSock = android_get_control_socket(mSocketName)) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070074 SLOGE("Obtaining file descriptor socket '%s' failed: %s",
San Mehat168415b2009-05-06 11:14:21 -070075 mSocketName, strerror(errno));
76 return -1;
77 }
Robert Greenwaltdc58e732012-02-07 12:23:14 -080078 if (DBG) SLOGE("got mSock = %d for %s", mSock, mSocketName);
San Mehat168415b2009-05-06 11:14:21 -070079 }
80
San Mehatfa644ff2009-05-08 11:15:53 -070081 if (mListen && listen(mSock, 4) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070082 SLOGE("Unable to listen on socket (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070083 return -1;
San Mehatdf6c1b92009-05-13 08:58:43 -070084 } else if (!mListen)
Xianzhu Wang45202462011-09-29 12:59:55 +080085 mClients->push_back(new SocketClient(mSock, false));
San Mehat168415b2009-05-06 11:14:21 -070086
San Mehatc4a895b2009-06-23 21:10:57 -070087 if (pipe(mCtrlPipe)) {
San Mehat7e8529a2010-03-25 09:31:42 -070088 SLOGE("pipe failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070089 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -070090 }
San Mehatfa644ff2009-05-08 11:15:53 -070091
San Mehatc4a895b2009-06-23 21:10:57 -070092 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
San Mehat7e8529a2010-03-25 09:31:42 -070093 SLOGE("pthread_create (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070094 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -070095 }
San Mehatfa644ff2009-05-08 11:15:53 -070096
97 return 0;
98}
99
100int SocketListener::stopListener() {
101 char c = 0;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100102 int rc;
San Mehatfa644ff2009-05-08 11:15:53 -0700103
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100104 rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
105 if (rc != 1) {
San Mehat7e8529a2010-03-25 09:31:42 -0700106 SLOGE("Error writing to control pipe (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700107 return -1;
108 }
109
San Mehatfa644ff2009-05-08 11:15:53 -0700110 void *ret;
111 if (pthread_join(mThread, &ret)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700112 SLOGE("Error joining to listener thread (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700113 return -1;
114 }
San Mehatdbdb0db2009-05-12 15:50:26 -0700115 close(mCtrlPipe[0]);
116 close(mCtrlPipe[1]);
San Mehatc4a895b2009-06-23 21:10:57 -0700117 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;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100126 for (it = mClients->begin(); it != mClients->end();) {
San Mehatc4a895b2009-06-23 21:10:57 -0700127 delete (*it);
128 it = mClients->erase(it);
129 }
San Mehatfa644ff2009-05-08 11:15:53 -0700130 return 0;
131}
132
133void *SocketListener::threadStart(void *obj) {
134 SocketListener *me = reinterpret_cast<SocketListener *>(obj);
135
136 me->runListener();
San Mehatfa644ff2009-05-08 11:15:53 -0700137 pthread_exit(NULL);
138 return NULL;
139}
140
141void SocketListener::runListener() {
142
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100143 SocketClientCollection *pendingList = new SocketClientCollection();
144
San Mehat168415b2009-05-06 11:14:21 -0700145 while(1) {
San Mehatfa644ff2009-05-08 11:15:53 -0700146 SocketClientCollection::iterator it;
San Mehat168415b2009-05-06 11:14:21 -0700147 fd_set read_fds;
San Mehat168415b2009-05-06 11:14:21 -0700148 int rc = 0;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100149 int max = -1;
San Mehatfa644ff2009-05-08 11:15:53 -0700150
San Mehat168415b2009-05-06 11:14:21 -0700151 FD_ZERO(&read_fds);
152
San Mehatfa644ff2009-05-08 11:15:53 -0700153 if (mListen) {
San Mehat168415b2009-05-06 11:14:21 -0700154 max = mSock;
San Mehatfa644ff2009-05-08 11:15:53 -0700155 FD_SET(mSock, &read_fds);
San Mehat168415b2009-05-06 11:14:21 -0700156 }
157
San Mehatfa644ff2009-05-08 11:15:53 -0700158 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) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100164 int fd = (*it)->getSocket();
165 FD_SET(fd, &read_fds);
166 if (fd > max)
167 max = fd;
San Mehatfa644ff2009-05-08 11:15:53 -0700168 }
169 pthread_mutex_unlock(&mClientsLock);
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800170 if (DBG) SLOGE("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
San Mehatdf6c1b92009-05-13 08:58:43 -0700171 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100172 if (errno == EINTR)
173 continue;
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800174 SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
San Mehatfa644ff2009-05-08 11:15:53 -0700175 sleep(1);
San Mehat168415b2009-05-06 11:14:21 -0700176 continue;
San Mehatdf6c1b92009-05-13 08:58:43 -0700177 } else if (!rc)
San Mehatfa644ff2009-05-08 11:15:53 -0700178 continue;
San Mehat168415b2009-05-06 11:14:21 -0700179
San Mehatdbdb0db2009-05-12 15:50:26 -0700180 if (FD_ISSET(mCtrlPipe[0], &read_fds))
San Mehatfa644ff2009-05-08 11:15:53 -0700181 break;
San Mehatfa644ff2009-05-08 11:15:53 -0700182 if (mListen && FD_ISSET(mSock, &read_fds)) {
183 struct sockaddr addr;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100184 socklen_t alen;
San Mehatfa644ff2009-05-08 11:15:53 -0700185 int c;
186
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100187 do {
188 alen = sizeof(addr);
189 c = accept(mSock, &addr, &alen);
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800190 if (DBG) SLOGE("%s got %d from accept", mSocketName, c);
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100191 } while (c < 0 && errno == EINTR);
192 if (c < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -0700193 SLOGE("accept failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700194 sleep(1);
195 continue;
196 }
San Mehatfa644ff2009-05-08 11:15:53 -0700197 pthread_mutex_lock(&mClientsLock);
Xianzhu Wang45202462011-09-29 12:59:55 +0800198 mClients->push_back(new SocketClient(c, true));
San Mehatfa644ff2009-05-08 11:15:53 -0700199 pthread_mutex_unlock(&mClientsLock);
200 }
201
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100202 /* 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);
San Mehat168415b2009-05-06 11:14:21 -0700209 }
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100210 }
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);
Vernon Tang87950072011-04-27 14:01:27 +1000220 /* Process it, if false is returned and our sockets are
221 * connection-based, remove and destroy it */
222 if (!onDataAvailable(c) && mListen) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100223 /* Remove the client from our array */
Robert Greenwaltdc58e732012-02-07 12:23:14 -0800224 if (DBG) SLOGE("going to zap %d for %s", c->getSocket(), mSocketName);
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100225 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);
Xianzhu Wang45202462011-09-29 12:59:55 +0800233 /* Remove our reference to the client */
234 c->decRef();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100235 }
236 }
San Mehat168415b2009-05-06 11:14:21 -0700237 }
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100238 delete pendingList;
San Mehat168415b2009-05-06 11:14:21 -0700239}
240
San Mehatdb017542009-05-20 15:27:14 -0700241void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
San Mehatd7680662009-05-12 11:16:59 -0700242 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)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700247 SLOGW("Error sending broadcast (%s)", strerror(errno));
San Mehatd7680662009-05-12 11:16:59 -0700248 }
249 }
250 pthread_mutex_unlock(&mClientsLock);
251}