Home | History | Annotate | Download | only in src
      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 
     34 SocketListener::SocketListener(const char *socketName, bool listen) {
     35     init(socketName, -1, listen, false);
     36 }
     37 
     38 SocketListener::SocketListener(int socketFd, bool listen) {
     39     init(NULL, socketFd, listen, false);
     40 }
     41 
     42 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
     43     init(socketName, -1, listen, useCmdNum);
     44 }
     45 
     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 
     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 
     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 
    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 
    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 
    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 
    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