• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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