blob: 3f871ea88ff3acdb3b381c3eca7a14453934351e [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
San Mehatfa644ff2009-05-08 11:15:53 -070032SocketListener::SocketListener(const char *socketName, bool listen) {
33 mListen = listen;
San Mehat168415b2009-05-06 11:14:21 -070034 mSocketName = socketName;
35 mSock = -1;
San Mehatfa644ff2009-05-08 11:15:53 -070036 pthread_mutex_init(&mClientsLock, NULL);
37 mClients = new SocketClientCollection();
San Mehat168415b2009-05-06 11:14:21 -070038}
39
San Mehatfa644ff2009-05-08 11:15:53 -070040SocketListener::SocketListener(int socketFd, bool listen) {
41 mListen = listen;
San Mehat168415b2009-05-06 11:14:21 -070042 mSocketName = NULL;
43 mSock = socketFd;
San Mehatfa644ff2009-05-08 11:15:53 -070044 pthread_mutex_init(&mClientsLock, NULL);
45 mClients = new SocketClientCollection();
San Mehat168415b2009-05-06 11:14:21 -070046}
47
San Mehatc4a895b2009-06-23 21:10:57 -070048SocketListener::~SocketListener() {
49 if (mSocketName && mSock > -1)
50 close(mSock);
51
52 if (mCtrlPipe[0] != -1) {
53 close(mCtrlPipe[0]);
54 close(mCtrlPipe[1]);
55 }
56 SocketClientCollection::iterator it;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +010057 for (it = mClients->begin(); it != mClients->end();) {
Brad Fitzpatrick13aa8ad2011-03-17 15:41:20 -070058 (*it)->decRef();
San Mehatc4a895b2009-06-23 21:10:57 -070059 it = mClients->erase(it);
60 }
61 delete mClients;
62}
63
San Mehatfa644ff2009-05-08 11:15:53 -070064int SocketListener::startListener() {
San Mehat168415b2009-05-06 11:14:21 -070065
66 if (!mSocketName && mSock == -1) {
San Mehat7e8529a2010-03-25 09:31:42 -070067 SLOGE("Failed to start unbound listener");
San Mehat168415b2009-05-06 11:14:21 -070068 errno = EINVAL;
69 return -1;
70 } else if (mSocketName) {
71 if ((mSock = android_get_control_socket(mSocketName)) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070072 SLOGE("Obtaining file descriptor socket '%s' failed: %s",
San Mehat168415b2009-05-06 11:14:21 -070073 mSocketName, strerror(errno));
74 return -1;
75 }
76 }
77
San Mehatfa644ff2009-05-08 11:15:53 -070078 if (mListen && listen(mSock, 4) < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -070079 SLOGE("Unable to listen on socket (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070080 return -1;
San Mehatdf6c1b92009-05-13 08:58:43 -070081 } else if (!mListen)
Xianzhu Wang45202462011-09-29 12:59:55 +080082 mClients->push_back(new SocketClient(mSock, false));
San Mehat168415b2009-05-06 11:14:21 -070083
San Mehatc4a895b2009-06-23 21:10:57 -070084 if (pipe(mCtrlPipe)) {
San Mehat7e8529a2010-03-25 09:31:42 -070085 SLOGE("pipe failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070086 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -070087 }
San Mehatfa644ff2009-05-08 11:15:53 -070088
San Mehatc4a895b2009-06-23 21:10:57 -070089 if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
San Mehat7e8529a2010-03-25 09:31:42 -070090 SLOGE("pthread_create (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -070091 return -1;
San Mehatc4a895b2009-06-23 21:10:57 -070092 }
San Mehatfa644ff2009-05-08 11:15:53 -070093
94 return 0;
95}
96
97int SocketListener::stopListener() {
98 char c = 0;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +010099 int rc;
San Mehatfa644ff2009-05-08 11:15:53 -0700100
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100101 rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
102 if (rc != 1) {
San Mehat7e8529a2010-03-25 09:31:42 -0700103 SLOGE("Error writing to control pipe (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700104 return -1;
105 }
106
San Mehatfa644ff2009-05-08 11:15:53 -0700107 void *ret;
108 if (pthread_join(mThread, &ret)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700109 SLOGE("Error joining to listener thread (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700110 return -1;
111 }
San Mehatdbdb0db2009-05-12 15:50:26 -0700112 close(mCtrlPipe[0]);
113 close(mCtrlPipe[1]);
San Mehatc4a895b2009-06-23 21:10:57 -0700114 mCtrlPipe[0] = -1;
115 mCtrlPipe[1] = -1;
116
117 if (mSocketName && mSock > -1) {
118 close(mSock);
119 mSock = -1;
120 }
121
122 SocketClientCollection::iterator it;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100123 for (it = mClients->begin(); it != mClients->end();) {
San Mehatc4a895b2009-06-23 21:10:57 -0700124 delete (*it);
125 it = mClients->erase(it);
126 }
San Mehatfa644ff2009-05-08 11:15:53 -0700127 return 0;
128}
129
130void *SocketListener::threadStart(void *obj) {
131 SocketListener *me = reinterpret_cast<SocketListener *>(obj);
132
133 me->runListener();
San Mehatfa644ff2009-05-08 11:15:53 -0700134 pthread_exit(NULL);
135 return NULL;
136}
137
138void SocketListener::runListener() {
139
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100140 SocketClientCollection *pendingList = new SocketClientCollection();
141
San Mehat168415b2009-05-06 11:14:21 -0700142 while(1) {
San Mehatfa644ff2009-05-08 11:15:53 -0700143 SocketClientCollection::iterator it;
San Mehat168415b2009-05-06 11:14:21 -0700144 fd_set read_fds;
San Mehat168415b2009-05-06 11:14:21 -0700145 int rc = 0;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100146 int max = -1;
San Mehatfa644ff2009-05-08 11:15:53 -0700147
San Mehat168415b2009-05-06 11:14:21 -0700148 FD_ZERO(&read_fds);
149
San Mehatfa644ff2009-05-08 11:15:53 -0700150 if (mListen) {
San Mehat168415b2009-05-06 11:14:21 -0700151 max = mSock;
San Mehatfa644ff2009-05-08 11:15:53 -0700152 FD_SET(mSock, &read_fds);
San Mehat168415b2009-05-06 11:14:21 -0700153 }
154
San Mehatfa644ff2009-05-08 11:15:53 -0700155 FD_SET(mCtrlPipe[0], &read_fds);
156 if (mCtrlPipe[0] > max)
157 max = mCtrlPipe[0];
158
159 pthread_mutex_lock(&mClientsLock);
160 for (it = mClients->begin(); it != mClients->end(); ++it) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100161 int fd = (*it)->getSocket();
162 FD_SET(fd, &read_fds);
163 if (fd > max)
164 max = fd;
San Mehatfa644ff2009-05-08 11:15:53 -0700165 }
166 pthread_mutex_unlock(&mClientsLock);
San Mehat03f0d272009-05-26 15:18:25 -0700167
San Mehatdf6c1b92009-05-13 08:58:43 -0700168 if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100169 if (errno == EINTR)
170 continue;
San Mehat7e8529a2010-03-25 09:31:42 -0700171 SLOGE("select failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700172 sleep(1);
San Mehat168415b2009-05-06 11:14:21 -0700173 continue;
San Mehatdf6c1b92009-05-13 08:58:43 -0700174 } else if (!rc)
San Mehatfa644ff2009-05-08 11:15:53 -0700175 continue;
San Mehat168415b2009-05-06 11:14:21 -0700176
San Mehatdbdb0db2009-05-12 15:50:26 -0700177 if (FD_ISSET(mCtrlPipe[0], &read_fds))
San Mehatfa644ff2009-05-08 11:15:53 -0700178 break;
San Mehatfa644ff2009-05-08 11:15:53 -0700179 if (mListen && FD_ISSET(mSock, &read_fds)) {
180 struct sockaddr addr;
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100181 socklen_t alen;
San Mehatfa644ff2009-05-08 11:15:53 -0700182 int c;
183
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100184 do {
185 alen = sizeof(addr);
186 c = accept(mSock, &addr, &alen);
187 } while (c < 0 && errno == EINTR);
188 if (c < 0) {
San Mehat7e8529a2010-03-25 09:31:42 -0700189 SLOGE("accept failed (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700190 sleep(1);
191 continue;
192 }
San Mehatfa644ff2009-05-08 11:15:53 -0700193 pthread_mutex_lock(&mClientsLock);
Xianzhu Wang45202462011-09-29 12:59:55 +0800194 mClients->push_back(new SocketClient(c, true));
San Mehatfa644ff2009-05-08 11:15:53 -0700195 pthread_mutex_unlock(&mClientsLock);
196 }
197
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100198 /* Add all active clients to the pending list first */
199 pendingList->clear();
200 pthread_mutex_lock(&mClientsLock);
201 for (it = mClients->begin(); it != mClients->end(); ++it) {
202 int fd = (*it)->getSocket();
203 if (FD_ISSET(fd, &read_fds)) {
204 pendingList->push_back(*it);
San Mehat168415b2009-05-06 11:14:21 -0700205 }
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100206 }
207 pthread_mutex_unlock(&mClientsLock);
208
209 /* Process the pending list, since it is owned by the thread,
210 * there is no need to lock it */
211 while (!pendingList->empty()) {
212 /* Pop the first item from the list */
213 it = pendingList->begin();
214 SocketClient* c = *it;
215 pendingList->erase(it);
Vernon Tang87950072011-04-27 14:01:27 +1000216 /* Process it, if false is returned and our sockets are
217 * connection-based, remove and destroy it */
218 if (!onDataAvailable(c) && mListen) {
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100219 /* Remove the client from our array */
220 pthread_mutex_lock(&mClientsLock);
221 for (it = mClients->begin(); it != mClients->end(); ++it) {
222 if (*it == c) {
223 mClients->erase(it);
224 break;
225 }
226 }
227 pthread_mutex_unlock(&mClientsLock);
Xianzhu Wang45202462011-09-29 12:59:55 +0800228 /* Remove our reference to the client */
229 c->decRef();
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100230 }
231 }
San Mehat168415b2009-05-06 11:14:21 -0700232 }
David 'Digit' Turner100c0e22011-01-17 03:10:31 +0100233 delete pendingList;
San Mehat168415b2009-05-06 11:14:21 -0700234}
235
San Mehatdb017542009-05-20 15:27:14 -0700236void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
San Mehatd7680662009-05-12 11:16:59 -0700237 pthread_mutex_lock(&mClientsLock);
238 SocketClientCollection::iterator i;
239
240 for (i = mClients->begin(); i != mClients->end(); ++i) {
241 if ((*i)->sendMsg(code, msg, addErrno)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700242 SLOGW("Error sending broadcast (%s)", strerror(errno));
San Mehatd7680662009-05-12 11:16:59 -0700243 }
244 }
245 pthread_mutex_unlock(&mClientsLock);
246}
247
San Mehatdb017542009-05-20 15:27:14 -0700248void SocketListener::sendBroadcast(const char *msg) {
San Mehatfa644ff2009-05-08 11:15:53 -0700249 pthread_mutex_lock(&mClientsLock);
250 SocketClientCollection::iterator i;
251
252 for (i = mClients->begin(); i != mClients->end(); ++i) {
253 if ((*i)->sendMsg(msg)) {
San Mehat7e8529a2010-03-25 09:31:42 -0700254 SLOGW("Error sending broadcast (%s)", strerror(errno));
San Mehatfa644ff2009-05-08 11:15:53 -0700255 }
256 }
257 pthread_mutex_unlock(&mClientsLock);
San Mehat168415b2009-05-06 11:14:21 -0700258}