Home | History | Annotate | Download | only in app
      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