Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2008-2014 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 CtrlPipe_Shutdown 0
     33 #define CtrlPipe_Wakeup   1
     34 
     35 SocketListener::SocketListener(const char *socketName, bool listen) {
     36     init(socketName, -1, listen, false);
     37 }
     38 
     39 SocketListener::SocketListener(int socketFd, bool listen) {
     40     init(NULL, socketFd, listen, false);
     41 }
     42 
     43 SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
     44     init(socketName, -1, listen, useCmdNum);
     45 }
     46 
     47 void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
     48     mListen = listen;
     49     mSocketName = socketName;
     50     mSock = socketFd;
     51     mUseCmdNum = useCmdNum;
     52     pthread_mutex_init(&mClientsLock, NULL);
     53     mClients = new SocketClientCollection();
     54 }
     55 
     56 SocketListener::~SocketListener() {
     57     if (mSocketName && mSock > -1)
     58         close(mSock);
     59 
     60     if (mCtrlPipe[0] != -1) {
     61         close(mCtrlPipe[0]);
     62         close(mCtrlPipe[1]);
     63     }
     64     SocketClientCollection::iterator it;
     65     for (it = mClients->begin(); it != mClients->end();) {
     66         (*it)->decRef();
     67         it = mClients->erase(it);
     68     }
     69     delete mClients;
     70 }
     71 
     72 int SocketListener::startListener() {
     73     return startListener(4);
     74 }
     75 
     76 int SocketListener::startListener(int backlog) {
     77 
     78     if (!mSocketName && mSock == -1) {
     79         SLOGE("Failed to start unbound listener");
     80         errno = EINVAL;
     81         return -1;
     82     } else if (mSocketName) {
     83         if ((mSock = android_get_control_socket(mSocketName)) < 0) {
     84             SLOGE("Obtaining file descriptor socket '%s' failed: %s",
     85                  mSocketName, strerror(errno));
     86             return -1;
     87         }
     88         SLOGV("got mSock = %d for %s", mSock, mSocketName);
     89     }
     90 
     91     if (mListen && listen(mSock, backlog) < 0) {
     92         SLOGE("Unable to listen on socket (%s)", strerror(errno));
     93         return -1;
     94     } else if (!mListen)
     95         mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
     96 
     97     if (pipe(mCtrlPipe)) {
     98         SLOGE("pipe failed (%s)", strerror(errno));
     99         return -1;
    100     }
    101 
    102     if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
    103         SLOGE("pthread_create (%s)", strerror(errno));
    104         return -1;
    105     }
    106 
    107     return 0;
    108 }
    109 
    110 int SocketListener::stopListener() {
    111     char c = CtrlPipe_Shutdown;
    112     int  rc;
    113 
    114     rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
    115     if (rc != 1) {
    116         SLOGE("Error writing to control pipe (%s)", strerror(errno));
    117         return -1;
    118     }
    119 
    120     void *ret;
    121     if (pthread_join(mThread, &ret)) {
    122         SLOGE("Error joining to listener thread (%s)", strerror(errno));
    123         return -1;
    124     }
    125     close(mCtrlPipe[0]);
    126     close(mCtrlPipe[1]);
    127     mCtrlPipe[0] = -1;
    128     mCtrlPipe[1] = -1;
    129 
    130     if (mSocketName && mSock > -1) {
    131         close(mSock);
    132         mSock = -1;
    133     }
    134 
    135     SocketClientCollection::iterator it;
    136     for (it = mClients->begin(); it != mClients->end();) {
    137         delete (*it);
    138         it = mClients->erase(it);
    139     }
    140     return 0;
    141 }
    142 
    143 void *SocketListener::threadStart(void *obj) {
    144     SocketListener *me = reinterpret_cast<SocketListener *>(obj);
    145 
    146     me->runListener();
    147     pthread_exit(NULL);
    148     return NULL;
    149 }
    150 
    151 void SocketListener::runListener() {
    152 
    153     SocketClientCollection pendingList;
    154 
    155     while(1) {
    156         SocketClientCollection::iterator it;
    157         fd_set read_fds;
    158         int rc = 0;
    159         int max = -1;
    160 
    161         FD_ZERO(&read_fds);
    162 
    163         if (mListen) {
    164             max = mSock;
    165             FD_SET(mSock, &read_fds);
    166         }
    167 
    168         FD_SET(mCtrlPipe[0], &read_fds);
    169         if (mCtrlPipe[0] > max)
    170             max = mCtrlPipe[0];
    171 
    172         pthread_mutex_lock(&mClientsLock);
    173         for (it = mClients->begin(); it != mClients->end(); ++it) {
    174             // NB: calling out to an other object with mClientsLock held (safe)
    175             int fd = (*it)->getSocket();
    176             FD_SET(fd, &read_fds);
    177             if (fd > max) {
    178                 max = fd;
    179             }
    180         }
    181         pthread_mutex_unlock(&mClientsLock);
    182         SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
    183         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
    184             if (errno == EINTR)
    185                 continue;
    186             SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
    187             sleep(1);
    188             continue;
    189         } else if (!rc)
    190             continue;
    191 
    192         if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
    193             char c = CtrlPipe_Shutdown;
    194             TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
    195             if (c == CtrlPipe_Shutdown) {
    196                 break;
    197             }
    198             continue;
    199         }
    200         if (mListen && FD_ISSET(mSock, &read_fds)) {
    201             struct sockaddr addr;
    202             socklen_t alen;
    203             int c;
    204 
    205             do {
    206                 alen = sizeof(addr);
    207                 c = accept(mSock, &addr, &alen);
    208                 SLOGV("%s got %d from accept", mSocketName, c);
    209             } while (c < 0 && errno == EINTR);
    210             if (c < 0) {
    211                 SLOGE("accept failed (%s)", strerror(errno));
    212                 sleep(1);
    213                 continue;
    214             }
    215             pthread_mutex_lock(&mClientsLock);
    216             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
    217             pthread_mutex_unlock(&mClientsLock);
    218         }
    219 
    220         /* Add all active clients to the pending list first */
    221         pendingList.clear();
    222         pthread_mutex_lock(&mClientsLock);
    223         for (it = mClients->begin(); it != mClients->end(); ++it) {
    224             SocketClient* c = *it;
    225             // NB: calling out to an other object with mClientsLock held (safe)
    226             int fd = c->getSocket();
    227             if (FD_ISSET(fd, &read_fds)) {
    228                 pendingList.push_back(c);
    229                 c->incRef();
    230             }
    231         }
    232         pthread_mutex_unlock(&mClientsLock);
    233 
    234         /* Process the pending list, since it is owned by the thread,
    235          * there is no need to lock it */
    236         while (!pendingList.empty()) {
    237             /* Pop the first item from the list */
    238             it = pendingList.begin();
    239             SocketClient* c = *it;
    240             pendingList.erase(it);
    241             /* Process it, if false is returned, remove from list */
    242             if (!onDataAvailable(c)) {
    243                 release(c, false);
    244             }
    245             c->decRef();
    246         }
    247     }
    248 }
    249 
    250 bool SocketListener::release(SocketClient* c, bool wakeup) {
    251     bool ret = false;
    252     /* if our sockets are connection-based, remove and destroy it */
    253     if (mListen && c) {
    254         /* Remove the client from our array */
    255         SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
    256         pthread_mutex_lock(&mClientsLock);
    257         SocketClientCollection::iterator it;
    258         for (it = mClients->begin(); it != mClients->end(); ++it) {
    259             if (*it == c) {
    260                 mClients->erase(it);
    261                 ret = true;
    262                 break;
    263             }
    264         }
    265         pthread_mutex_unlock(&mClientsLock);
    266         if (ret) {
    267             ret = c->decRef();
    268             if (wakeup) {
    269                 char b = CtrlPipe_Wakeup;
    270                 TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
    271             }
    272         }
    273     }
    274     return ret;
    275 }
    276 
    277 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
    278     SocketClientCollection safeList;
    279 
    280     /* Add all active clients to the safe list first */
    281     safeList.clear();
    282     pthread_mutex_lock(&mClientsLock);
    283     SocketClientCollection::iterator i;
    284 
    285     for (i = mClients->begin(); i != mClients->end(); ++i) {
    286         SocketClient* c = *i;
    287         c->incRef();
    288         safeList.push_back(c);
    289     }
    290     pthread_mutex_unlock(&mClientsLock);
    291 
    292     while (!safeList.empty()) {
    293         /* Pop the first item from the list */
    294         i = safeList.begin();
    295         SocketClient* c = *i;
    296         safeList.erase(i);
    297         // broadcasts are unsolicited and should not include a cmd number
    298         if (c->sendMsg(code, msg, addErrno, false)) {
    299             SLOGW("Error sending broadcast (%s)", strerror(errno));
    300         }
    301         c->decRef();
    302     }
    303 }
    304 
    305 void SocketListener::runOnEachSocket(SocketClientCommand *command) {
    306     SocketClientCollection safeList;
    307 
    308     /* Add all active clients to the safe list first */
    309     safeList.clear();
    310     pthread_mutex_lock(&mClientsLock);
    311     SocketClientCollection::iterator i;
    312 
    313     for (i = mClients->begin(); i != mClients->end(); ++i) {
    314         SocketClient* c = *i;
    315         c->incRef();
    316         safeList.push_back(c);
    317     }
    318     pthread_mutex_unlock(&mClientsLock);
    319 
    320     while (!safeList.empty()) {
    321         /* Pop the first item from the list */
    322         i = safeList.begin();
    323         SocketClient* c = *i;
    324         safeList.erase(i);
    325         command->runSocketCommand(c);
    326         c->decRef();
    327     }
    328 }
    329