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