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