SocketListener.cpp revision dc58e73071aa829a5038caf37211f6b3e2d7b275
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 DBG 0
33
34SocketListener::SocketListener(const char *socketName, bool listen) {
35    mListen = listen;
36    mSocketName = socketName;
37    mSock = -1;
38    pthread_mutex_init(&mClientsLock, NULL);
39    mClients = new SocketClientCollection();
40}
41
42SocketListener::SocketListener(int socketFd, bool listen) {
43    mListen = listen;
44    mSocketName = NULL;
45    mSock = socketFd;
46    pthread_mutex_init(&mClientsLock, NULL);
47    mClients = new SocketClientCollection();
48}
49
50SocketListener::~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;
59    for (it = mClients->begin(); it != mClients->end();) {
60        (*it)->decRef();
61        it = mClients->erase(it);
62    }
63    delete mClients;
64}
65
66int SocketListener::startListener() {
67
68    if (!mSocketName && mSock == -1) {
69        SLOGE("Failed to start unbound listener");
70        errno = EINVAL;
71        return -1;
72    } else if (mSocketName) {
73        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
74            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
75                 mSocketName, strerror(errno));
76            return -1;
77        }
78        if (DBG) SLOGE("got mSock = %d for %s", mSock, mSocketName);
79    }
80
81    if (mListen && listen(mSock, 4) < 0) {
82        SLOGE("Unable to listen on socket (%s)", strerror(errno));
83        return -1;
84    } else if (!mListen)
85        mClients->push_back(new SocketClient(mSock, false));
86
87    if (pipe(mCtrlPipe)) {
88        SLOGE("pipe failed (%s)", strerror(errno));
89        return -1;
90    }
91
92    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
93        SLOGE("pthread_create (%s)", strerror(errno));
94        return -1;
95    }
96
97    return 0;
98}
99
100int SocketListener::stopListener() {
101    char c = 0;
102    int  rc;
103
104    rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
105    if (rc != 1) {
106        SLOGE("Error writing to control pipe (%s)", strerror(errno));
107        return -1;
108    }
109
110    void *ret;
111    if (pthread_join(mThread, &ret)) {
112        SLOGE("Error joining to listener thread (%s)", strerror(errno));
113        return -1;
114    }
115    close(mCtrlPipe[0]);
116    close(mCtrlPipe[1]);
117    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;
126    for (it = mClients->begin(); it != mClients->end();) {
127        delete (*it);
128        it = mClients->erase(it);
129    }
130    return 0;
131}
132
133void *SocketListener::threadStart(void *obj) {
134    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
135
136    me->runListener();
137    pthread_exit(NULL);
138    return NULL;
139}
140
141void SocketListener::runListener() {
142
143    SocketClientCollection *pendingList = new SocketClientCollection();
144
145    while(1) {
146        SocketClientCollection::iterator it;
147        fd_set read_fds;
148        int rc = 0;
149        int max = -1;
150
151        FD_ZERO(&read_fds);
152
153        if (mListen) {
154            max = mSock;
155            FD_SET(mSock, &read_fds);
156        }
157
158        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) {
164            int fd = (*it)->getSocket();
165            FD_SET(fd, &read_fds);
166            if (fd > max)
167                max = fd;
168        }
169        pthread_mutex_unlock(&mClientsLock);
170        if (DBG) SLOGE("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
171        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
172            if (errno == EINTR)
173                continue;
174            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
175            sleep(1);
176            continue;
177        } else if (!rc)
178            continue;
179
180        if (FD_ISSET(mCtrlPipe[0], &read_fds))
181            break;
182        if (mListen && FD_ISSET(mSock, &read_fds)) {
183            struct sockaddr addr;
184            socklen_t alen;
185            int c;
186
187            do {
188                alen = sizeof(addr);
189                c = accept(mSock, &addr, &alen);
190                if (DBG) SLOGE("%s got %d from accept", mSocketName, c);
191            } while (c < 0 && errno == EINTR);
192            if (c < 0) {
193                SLOGE("accept failed (%s)", strerror(errno));
194                sleep(1);
195                continue;
196            }
197            pthread_mutex_lock(&mClientsLock);
198            mClients->push_back(new SocketClient(c, true));
199            pthread_mutex_unlock(&mClientsLock);
200        }
201
202        /* 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);
209            }
210        }
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);
220            /* Process it, if false is returned and our sockets are
221             * connection-based, remove and destroy it */
222            if (!onDataAvailable(c) && mListen) {
223                /* Remove the client from our array */
224                if (DBG) SLOGE("going to zap %d for %s", c->getSocket(), mSocketName);
225                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);
233                /* Remove our reference to the client */
234                c->decRef();
235            }
236        }
237    }
238    delete pendingList;
239}
240
241void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
242    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)) {
247            SLOGW("Error sending broadcast (%s)", strerror(errno));
248        }
249    }
250    pthread_mutex_unlock(&mClientsLock);
251}
252