Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2009-2016 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 
     17 #define LOG_TAG "SocketClient"
     18 
     19 #include <alloca.h>
     20 #include <arpa/inet.h>
     21 #include <errno.h>
     22 #include <malloc.h>
     23 #include <pthread.h>
     24 #include <signal.h>
     25 #include <string.h>
     26 #include <sys/socket.h>
     27 #include <sys/types.h>
     28 #include <unistd.h>
     29 
     30 #include <log/log.h>
     31 #include <sysutils/SocketClient.h>
     32 
     33 SocketClient::SocketClient(int socket, bool owned) {
     34     init(socket, owned, false);
     35 }
     36 
     37 SocketClient::SocketClient(int socket, bool owned, bool useCmdNum) {
     38     init(socket, owned, useCmdNum);
     39 }
     40 
     41 void SocketClient::init(int socket, bool owned, bool useCmdNum) {
     42     mSocket = socket;
     43     mSocketOwned = owned;
     44     mUseCmdNum = useCmdNum;
     45     pthread_mutex_init(&mWriteMutex, NULL);
     46     pthread_mutex_init(&mRefCountMutex, NULL);
     47     mPid = -1;
     48     mUid = -1;
     49     mGid = -1;
     50     mRefCount = 1;
     51     mCmdNum = 0;
     52 
     53     struct ucred creds;
     54     socklen_t szCreds = sizeof(creds);
     55     memset(&creds, 0, szCreds);
     56 
     57     int err = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
     58     if (err == 0) {
     59         mPid = creds.pid;
     60         mUid = creds.uid;
     61         mGid = creds.gid;
     62     }
     63 }
     64 
     65 SocketClient::~SocketClient() {
     66     if (mSocketOwned) {
     67         close(mSocket);
     68     }
     69 }
     70 
     71 int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
     72     return sendMsg(code, msg, addErrno, mUseCmdNum);
     73 }
     74 
     75 int SocketClient::sendMsg(int code, const char *msg, bool addErrno, bool useCmdNum) {
     76     char *buf;
     77     int ret = 0;
     78 
     79     if (addErrno) {
     80         if (useCmdNum) {
     81             ret = asprintf(&buf, "%d %d %s (%s)", code, getCmdNum(), msg, strerror(errno));
     82         } else {
     83             ret = asprintf(&buf, "%d %s (%s)", code, msg, strerror(errno));
     84         }
     85     } else {
     86         if (useCmdNum) {
     87             ret = asprintf(&buf, "%d %d %s", code, getCmdNum(), msg);
     88         } else {
     89             ret = asprintf(&buf, "%d %s", code, msg);
     90         }
     91     }
     92     // Send the zero-terminated message
     93     if (ret != -1) {
     94         ret = sendMsg(buf);
     95         free(buf);
     96     }
     97     return ret;
     98 }
     99 
    100 // send 3-digit code, null, binary-length, binary data
    101 int SocketClient::sendBinaryMsg(int code, const void *data, int len) {
    102 
    103     // 4 bytes for the code & null + 4 bytes for the len
    104     char buf[8];
    105     // Write the code
    106     snprintf(buf, 4, "%.3d", code);
    107     // Write the len
    108     uint32_t tmp = htonl(len);
    109     memcpy(buf + 4, &tmp, sizeof(uint32_t));
    110 
    111     struct iovec vec[2];
    112     vec[0].iov_base = (void *) buf;
    113     vec[0].iov_len = sizeof(buf);
    114     vec[1].iov_base = (void *) data;
    115     vec[1].iov_len = len;
    116 
    117     pthread_mutex_lock(&mWriteMutex);
    118     int result = sendDataLockedv(vec, (len > 0) ? 2 : 1);
    119     pthread_mutex_unlock(&mWriteMutex);
    120 
    121     return result;
    122 }
    123 
    124 // Sends the code (c-string null-terminated).
    125 int SocketClient::sendCode(int code) {
    126     char buf[4];
    127     snprintf(buf, sizeof(buf), "%.3d", code);
    128     return sendData(buf, sizeof(buf));
    129 }
    130 
    131 char *SocketClient::quoteArg(const char *arg) {
    132     int len = strlen(arg);
    133     char *result = (char *)malloc(len * 2 + 3);
    134     char *current = result;
    135     const char *end = arg + len;
    136     char *oldresult;
    137 
    138     if(result == NULL) {
    139         SLOGW("malloc error (%s)", strerror(errno));
    140         return NULL;
    141     }
    142 
    143     *(current++) = '"';
    144     while (arg < end) {
    145         switch (*arg) {
    146         case '\\':
    147         case '"':
    148             *(current++) = '\\'; // fallthrough
    149         default:
    150             *(current++) = *(arg++);
    151         }
    152     }
    153     *(current++) = '"';
    154     *(current++) = '\0';
    155     oldresult = result; // save pointer in case realloc fails
    156     result = (char *)realloc(result, current-result);
    157     return result ? result : oldresult;
    158 }
    159 
    160 
    161 int SocketClient::sendMsg(const char *msg) {
    162     // Send the message including null character
    163     if (sendData(msg, strlen(msg) + 1) != 0) {
    164         SLOGW("Unable to send msg '%s'", msg);
    165         return -1;
    166     }
    167     return 0;
    168 }
    169 
    170 int SocketClient::sendData(const void *data, int len) {
    171     struct iovec vec[1];
    172     vec[0].iov_base = (void *) data;
    173     vec[0].iov_len = len;
    174 
    175     pthread_mutex_lock(&mWriteMutex);
    176     int rc = sendDataLockedv(vec, 1);
    177     pthread_mutex_unlock(&mWriteMutex);
    178 
    179     return rc;
    180 }
    181 
    182 int SocketClient::sendDatav(struct iovec *iov, int iovcnt) {
    183     pthread_mutex_lock(&mWriteMutex);
    184     int rc = sendDataLockedv(iov, iovcnt);
    185     pthread_mutex_unlock(&mWriteMutex);
    186 
    187     return rc;
    188 }
    189 
    190 int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) {
    191 
    192     if (mSocket < 0) {
    193         errno = EHOSTUNREACH;
    194         return -1;
    195     }
    196 
    197     if (iovcnt <= 0) {
    198         return 0;
    199     }
    200 
    201     int ret = 0;
    202     int e = 0; // SLOGW and sigaction are not inert regarding errno
    203     int current = 0;
    204 
    205     struct sigaction new_action, old_action;
    206     memset(&new_action, 0, sizeof(new_action));
    207     new_action.sa_handler = SIG_IGN;
    208     sigaction(SIGPIPE, &new_action, &old_action);
    209 
    210     for (;;) {
    211         ssize_t rc = TEMP_FAILURE_RETRY(
    212             writev(mSocket, iov + current, iovcnt - current));
    213 
    214         if (rc > 0) {
    215             size_t written = rc;
    216             while ((current < iovcnt) && (written >= iov[current].iov_len)) {
    217                 written -= iov[current].iov_len;
    218                 current++;
    219             }
    220             if (current == iovcnt) {
    221                 break;
    222             }
    223             iov[current].iov_base = (char *)iov[current].iov_base + written;
    224             iov[current].iov_len -= written;
    225             continue;
    226         }
    227 
    228         if (rc == 0) {
    229             e = EIO;
    230             SLOGW("0 length write :(");
    231         } else {
    232             e = errno;
    233             SLOGW("write error (%s)", strerror(e));
    234         }
    235         ret = -1;
    236         break;
    237     }
    238 
    239     sigaction(SIGPIPE, &old_action, &new_action);
    240 
    241     if (e != 0) {
    242         errno = e;
    243     }
    244     return ret;
    245 }
    246 
    247 void SocketClient::incRef() {
    248     pthread_mutex_lock(&mRefCountMutex);
    249     mRefCount++;
    250     pthread_mutex_unlock(&mRefCountMutex);
    251 }
    252 
    253 bool SocketClient::decRef() {
    254     bool deleteSelf = false;
    255     pthread_mutex_lock(&mRefCountMutex);
    256     mRefCount--;
    257     if (mRefCount == 0) {
    258         deleteSelf = true;
    259     } else if (mRefCount < 0) {
    260         SLOGE("SocketClient refcount went negative!");
    261     }
    262     pthread_mutex_unlock(&mRefCountMutex);
    263     if (deleteSelf) {
    264         delete this;
    265     }
    266     return deleteSelf;
    267 }
    268