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