Home | History | Annotate | Download | only in remote-processor
      1 /*
      2  * Copyright (c) 2011-2015, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include "Message.h"
     31 #include "Socket.h"
     32 #include "Iterator.hpp"
     33 #include <asio.hpp>
     34 #include <vector>
     35 #include <numeric>
     36 #include <cassert>
     37 
     38 using std::string;
     39 
     40 CMessage::CMessage(MsgType ucMsgId) : _ucMsgId(ucMsgId), _uiIndex(0)
     41 {
     42 }
     43 
     44 CMessage::CMessage() : _ucMsgId(MsgType::EInvalid), _uiIndex(0)
     45 {
     46 }
     47 
     48 // Msg Id
     49 CMessage::MsgType CMessage::getMsgId() const
     50 {
     51     return _ucMsgId;
     52 }
     53 
     54 bool CMessage::isValidAccess(size_t offset, size_t size) const
     55 {
     56     return offset + size <= getMessageDataSize();
     57 }
     58 
     59 // Data
     60 void CMessage::writeData(const void *pvData, size_t size)
     61 {
     62     assert(isValidAccess(_uiIndex, size));
     63 
     64     auto first = MAKE_ARRAY_ITERATOR(static_cast<const uint8_t *>(pvData), size);
     65     auto last = first + size;
     66     auto destFirst = begin(mData) + _uiIndex;
     67 
     68     std::copy(first, last, destFirst);
     69 
     70     _uiIndex += size;
     71 }
     72 
     73 void CMessage::readData(void *pvData, size_t size)
     74 {
     75     assert(isValidAccess(_uiIndex, size));
     76 
     77     auto first = begin(mData) + _uiIndex;
     78     auto last = first + size;
     79     auto destFirst = MAKE_ARRAY_ITERATOR(static_cast<uint8_t *>(pvData), size);
     80 
     81     std::copy(first, last, destFirst);
     82 
     83     _uiIndex += size;
     84 }
     85 
     86 void CMessage::writeString(const string &strData)
     87 {
     88     // Size
     89     uint32_t size = static_cast<uint32_t>(strData.length());
     90 
     91     writeData(&size, sizeof(size));
     92 
     93     // Content
     94     writeData(strData.c_str(), size);
     95 }
     96 
     97 void CMessage::readString(string &strData)
     98 {
     99     // Size
    100     uint32_t uiSize;
    101 
    102     readData(&uiSize, sizeof(uiSize));
    103 
    104     // Data
    105     std::vector<char> string(uiSize + 1);
    106 
    107     // Content
    108     readData(string.data(), uiSize);
    109 
    110     // NULL-terminate string
    111     string.back() = '\0';
    112 
    113     // Output
    114     strData = string.data();
    115 }
    116 
    117 size_t CMessage::getStringSize(const string &strData) const
    118 {
    119     // Return string length plus room to store its length
    120     return strData.length() + sizeof(uint32_t);
    121 }
    122 
    123 // Remaining data size
    124 size_t CMessage::getRemainingDataSize() const
    125 {
    126     return getMessageDataSize() - _uiIndex;
    127 }
    128 
    129 // Send/Receive
    130 CMessage::Result CMessage::serialize(Socket &&socket, bool bOut, string &strError)
    131 {
    132     asio::ip::tcp::socket &asioSocket = socket.get();
    133 
    134     if (bOut) {
    135         asio::error_code ec;
    136 
    137         // Make room for data to send
    138         allocateData(getDataSize());
    139 
    140         // Get data from derived
    141         fillDataToSend();
    142 
    143         // Finished providing data?
    144         assert(_uiIndex == getMessageDataSize());
    145 
    146         // First send sync word
    147         uint16_t uiSyncWord = SYNC_WORD;
    148 
    149         if (!asio::write(asioSocket, asio::buffer(&uiSyncWord, sizeof(uiSyncWord)), ec)) {
    150 
    151             if (ec == asio::error::eof) {
    152                 return peerDisconnected;
    153             }
    154             return error;
    155         }
    156 
    157         // Size
    158         uint32_t uiSize = (uint32_t)(sizeof(_ucMsgId) + getMessageDataSize());
    159 
    160         if (!asio::write(asioSocket, asio::buffer(&uiSize, sizeof(uiSize)), ec)) {
    161 
    162             strError += string("Size write failed: ") + ec.message();
    163             return error;
    164         }
    165 
    166         // Msg Id
    167         if (!asio::write(asioSocket, asio::buffer(&_ucMsgId, sizeof(_ucMsgId)), ec)) {
    168 
    169             strError += string("Msg write failed: ") + ec.message();
    170             return error;
    171         }
    172 
    173         // Data
    174         if (!asio::write(asioSocket, asio::buffer(mData), ec)) {
    175 
    176             strError = string("Data write failed: ") + ec.message();
    177             return error;
    178         }
    179 
    180         // Checksum
    181         uint8_t ucChecksum = computeChecksum();
    182 
    183         if (!asio::write(asioSocket, asio::buffer(&ucChecksum, sizeof(ucChecksum)), ec)) {
    184 
    185             strError = string("Checksum write failed: ") + ec.message();
    186             return error;
    187         }
    188 
    189     } else {
    190         // First read sync word
    191         uint16_t uiSyncWord = 0;
    192         asio::error_code ec;
    193 
    194         if (!asio::read(asioSocket, asio::buffer(&uiSyncWord, sizeof(uiSyncWord)), ec)) {
    195             strError = string("Sync read failed: ") + ec.message();
    196             if (ec == asio::error::eof) {
    197                 return peerDisconnected;
    198             }
    199             return error;
    200         }
    201 
    202         // Check Sync word
    203         if (uiSyncWord != SYNC_WORD) {
    204 
    205             strError = "Sync word incorrect";
    206             return error;
    207         }
    208 
    209         // Size
    210         uint32_t uiSize = 0;
    211 
    212         if (!asio::read(asioSocket, asio::buffer(&uiSize, sizeof(uiSize)), ec)) {
    213             strError = string("Size read failed: ") + ec.message();
    214             return error;
    215         }
    216 
    217         // Msg Id
    218         if (!asio::read(asioSocket, asio::buffer(&_ucMsgId, sizeof(_ucMsgId)), ec)) {
    219             strError = string("Msg id read failed: ") + ec.message();
    220             return error;
    221         }
    222 
    223         // Data
    224 
    225         // Allocate
    226         allocateData(uiSize - sizeof(_ucMsgId));
    227 
    228         // Data receive
    229         if (!asio::read(asioSocket, asio::buffer(mData), ec)) {
    230             strError = string("Data read failed: ") + ec.message();
    231             return error;
    232         }
    233 
    234         // Checksum
    235         uint8_t ucChecksum = 0;
    236 
    237         if (!asio::read(asioSocket, asio::buffer(&ucChecksum, sizeof(ucChecksum)), ec)) {
    238             strError = string("Checksum read failed: ") + ec.message();
    239             return error;
    240         }
    241         // Compare
    242         if (ucChecksum != computeChecksum()) {
    243 
    244             strError = "Received checksum != computed checksum";
    245             return error;
    246         }
    247 
    248         // Collect data in derived
    249         collectReceivedData();
    250     }
    251 
    252     return success;
    253 }
    254 
    255 // Checksum
    256 uint8_t CMessage::computeChecksum() const
    257 {
    258     return accumulate(begin(mData), end(mData), static_cast<uint8_t>(_ucMsgId));
    259 }
    260 
    261 // Allocation of room to store the message
    262 void CMessage::allocateData(size_t size)
    263 {
    264     // Remove previous one
    265     mData.clear();
    266 
    267     // Do allocate
    268     mData.resize(size);
    269 
    270     // Reset Index
    271     _uiIndex = 0;
    272 }
    273