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