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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 270 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 */ 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