SocketListener.cpp revision 03f0d27f6c49530a91402ed42f8ca4b2fda04b9f
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
48int SocketListener::startListener() {
49
50    if (!mSocketName && mSock == -1) {
51        errno = EINVAL;
52        return -1;
53    } else if (mSocketName) {
54        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
55            LOGE("Obtaining file descriptor socket '%s' failed: %s",
56                 mSocketName, strerror(errno));
57            return -1;
58        }
59    }
60
61    if (mListen && listen(mSock, 4) < 0) {
62        LOGE("Unable to listen on socket (%s)", strerror(errno));
63        return -1;
64    } else if (!mListen)
65        mClients->push_back(new SocketClient(mSock));
66
67    if (pipe(mCtrlPipe))
68        return -1;
69
70    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this))
71        return -1;
72
73    return 0;
74}
75
76int SocketListener::stopListener() {
77    char c = 0;
78
79    if (write(mCtrlPipe[1], &c, 1) != 1) {
80        LOGE("Error writing to control pipe (%s)", strerror(errno));
81        return -1;
82    }
83
84    void *ret;
85    if (pthread_join(mThread, &ret)) {
86        LOGE("Error joining to listener thread (%s)", strerror(errno));
87        return -1;
88    }
89    close(mCtrlPipe[0]);
90    close(mCtrlPipe[1]);
91    return 0;
92}
93
94void *SocketListener::threadStart(void *obj) {
95    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
96
97    me->runListener();
98    pthread_exit(NULL);
99    return NULL;
100}
101
102void SocketListener::runListener() {
103
104    while(1) {
105        SocketClientCollection::iterator it;
106        fd_set read_fds;
107        int rc = 0;
108        int max = 0;
109
110        FD_ZERO(&read_fds);
111
112        if (mListen) {
113            max = mSock;
114            FD_SET(mSock, &read_fds);
115        }
116
117        FD_SET(mCtrlPipe[0], &read_fds);
118        if (mCtrlPipe[0] > max)
119            max = mCtrlPipe[0];
120
121        pthread_mutex_lock(&mClientsLock);
122        for (it = mClients->begin(); it != mClients->end(); ++it) {
123            FD_SET((*it)->getSocket(), &read_fds);
124            if ((*it)->getSocket() > max)
125                max = (*it)->getSocket();
126        }
127        pthread_mutex_unlock(&mClientsLock);
128
129        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
130            LOGE("select failed (%s)", strerror(errno));
131            sleep(1);
132            continue;
133        } else if (!rc)
134            continue;
135
136        if (FD_ISSET(mCtrlPipe[0], &read_fds))
137            break;
138        if (mListen && FD_ISSET(mSock, &read_fds)) {
139            struct sockaddr addr;
140            socklen_t alen = sizeof(addr);
141            int c;
142
143            if ((c = accept(mSock, &addr, &alen)) < 0) {
144                LOGE("accept failed (%s)", strerror(errno));
145                sleep(1);
146                continue;
147            }
148            pthread_mutex_lock(&mClientsLock);
149            mClients->push_back(new SocketClient(c));
150            pthread_mutex_unlock(&mClientsLock);
151        }
152
153        do {
154            pthread_mutex_lock(&mClientsLock);
155            for (it = mClients->begin(); it != mClients->end(); ++it) {
156                int fd = (*it)->getSocket();
157                if (FD_ISSET(fd, &read_fds)) {
158                    pthread_mutex_unlock(&mClientsLock);
159                    if (!onDataAvailable(*it)) {
160                        LOGD("SocketListener closing client socket");
161                        close(fd);
162                        pthread_mutex_lock(&mClientsLock);
163                        delete *it;
164                        it = mClients->erase(it);
165                        pthread_mutex_unlock(&mClientsLock);
166                    }
167                    FD_CLR(fd, &read_fds);
168                    continue;
169                }
170            }
171            pthread_mutex_unlock(&mClientsLock);
172        } while (0);
173    }
174}
175
176void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
177    pthread_mutex_lock(&mClientsLock);
178    SocketClientCollection::iterator i;
179
180    for (i = mClients->begin(); i != mClients->end(); ++i) {
181        if ((*i)->sendMsg(code, msg, addErrno)) {
182            LOGW("Error sending broadcast (%s)", strerror(errno));
183        }
184    }
185    pthread_mutex_unlock(&mClientsLock);
186}
187
188void SocketListener::sendBroadcast(const char *msg) {
189    pthread_mutex_lock(&mClientsLock);
190    SocketClientCollection::iterator i;
191
192    for (i = mClients->begin(); i != mClients->end(); ++i) {
193        if ((*i)->sendMsg(msg)) {
194            LOGW("Error sending broadcast (%s)", strerror(errno));
195        }
196    }
197    pthread_mutex_unlock(&mClientsLock);
198}
199