1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Message stream abstraction.
5 //
6 #include "MessageStream.h"
7 #include "LogBundle.h"
8
9 #include "utils/Log.h"
10
11 #include <stdint.h>
12 #include <string.h>
13 #include <assert.h>
14
15 using namespace android;
16
17 /*
18 * ===========================================================================
19 * Message
20 * ===========================================================================
21 */
22
23 /*
24 * Send a blob of raw data.
25 */
setRaw(const unsigned char * data,int len,Cleanup cleanup)26 void Message::setRaw(const unsigned char* data, int len, Cleanup cleanup)
27 {
28 reset();
29
30 mData = const_cast<unsigned char*>(data);
31 mLength = len;
32 mCleanup = cleanup;
33 mType = kTypeRaw;
34 }
35
36 /*
37 * Send a "name=value" config pair.
38 */
setConfig(const char * name,const char * value)39 void Message::setConfig(const char* name, const char* value)
40 {
41 reset();
42
43 assert(name != NULL && value != NULL);
44
45 int nlen = strlen(name) +1;
46 int vlen = strlen(value) +1;
47 mData = new unsigned char[nlen+vlen];
48 mCleanup = kCleanupDelete;
49 mLength = nlen + vlen;
50 mType = kTypeConfig;
51
52 memcpy(mData, name, nlen);
53 memcpy(mData + nlen, value, vlen);
54 }
55
56 /*
57 * Try to return the contents of the message as if it were a name/value pair.
58 */
getConfig(const char ** pName,const char ** pValue)59 bool Message::getConfig(const char** pName, const char** pValue)
60 {
61 if (mLength < 2)
62 return false;
63 assert(mData != NULL);
64
65 *pName = (const char*) mData;
66 *pValue = (const char*) (mData + strlen((char*)mData) +1);
67 return true;
68 }
69
70 /*
71 * Send a command/arg pair.
72 */
setCommand(int cmd,int arg)73 void Message::setCommand(int cmd, int arg)
74 {
75 reset();
76
77 mData = new unsigned char[sizeof(int) * 2];
78 mCleanup = kCleanupDelete;
79 mLength = sizeof(int) * 2;
80 mType = kTypeCommand;
81
82 int* pInt = (int*) mData;
83 pInt[0] = cmd;
84 pInt[1] = arg;
85 }
86
87 /*
88 * Send a command with 3 args instead of just one.
89 */
setCommandExt(int cmd,int arg0,int arg1,int arg2)90 void Message::setCommandExt(int cmd, int arg0, int arg1, int arg2)
91 {
92 reset();
93
94 mData = new unsigned char[sizeof(int) * 4];
95 mCleanup = kCleanupDelete;
96 mLength = sizeof(int) * 4;
97 mType = kTypeCommandExt;
98
99 int* pInt = (int*) mData;
100 pInt[0] = cmd;
101 pInt[1] = arg0;
102 pInt[2] = arg1;
103 pInt[3] = arg2;
104 }
105
106 /*
107 * Try to return the contents of the message as if it were a "command".
108 */
getCommand(int * pCmd,int * pArg)109 bool Message::getCommand(int* pCmd, int* pArg)
110 {
111 if (mLength != sizeof(int) * 2) {
112 LOG(LOG_WARN, "", "type is %d, len is %d\n", mType, mLength);
113 return false;
114 }
115 assert(mData != NULL);
116
117 const int* pInt = (const int*) mData;
118 *pCmd = pInt[0];
119 *pArg = pInt[1];
120
121 return true;
122 }
123
124 /*
125 * Serialize a log message.
126 *
127 * DO NOT call LOG() from here.
128 */
setLogBundle(const android_LogBundle * pBundle)129 void Message::setLogBundle(const android_LogBundle* pBundle)
130 {
131 reset();
132
133 /* get string lengths; we add one here to include the '\0' */
134 int tagLen, msgLen;
135 tagLen = strlen(pBundle->tag) + 1;
136 size_t i;
137 msgLen = 0;
138 for (i=0; i<pBundle->msgCount; i++) msgLen += pBundle->msgVec[i].iov_len;
139 msgLen += 1;
140
141 /* set up the structure */
142 mCleanup = kCleanupDelete;
143 mLength = sizeof(pBundle->when) +
144 sizeof(pBundle->priority) +
145 sizeof(pBundle->pid) +
146 tagLen +
147 msgLen;
148 mData = new unsigned char[mLength];
149 mType = kTypeLogBundle;
150
151 unsigned char* pCur = mData;
152
153 /* copy the stuff over */
154 *((time_t*)pCur) = pBundle->when;
155 pCur += sizeof(pBundle->when);
156 *((android_LogPriority*)pCur) = pBundle->priority;
157 pCur += sizeof(pBundle->priority);
158 *((pid_t*)pCur) = pBundle->pid;
159 pCur += sizeof(pBundle->pid);
160 memcpy(pCur, pBundle->tag, tagLen);
161 pCur += tagLen;
162 for (i=0; i<pBundle->msgCount; i++) {
163 memcpy(pCur, pBundle->msgVec[i].iov_base, pBundle->msgVec[i].iov_len);
164 pCur += pBundle->msgVec[i].iov_len;
165 }
166 *pCur++ = 0;
167
168 assert(pCur - mData == mLength);
169 }
170
171 /*
172 * Extract the components of a log bundle.
173 *
174 * We're just returning points inside the message buffer, so the caller
175 * will need to copy them out before the next reset().
176 */
getLogBundle(android_LogBundle * pBundle)177 bool Message::getLogBundle(android_LogBundle* pBundle)
178 {
179 if (mLength < (int)(sizeof(time_t) + sizeof(int)*2 + 4)) {
180 LOG(LOG_WARN, "", "type is %d, len is %d, too small\n",
181 mType, mLength);
182 return false;
183 }
184 assert(mData != NULL);
185
186 unsigned char* pCur = mData;
187
188 pBundle->when = *((time_t*) pCur);
189 pCur += sizeof(pBundle->when);
190 pBundle->priority = *((android_LogPriority*) pCur);
191 pCur += sizeof(pBundle->priority);
192 pBundle->pid = *((pid_t*) pCur);
193 pCur += sizeof(pBundle->pid);
194 pBundle->tag = (const char*) pCur;
195 pCur += strlen((const char*) pCur) +1;
196 mVec.iov_base = (char*) pCur;
197 mVec.iov_len = strlen((const char*) pCur);
198 pBundle->msgVec = &mVec;
199 pBundle->msgCount = 1;
200 pCur += mVec.iov_len +1;
201
202 if (pCur - mData != mLength) {
203 LOG(LOG_WARN, "", "log bundle rcvd %d, used %d\n", mLength,
204 (int) (pCur - mData));
205 return false;
206 }
207
208 return true;
209 }
210
211 /*
212 * Read the next event from the pipe.
213 *
214 * This is not expected to work well when multiple threads are reading.
215 */
read(Pipe * pPipe,bool wait)216 bool Message::read(Pipe* pPipe, bool wait)
217 {
218 if (pPipe == NULL)
219 return false;
220 assert(pPipe->isCreated());
221
222 if (!wait) {
223 if (!pPipe->readReady())
224 return false;
225 }
226
227 reset();
228
229 unsigned char header[4];
230 if (pPipe->read(header, 4) != 4)
231 return false;
232
233 mType = (MessageType) header[2];
234 mLength = header[0] | header[1] << 8;
235 mLength -= 2; // we already read two of them in the header
236
237 if (mLength > 0) {
238 int actual;
239
240 mData = new unsigned char[mLength];
241 if (mData == NULL) {
242 LOG(LOG_ERROR, "", "alloc failed\n");
243 return false;
244 }
245 mCleanup = kCleanupDelete;
246
247 actual = pPipe->read(mData, mLength);
248 if (actual != mLength) {
249 LOG(LOG_WARN, "", "failed reading message body (%d of %d bytes)\n",
250 actual, mLength);
251 return false;
252 }
253 }
254
255 return true;
256 }
257
258 /*
259 * Write this event to a pipe.
260 *
261 * It would be easiest to write the header and message body with two
262 * separate calls, but that will occasionally fail on multithreaded
263 * systems when the writes are interleaved. We have to allocate a
264 * temporary buffer, copy the data, and write it all at once. This
265 * would be easier with writev(), but we can't rely on having that.
266 *
267 * DO NOT call LOG() from here, as we could be in the process of sending
268 * a log message.
269 */
write(Pipe * pPipe) const270 bool Message::write(Pipe* pPipe) const
271 {
272 char tmpBuf[128];
273 char* writeBuf = tmpBuf;
274 bool result = false;
275 int kHeaderLen = 4;
276
277 if (pPipe == NULL)
278 return false;
279 assert(pPipe->isCreated());
280
281 if (mData == NULL || mLength < 0)
282 return false;
283
284 /* if it doesn't fit in stack buffer, allocate space */
285 if (mLength + kHeaderLen > (int) sizeof(tmpBuf)) {
286 writeBuf = new char[mLength + kHeaderLen];
287 if (writeBuf == NULL)
288 goto bail;
289 }
290
291 /*
292 * The current value of "mLength" does not include the 4-byte header.
293 * Two of the 4 header bytes are included in the length we output
294 * (the type byte and the pad byte), so we adjust mLength.
295 */
296 writeBuf[0] = (unsigned char) (mLength + kHeaderLen -2);
297 writeBuf[1] = (unsigned char) ((mLength + kHeaderLen -2) >> 8);
298 writeBuf[2] = (unsigned char) mType;
299 writeBuf[3] = 0;
300 if (mLength > 0)
301 memcpy(writeBuf + kHeaderLen, mData, mLength);
302
303 int actual;
304
305 actual = pPipe->write(writeBuf, mLength + kHeaderLen);
306 if (actual != mLength + kHeaderLen) {
307 fprintf(stderr,
308 "Message::write failed writing message body (%d of %d bytes)\n",
309 actual, mLength + kHeaderLen);
310 goto bail;
311 }
312
313 result = true;
314
315 bail:
316 if (writeBuf != tmpBuf)
317 delete[] writeBuf;
318 return result;
319 }
320
321
322 /*
323 * ===========================================================================
324 * MessageStream
325 * ===========================================================================
326 */
327
328 /*
329 * Get ready to go.
330 */
init(Pipe * readPipe,Pipe * writePipe,bool initiateHello)331 bool MessageStream::init(Pipe* readPipe, Pipe* writePipe, bool initiateHello)
332 {
333 assert(mReadPipe == NULL && mWritePipe == NULL); // only once
334
335 /*
336 * Swap "hello" messages.
337 *
338 * In a more robust implementation, this would include version numbers
339 * and capability flags.
340 */
341 if (initiateHello) {
342 int32_t data = kHelloMsg;
343 Message msg;
344
345 /* send hello */
346 msg.setRaw((unsigned char*) &data, sizeof(data),
347 Message::kCleanupNoDelete);
348 if (!msg.write(writePipe)) {
349 LOG(LOG_WARN, "", "hello write failed in stream init\n");
350 return false;
351 }
352
353 LOG(LOG_DEBUG, "", "waiting for peer to ack my hello\n");
354
355 /* wait for the ack */
356 if (!msg.read(readPipe, true)) {
357 LOG(LOG_WARN, "", "hello ack read failed in stream init\n");
358 return false;
359 }
360
361 const int32_t* pAck;
362 pAck = (const int32_t*) msg.getData();
363 if (pAck == NULL || *pAck != kHelloAckMsg) {
364 LOG(LOG_WARN, "", "hello ack was bad (%08x vs %08x)\n",
365 *pAck, kHelloAckMsg);
366 return false;
367 }
368 } else {
369 int32_t data = kHelloAckMsg;
370 Message msg;
371
372 LOG(LOG_DEBUG, "", "waiting for hello from peer\n");
373
374 /* wait for the hello */
375 if (!msg.read(readPipe, true)) {
376 LOG(LOG_WARN, "", "hello read failed in stream init\n");
377 return false;
378 }
379
380 const int32_t* pAck;
381 pAck = (const int32_t*) msg.getData();
382 if (pAck == NULL || *pAck != kHelloMsg) {
383 LOG(LOG_WARN, "", "hello was bad\n");
384 return false;
385 }
386
387 /* send hello ack */
388 msg.setRaw((unsigned char*) &data, sizeof(data),
389 Message::kCleanupNoDelete);
390 if (!msg.write(writePipe)) {
391 LOG(LOG_WARN, "", "hello ack write failed in stream init\n");
392 return false;
393 }
394 }
395
396 /* success, set up our local stuff */
397 mReadPipe = readPipe;
398 mWritePipe = writePipe;
399
400 //LOG(LOG_DEBUG, "", "init success\n");
401
402 return true;
403 }
404
405