SocketListener.cpp revision 8702bb17f40022e970e8acd40b348d074e39afc7
1/*
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>
27#include <cutils/sockets.h>
28
29#include <sysutils/SocketListener.h>
30#include <sysutils/SocketClient.h>
31
32#define LOG_NDEBUG 0
33
34SocketListener::SocketListener(const char *socketName, bool listen) {
35    init(socketName, -1, listen, false);
36}
37
38SocketListener::SocketListener(int socketFd, bool listen) {
39    init(NULL, socketFd, listen, false);
40}
41
42SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
43    init(socketName, -1, listen, useCmdNum);
44}
45
46void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
47    mListen = listen;
48    mSocketName = socketName;
49    mSock = socketFd;
50    mUseCmdNum = useCmdNum;
51    pthread_mutex_init(&mClientsLock, NULL);
52    mClients = new SocketClientCollection();
53}
54
55SocketListener::~SocketListener() {
56    if (mSocketName && mSock > -1)
57        close(mSock);
58
59    if (mCtrlPipe[0] != -1) {
60        close(mCtrlPipe[0]);
61        close(mCtrlPipe[1]);
62    }
63    SocketClientCollection::iterator it;
64    for (it = mClients->begin(); it != mClients->end();) {
65        (*it)->decRef();
66        it = mClients->erase(it);
67    }
68    delete mClients;
69}
70
71int SocketListener::startListener() {
72
73    if (!mSocketName && mSock == -1) {
74        SLOGE("Failed to start unbound listener");
75        errno = EINVAL;
76        return -1;
77    } else if (mSocketName) {
78        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
79            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
80                 mSocketName, strerror(errno));
81            return -1;
82        }
83        SLOGV("got mSock = %d for %s", mSock, mSocketName);
84    }
85
86    if (mListen && listen(mSock, 4) < 0) {
87        SLOGE("Unable to listen on socket (%s)", strerror(errno));
88        return -1;
89    } else if (!mListen)
90        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
91
92    if (pipe(mCtrlPipe)) {
93        SLOGE("pipe failed (%s)", strerror(errno));
94        return -1;
95    }
96
97    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
98        SLOGE("pthread_create (%s)", strerror(errno));
99        return -1;
100    }
101
102    return 0;
103}
104
105int SocketListener::stopListener() {
106    char c = 0;
107    int  rc;
108
109    rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
110    if (rc != 1) {
111        SLOGE("Error writing to control pipe (%s)", strerror(errno));
112        return -1;
113    }
114
115    void *ret;
116    if (pthread_join(mThread, &ret)) {
117        SLOGE("Error joining to listener thread (%s)", strerror(errno));
118        return -1;
119    }
120    close(mCtrlPipe[0]);
121    close(mCtrlPipe[1]);
122    mCtrlPipe[0] = -1;
123    mCtrlPipe[1] = -1;
124
125    if (mSocketName && mSock > -1) {
126        close(mSock);
127        mSock = -1;
128    }
129
130    SocketClientCollection::iterator it;
131    for (it = mClients->begin(); it != mClients->end();) {
132        delete (*it);
133        it = mClients->erase(it);
134    }
135    return 0;
136}
137
138void *SocketListener::threadStart(void *obj) {
139    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
140
141    me->runListener();
142    pthread_exit(NULL);
143    return NULL;
144}
145
146void SocketListener::runListener() {
147
148    SocketClientCollection *pendingList = new SocketClientCollection();
149
150    while(1) {
151        SocketClientCollection::iterator it;
152        fd_set read_fds;
153        int rc = 0;
154        int max = -1;
155
156        FD_ZERO(&read_fds);
157
158        if (mListen) {
159            max = mSock;
160            FD_SET(mSock, &read_fds);
161        }
162
163        FD_SET(mCtrlPipe[0], &read_fds);
164        if (mCtrlPipe[0] > max)
165            max = mCtrlPipe[0];
166
167        pthread_mutex_lock(&mClientsLock);
168        for (it = mClients->begin(); it != mClients->end(); ++it) {
169            int fd = (*it)->getSocket();
170            FD_SET(fd, &read_fds);
171            if (fd > max)
172                max = fd;
173        }
174        pthread_mutex_unlock(&mClientsLock);
175        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
176        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
177            if (errno == EINTR)
178                continue;
179            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
180            sleep(1);
181            continue;
182        } else if (!rc)
183            continue;
184
185        if (FD_ISSET(mCtrlPipe[0], &read_fds))
186            break;
187        if (mListen && FD_ISSET(mSock, &read_fds)) {
188            struct sockaddr addr;
189            socklen_t alen;
190            int c;
191
192            do {
193                alen = sizeof(addr);
194                c = accept(mSock, &addr, &alen);
195                SLOGV("%s got %d from accept", mSocketName, c);
196            } while (c < 0 && errno == EINTR);
197            if (c < 0) {
198                SLOGE("accept failed (%s)", strerror(errno));
199                sleep(1);
200                continue;
201            }
202            pthread_mutex_lock(&mClientsLock);
203            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
204            pthread_mutex_unlock(&mClientsLock);
205        }
206
207        /* Add all active clients to the pending list first */
208        pendingList->clear();
209        pthread_mutex_lock(&mClientsLock);
210        for (it = mClients->begin(); it != mClients->end(); ++it) {
211            int fd = (*it)->getSocket();
212            if (FD_ISSET(fd, &read_fds)) {
213                pendingList->push_back(*it);
214            }
215        }
216        pthread_mutex_unlock(&mClientsLock);
217
218        /* Process the pending list, since it is owned by the thread,
219         * there is no need to lock it */
220        while (!pendingList->empty()) {
221            /* Pop the first item from the list */
222            it = pendingList->begin();
223            SocketClient* c = *it;
224            pendingList->erase(it);
225            /* Process it, if false is returned and our sockets are
226             * connection-based, remove and destroy it */
227            if (!onDataAvailable(c) && mListen) {
228                /* Remove the client from our array */
229                SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
230                pthread_mutex_lock(&mClientsLock);
231                for (it = mClients->begin(); it != mClients->end(); ++it) {
232                    if (*it == c) {
233                        mClients->erase(it);
234                        break;
235                    }
236                }
237                pthread_mutex_unlock(&mClientsLock);
238                /* Remove our reference to the client */
239                c->decRef();
240            }
241        }
242    }
243    delete pendingList;
244}
245
246void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
247    pthread_mutex_lock(&mClientsLock);
248    SocketClientCollection::iterator i;
249
250    for (i = mClients->begin(); i != mClients->end(); ++i) {
251        // broadcasts are unsolicited and should not include a cmd number
252        if ((*i)->sendMsg(code, msg, addErrno, false)) {
253            SLOGW("Error sending broadcast (%s)", strerror(errno));
254        }
255    }
256    pthread_mutex_unlock(&mClientsLock);
257}
258