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