• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008-2014 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 
17 #define LOG_TAG "SocketListener"
18 
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/select.h>
23 #include <sys/socket.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <sys/un.h>
27 #include <unistd.h>
28 
29 #include <cutils/sockets.h>
30 #include <log/log.h>
31 #include <sysutils/SocketListener.h>
32 #include <sysutils/SocketClient.h>
33 
34 #define CtrlPipe_Shutdown 0
35 #define CtrlPipe_Wakeup   1
36 
SocketListener(const char * socketName,bool listen)37 SocketListener::SocketListener(const char *socketName, bool listen) {
38     init(socketName, -1, listen, false);
39 }
40 
SocketListener(int socketFd,bool listen)41 SocketListener::SocketListener(int socketFd, bool listen) {
42     init(NULL, socketFd, listen, false);
43 }
44 
SocketListener(const char * socketName,bool listen,bool useCmdNum)45 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
46     init(socketName, -1, listen, useCmdNum);
47 }
48 
init(const char * socketName,int socketFd,bool listen,bool useCmdNum)49 void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
50     mListen = listen;
51     mSocketName = socketName;
52     mSock = socketFd;
53     mUseCmdNum = useCmdNum;
54     pthread_mutex_init(&mClientsLock, NULL);
55     mClients = new SocketClientCollection();
56 }
57 
~SocketListener()58 SocketListener::~SocketListener() {
59     if (mSocketName && mSock > -1)
60         close(mSock);
61 
62     if (mCtrlPipe[0] != -1) {
63         close(mCtrlPipe[0]);
64         close(mCtrlPipe[1]);
65     }
66     SocketClientCollection::iterator it;
67     for (it = mClients->begin(); it != mClients->end();) {
68         (*it)->decRef();
69         it = mClients->erase(it);
70     }
71     delete mClients;
72 }
73 
startListener()74 int SocketListener::startListener() {
75     return startListener(4);
76 }
77 
startListener(int backlog)78 int SocketListener::startListener(int backlog) {
79 
80     if (!mSocketName && mSock == -1) {
81         SLOGE("Failed to start unbound listener");
82         errno = EINVAL;
83         return -1;
84     } else if (mSocketName) {
85         if ((mSock = android_get_control_socket(mSocketName)) < 0) {
86             SLOGE("Obtaining file descriptor socket '%s' failed: %s",
87                  mSocketName, strerror(errno));
88             return -1;
89         }
90         SLOGV("got mSock = %d for %s", mSock, mSocketName);
91         fcntl(mSock, F_SETFD, FD_CLOEXEC);
92     }
93 
94     if (mListen && listen(mSock, backlog) < 0) {
95         SLOGE("Unable to listen on socket (%s)", strerror(errno));
96         return -1;
97     } else if (!mListen)
98         mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
99 
100     if (pipe(mCtrlPipe)) {
101         SLOGE("pipe failed (%s)", strerror(errno));
102         return -1;
103     }
104 
105     if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
106         SLOGE("pthread_create (%s)", strerror(errno));
107         return -1;
108     }
109 
110     return 0;
111 }
112 
stopListener()113 int SocketListener::stopListener() {
114     char c = CtrlPipe_Shutdown;
115     int  rc;
116 
117     rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
118     if (rc != 1) {
119         SLOGE("Error writing to control pipe (%s)", strerror(errno));
120         return -1;
121     }
122 
123     void *ret;
124     if (pthread_join(mThread, &ret)) {
125         SLOGE("Error joining to listener thread (%s)", strerror(errno));
126         return -1;
127     }
128     close(mCtrlPipe[0]);
129     close(mCtrlPipe[1]);
130     mCtrlPipe[0] = -1;
131     mCtrlPipe[1] = -1;
132 
133     if (mSocketName && mSock > -1) {
134         close(mSock);
135         mSock = -1;
136     }
137 
138     SocketClientCollection::iterator it;
139     for (it = mClients->begin(); it != mClients->end();) {
140         delete (*it);
141         it = mClients->erase(it);
142     }
143     return 0;
144 }
145 
threadStart(void * obj)146 void *SocketListener::threadStart(void *obj) {
147     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
148 
149     me->runListener();
150     pthread_exit(NULL);
151     return NULL;
152 }
153 
runListener()154 void SocketListener::runListener() {
155 
156     SocketClientCollection pendingList;
157 
158     while(1) {
159         SocketClientCollection::iterator it;
160         fd_set read_fds;
161         int rc = 0;
162         int max = -1;
163 
164         FD_ZERO(&read_fds);
165 
166         if (mListen) {
167             max = mSock;
168             FD_SET(mSock, &read_fds);
169         }
170 
171         FD_SET(mCtrlPipe[0], &read_fds);
172         if (mCtrlPipe[0] > max)
173             max = mCtrlPipe[0];
174 
175         pthread_mutex_lock(&mClientsLock);
176         for (it = mClients->begin(); it != mClients->end(); ++it) {
177             // NB: calling out to an other object with mClientsLock held (safe)
178             int fd = (*it)->getSocket();
179             FD_SET(fd, &read_fds);
180             if (fd > max) {
181                 max = fd;
182             }
183         }
184         pthread_mutex_unlock(&mClientsLock);
185         SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
186         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
187             if (errno == EINTR)
188                 continue;
189             SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
190             sleep(1);
191             continue;
192         } else if (!rc)
193             continue;
194 
195         if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
196             char c = CtrlPipe_Shutdown;
197             TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
198             if (c == CtrlPipe_Shutdown) {
199                 break;
200             }
201             continue;
202         }
203         if (mListen && FD_ISSET(mSock, &read_fds)) {
204             int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
205             if (c < 0) {
206                 SLOGE("accept failed (%s)", strerror(errno));
207                 sleep(1);
208                 continue;
209             }
210             pthread_mutex_lock(&mClientsLock);
211             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
212             pthread_mutex_unlock(&mClientsLock);
213         }
214 
215         /* Add all active clients to the pending list first */
216         pendingList.clear();
217         pthread_mutex_lock(&mClientsLock);
218         for (it = mClients->begin(); it != mClients->end(); ++it) {
219             SocketClient* c = *it;
220             // NB: calling out to an other object with mClientsLock held (safe)
221             int fd = c->getSocket();
222             if (FD_ISSET(fd, &read_fds)) {
223                 pendingList.push_back(c);
224                 c->incRef();
225             }
226         }
227         pthread_mutex_unlock(&mClientsLock);
228 
229         /* Process the pending list, since it is owned by the thread,
230          * there is no need to lock it */
231         while (!pendingList.empty()) {
232             /* Pop the first item from the list */
233             it = pendingList.begin();
234             SocketClient* c = *it;
235             pendingList.erase(it);
236             /* Process it, if false is returned, remove from list */
237             if (!onDataAvailable(c)) {
238                 release(c, false);
239             }
240             c->decRef();
241         }
242     }
243 }
244 
release(SocketClient * c,bool wakeup)245 bool SocketListener::release(SocketClient* c, bool wakeup) {
246     bool ret = false;
247     /* if our sockets are connection-based, remove and destroy it */
248     if (mListen && c) {
249         /* Remove the client from our array */
250         SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
251         pthread_mutex_lock(&mClientsLock);
252         SocketClientCollection::iterator it;
253         for (it = mClients->begin(); it != mClients->end(); ++it) {
254             if (*it == c) {
255                 mClients->erase(it);
256                 ret = true;
257                 break;
258             }
259         }
260         pthread_mutex_unlock(&mClientsLock);
261         if (ret) {
262             ret = c->decRef();
263             if (wakeup) {
264                 char b = CtrlPipe_Wakeup;
265                 TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
266             }
267         }
268     }
269     return ret;
270 }
271 
sendBroadcast(int code,const char * msg,bool addErrno)272 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
273     SocketClientCollection safeList;
274 
275     /* Add all active clients to the safe list first */
276     safeList.clear();
277     pthread_mutex_lock(&mClientsLock);
278     SocketClientCollection::iterator i;
279 
280     for (i = mClients->begin(); i != mClients->end(); ++i) {
281         SocketClient* c = *i;
282         c->incRef();
283         safeList.push_back(c);
284     }
285     pthread_mutex_unlock(&mClientsLock);
286 
287     while (!safeList.empty()) {
288         /* Pop the first item from the list */
289         i = safeList.begin();
290         SocketClient* c = *i;
291         safeList.erase(i);
292         // broadcasts are unsolicited and should not include a cmd number
293         if (c->sendMsg(code, msg, addErrno, false)) {
294             SLOGW("Error sending broadcast (%s)", strerror(errno));
295         }
296         c->decRef();
297     }
298 }
299 
runOnEachSocket(SocketClientCommand * command)300 void SocketListener::runOnEachSocket(SocketClientCommand *command) {
301     SocketClientCollection safeList;
302 
303     /* Add all active clients to the safe list first */
304     safeList.clear();
305     pthread_mutex_lock(&mClientsLock);
306     SocketClientCollection::iterator i;
307 
308     for (i = mClients->begin(); i != mClients->end(); ++i) {
309         SocketClient* c = *i;
310         c->incRef();
311         safeList.push_back(c);
312     }
313     pthread_mutex_unlock(&mClientsLock);
314 
315     while (!safeList.empty()) {
316         /* Pop the first item from the list */
317         i = safeList.begin();
318         SocketClient* c = *i;
319         safeList.erase(i);
320         command->runSocketCommand(c);
321         c->decRef();
322     }
323 }
324