• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SocketListener(const char * socketName,bool listen)34 SocketListener::SocketListener(const char *socketName, bool listen) {
35     init(socketName, -1, listen, false);
36 }
37 
SocketListener(int socketFd,bool listen)38 SocketListener::SocketListener(int socketFd, bool listen) {
39     init(NULL, socketFd, listen, false);
40 }
41 
SocketListener(const char * socketName,bool listen,bool useCmdNum)42 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
43     init(socketName, -1, listen, useCmdNum);
44 }
45 
init(const char * socketName,int socketFd,bool listen,bool useCmdNum)46 void 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 
~SocketListener()55 SocketListener::~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 
startListener()71 int 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 
stopListener()105 int 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 
threadStart(void * obj)138 void *SocketListener::threadStart(void *obj) {
139     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
140 
141     me->runListener();
142     pthread_exit(NULL);
143     return NULL;
144 }
145 
runListener()146 void 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 
sendBroadcast(int code,const char * msg,bool addErrno)246 void 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