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             sockaddr_storage ss;
    203             sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
    204             socklen_t alen;
    205             int c;
    206 
    207             do {
    208                 alen = sizeof(ss);
    209                 c = accept(mSock, addrp, &alen);
    210                 SLOGV("%s got %d from accept", mSocketName, c);
    211             } while (c < 0 && errno == EINTR);
    212             if (c < 0) {
    213                 SLOGE("accept failed (%s)", strerror(errno));
    214                 sleep(1);
    215                 continue;
    216             }
    217             fcntl(c, F_SETFD, FD_CLOEXEC);
    218             pthread_mutex_lock(&mClientsLock);
    219             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
    220             pthread_mutex_unlock(&mClientsLock);
    221         }
    222 
    223         /* Add all active clients to the pending list first */
    224         pendingList.clear();
    225         pthread_mutex_lock(&mClientsLock);
    226         for (it = mClients->begin(); it != mClients->end(); ++it) {
    227             SocketClient* c = *it;
    228             // NB: calling out to an other object with mClientsLock held (safe)
    229             int fd = c->getSocket();
    230             if (FD_ISSET(fd, &read_fds)) {
    231                 pendingList.push_back(c);
    232                 c->incRef();
    233             }
    234         }
    235         pthread_mutex_unlock(&mClientsLock);
    236 
    237         /* Process the pending list, since it is owned by the thread,
    238          * there is no need to lock it */
    239         while (!pendingList.empty()) {
    240             /* Pop the first item from the list */
    241             it = pendingList.begin();
    242             SocketClient* c = *it;
    243             pendingList.erase(it);
    244             /* Process it, if false is returned, remove from list */
    245             if (!onDataAvailable(c)) {
    246                 release(c, false);
    247             }
    248             c->decRef();
    249         }
    250     }
    251 }
    252 
    253 bool SocketListener::release(SocketClient* c, bool wakeup) {
    254     bool ret = false;
    255     /* if our sockets are connection-based, remove and destroy it */
    256     if (mListen && c) {
    257         /* Remove the client from our array */
    258         SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
    259         pthread_mutex_lock(&mClientsLock);
    260         SocketClientCollection::iterator it;
    261         for (it = mClients->begin(); it != mClients->end(); ++it) {
    262             if (*it == c) {
    263                 mClients->erase(it);
    264                 ret = true;
    265                 break;
    266             }
    267         }
    268         pthread_mutex_unlock(&mClientsLock);
    269         if (ret) {
    270             ret = c->decRef();
    271             if (wakeup) {
    272                 char b = CtrlPipe_Wakeup;
    273                 TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
    274             }
    275         }
    276     }
    277     return ret;
    278 }
    279 
    280 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
    281     SocketClientCollection safeList;
    282 
    283     /* Add all active clients to the safe list first */
    284     safeList.clear();
    285     pthread_mutex_lock(&mClientsLock);
    286     SocketClientCollection::iterator i;
    287 
    288     for (i = mClients->begin(); i != mClients->end(); ++i) {
    289         SocketClient* c = *i;
    290         c->incRef();
    291         safeList.push_back(c);
    292     }
    293     pthread_mutex_unlock(&mClientsLock);
    294 
    295     while (!safeList.empty()) {
    296         /* Pop the first item from the list */
    297         i = safeList.begin();
    298         SocketClient* c = *i;
    299         safeList.erase(i);
    300         // broadcasts are unsolicited and should not include a cmd number
    301         if (c->sendMsg(code, msg, addErrno, false)) {
    302             SLOGW("Error sending broadcast (%s)", strerror(errno));
    303         }
    304         c->decRef();
    305     }
    306 }
    307 
    308 void SocketListener::runOnEachSocket(SocketClientCommand *command) {
    309     SocketClientCollection safeList;
    310 
    311     /* Add all active clients to the safe list first */
    312     safeList.clear();
    313     pthread_mutex_lock(&mClientsLock);
    314     SocketClientCollection::iterator i;
    315 
    316     for (i = mClients->begin(); i != mClients->end(); ++i) {
    317         SocketClient* c = *i;
    318         c->incRef();
    319         safeList.push_back(c);
    320     }
    321     pthread_mutex_unlock(&mClientsLock);
    322 
    323     while (!safeList.empty()) {
    324         /* Pop the first item from the list */
    325         i = safeList.begin();
    326         SocketClient* c = *i;
    327         safeList.erase(i);
    328         command->runSocketCommand(c);
    329         c->decRef();
    330     }
    331 }
    332