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