SocketListener.cpp revision c4a895b7094461c98101924cf096680bfb7856f1
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(); ++it) {
58        delete (*it);
59        it = mClients->erase(it);
60    }
61    delete mClients;
62}
63
64int SocketListener::startListener() {
65
66    if (!mSocketName && mSock == -1) {
67        LOGE("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            LOGE("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        LOGE("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        LOGE("pipe failed (%s)", strerror(errno));
86        return -1;
87    }
88
89    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
90        LOGE("pthread_create (%s)", strerror(errno));
91        return -1;
92    }
93
94    return 0;
95}
96
97int SocketListener::stopListener() {
98    char c = 0;
99
100    if (write(mCtrlPipe[1], &c, 1) != 1) {
101        LOGE("Error writing to control pipe (%s)", strerror(errno));
102        return -1;
103    }
104
105    void *ret;
106    if (pthread_join(mThread, &ret)) {
107        LOGE("Error joining to listener thread (%s)", strerror(errno));
108        return -1;
109    }
110    close(mCtrlPipe[0]);
111    close(mCtrlPipe[1]);
112    mCtrlPipe[0] = -1;
113    mCtrlPipe[1] = -1;
114
115    if (mSocketName && mSock > -1) {
116        close(mSock);
117        mSock = -1;
118    }
119
120    SocketClientCollection::iterator it;
121    for (it = mClients->begin(); it != mClients->end(); ++it) {
122        delete (*it);
123        it = mClients->erase(it);
124    }
125    return 0;
126}
127
128void *SocketListener::threadStart(void *obj) {
129    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
130
131    me->runListener();
132    pthread_exit(NULL);
133    return NULL;
134}
135
136void SocketListener::runListener() {
137
138    while(1) {
139        SocketClientCollection::iterator it;
140        fd_set read_fds;
141        int rc = 0;
142        int max = 0;
143
144        FD_ZERO(&read_fds);
145
146        if (mListen) {
147            max = mSock;
148            FD_SET(mSock, &read_fds);
149        }
150
151        FD_SET(mCtrlPipe[0], &read_fds);
152        if (mCtrlPipe[0] > max)
153            max = mCtrlPipe[0];
154
155        pthread_mutex_lock(&mClientsLock);
156        for (it = mClients->begin(); it != mClients->end(); ++it) {
157            FD_SET((*it)->getSocket(), &read_fds);
158            if ((*it)->getSocket() > max)
159                max = (*it)->getSocket();
160        }
161        pthread_mutex_unlock(&mClientsLock);
162
163        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
164            LOGE("select failed (%s)", strerror(errno));
165            sleep(1);
166            continue;
167        } else if (!rc)
168            continue;
169
170        if (FD_ISSET(mCtrlPipe[0], &read_fds))
171            break;
172        if (mListen && FD_ISSET(mSock, &read_fds)) {
173            struct sockaddr addr;
174            socklen_t alen = sizeof(addr);
175            int c;
176
177            if ((c = accept(mSock, &addr, &alen)) < 0) {
178                LOGE("accept failed (%s)", strerror(errno));
179                sleep(1);
180                continue;
181            }
182            pthread_mutex_lock(&mClientsLock);
183            mClients->push_back(new SocketClient(c));
184            pthread_mutex_unlock(&mClientsLock);
185        }
186
187        do {
188            pthread_mutex_lock(&mClientsLock);
189            for (it = mClients->begin(); it != mClients->end(); ++it) {
190                int fd = (*it)->getSocket();
191                if (FD_ISSET(fd, &read_fds)) {
192                    pthread_mutex_unlock(&mClientsLock);
193                    if (!onDataAvailable(*it)) {
194                        close(fd);
195                        pthread_mutex_lock(&mClientsLock);
196                        delete *it;
197                        it = mClients->erase(it);
198                        pthread_mutex_unlock(&mClientsLock);
199                    }
200                    FD_CLR(fd, &read_fds);
201                    continue;
202                }
203            }
204            pthread_mutex_unlock(&mClientsLock);
205        } while (0);
206    }
207}
208
209void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
210    pthread_mutex_lock(&mClientsLock);
211    SocketClientCollection::iterator i;
212
213    for (i = mClients->begin(); i != mClients->end(); ++i) {
214        if ((*i)->sendMsg(code, msg, addErrno)) {
215            LOGW("Error sending broadcast (%s)", strerror(errno));
216        }
217    }
218    pthread_mutex_unlock(&mClientsLock);
219}
220
221void SocketListener::sendBroadcast(const char *msg) {
222    pthread_mutex_lock(&mClientsLock);
223    SocketClientCollection::iterator i;
224
225    for (i = mClients->begin(); i != mClients->end(); ++i) {
226        if ((*i)->sendMsg(msg)) {
227            LOGW("Error sending broadcast (%s)", strerror(errno));
228        }
229    }
230    pthread_mutex_unlock(&mClientsLock);
231}
232