1 /*
2  * Copyright (c) 2011-2014, 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 <assert.h>
32 #include "Socket.h"
33 #include "RemoteProcessorProtocol.h"
34 #include <string.h>
35 #include <assert.h>
36 #include <errno.h>
37 
38 using std::string;
39 
CMessage(uint8_t ucMsgId)40 CMessage::CMessage(uint8_t ucMsgId) : _ucMsgId(ucMsgId), _pucData(NULL), _uiDataSize(0), _uiIndex(0)
41 {
42 }
43 
CMessage()44 CMessage::CMessage() : _ucMsgId((uint8_t)-1), _pucData(NULL), _uiDataSize(0), _uiIndex(0)
45 {
46 }
47 
~CMessage()48 CMessage::~CMessage()
49 {
50     delete [] _pucData;
51 }
52 
53 // Msg Id
getMsgId() const54 uint8_t CMessage::getMsgId() const
55 {
56     return _ucMsgId;
57 }
58 
59 // Data
writeData(const void * pvData,size_t uiSize)60 void CMessage::writeData(const void* pvData, size_t uiSize)
61 {
62     assert(_uiIndex + uiSize <= _uiDataSize);
63 
64     // Copy
65     memcpy(&_pucData[_uiIndex], pvData, uiSize);
66 
67     // Index
68     _uiIndex += uiSize;
69 }
70 
readData(void * pvData,size_t uiSize)71 void CMessage::readData(void* pvData, size_t uiSize)
72 {
73     assert(_uiIndex + uiSize <= _uiDataSize);
74 
75     // Copy
76     memcpy(pvData, &_pucData[_uiIndex], uiSize);
77 
78     // Index
79     _uiIndex += uiSize;
80 }
81 
writeString(const string & strData)82 void CMessage::writeString(const string& strData)
83 {
84     // Size
85     uint32_t uiSize = strData.length();
86 
87     writeData(&uiSize, sizeof(uiSize));
88 
89     // Content
90     writeData(strData.c_str(), uiSize);
91 }
92 
readString(string & strData)93 void CMessage::readString(string& strData)
94 {
95     // Size
96     uint32_t uiSize;
97 
98     readData(&uiSize, sizeof(uiSize));
99 
100     // Data
101     char pcData[uiSize + 1];
102 
103     // Content
104     readData(pcData, uiSize);
105 
106     // NULL-terminate string
107     pcData[uiSize] = '\0';
108 
109     // Output
110     strData = pcData;
111 }
112 
getStringSize(const string & strData) const113 size_t CMessage::getStringSize(const string& strData) const
114 {
115     // Return string length plus room to store its length
116     return strData.length() + sizeof(uint32_t);
117 }
118 
119 // Remaining data size
getRemainingDataSize() const120 size_t CMessage::getRemainingDataSize() const
121 {
122     return _uiDataSize - _uiIndex;
123 }
124 
125 // Send/Receive
serialize(CSocket * pSocket,bool bOut,string & strError)126 CMessage::Result CMessage::serialize(CSocket* pSocket, bool bOut, string& strError)
127 {
128     if (bOut) {
129 
130         // Make room for data to send
131         allocateData(getDataSize());
132 
133         // Get data from derived
134         fillDataToSend();
135 
136         // Finished providing data?
137         assert(_uiIndex == _uiDataSize);
138 
139         // First send sync word
140         uint16_t uiSyncWord = SYNC_WORD;
141 
142         if (!pSocket->write(&uiSyncWord, sizeof(uiSyncWord))) {
143 
144             if (pSocket->hasPeerDisconnected()) {
145                 return peerDisconnected;
146             }
147             return error;
148         }
149 
150         // Size
151         uint32_t uiSize = (uint32_t)(sizeof(_ucMsgId) + _uiDataSize);
152 
153         if (!pSocket->write(&uiSize, sizeof(uiSize))) {
154 
155             strError += string("Size write failed: ") + strerror(errno);
156             return error;
157         }
158 
159         // Msg Id
160         if (!pSocket->write(&_ucMsgId, sizeof(_ucMsgId))) {
161 
162             strError += string("Msg write failed: ") + strerror(errno);
163             return error;
164         }
165 
166         // Data
167         if (!pSocket->write(_pucData, _uiDataSize)) {
168 
169             strError = string("Data write failed: ") + strerror(errno);
170             return error;
171         }
172 
173         // Checksum
174         uint8_t ucChecksum = computeChecksum();
175 
176         if (!pSocket->write(&ucChecksum, sizeof(ucChecksum))) {
177 
178             strError = string("Checksum write failed: ") + strerror(errno);
179             return error;
180         }
181 
182     } else {
183         // First read sync word
184         uint16_t uiSyncWord;
185 
186         if (!pSocket->read(&uiSyncWord, sizeof(uiSyncWord))) {
187 
188             strError = string("Sync read failed: ") + strerror(errno);
189             if (pSocket->hasPeerDisconnected()) {
190                 return peerDisconnected;
191             }
192             return error;
193         }
194 
195         // Check Sync word
196         if (uiSyncWord != SYNC_WORD) {
197 
198             strError = "Sync word incorrect";
199             return error;
200         }
201 
202         // Size
203         uint32_t uiSize;
204 
205         if (!pSocket->read(&uiSize, sizeof(uiSize))) {
206 
207             strError = string("Size read failed: ") + strerror(errno);
208             return error;
209         }
210 
211         // Msg Id
212         if (!pSocket->read(&_ucMsgId, sizeof(_ucMsgId))) {
213 
214             strError = string("Msg id read failed: ") + strerror(errno);
215             return error;
216         }
217 
218         // Data
219 
220         // Allocate
221         allocateData(uiSize - sizeof(_ucMsgId));
222 
223         // Data receive
224         if (!pSocket->read(_pucData, _uiDataSize)) {
225 
226             strError = string("Data read failed: ") + strerror(errno);
227             return error;
228         }
229 
230         // Checksum
231         uint8_t ucChecksum;
232 
233         if (!pSocket->read(&ucChecksum, sizeof(ucChecksum))) {
234 
235             strError = string("Checksum read failed: ") + strerror(errno);
236             return error;
237         }
238         // Compare
239         if (ucChecksum != computeChecksum()) {
240 
241             strError = "Received checksum != computed checksum";
242             return error;
243         }
244 
245         // Collect data in derived
246         collectReceivedData();
247     }
248 
249     return success;
250 }
251 
252 // Checksum
computeChecksum() const253 uint8_t CMessage::computeChecksum() const
254 {
255     uint8_t uiChecksum = _ucMsgId;
256 
257     uint32_t uiIndex;
258 
259     for (uiIndex = 0; uiIndex < _uiDataSize; uiIndex++) {
260 
261         uiChecksum += _pucData[uiIndex];
262     }
263 
264     return uiChecksum;
265 }
266 
267 // Allocation of room to store the message
allocateData(size_t uiSize)268 void CMessage::allocateData(size_t uiSize)
269 {
270     // Remove previous one
271     if (_pucData) {
272 
273         delete [] _pucData;
274     }
275     // Do allocate
276     _pucData = new uint8_t[uiSize];
277 
278     // Record size
279     _uiDataSize = uiSize;
280 
281     // Reset Index
282     _uiIndex = 0;
283 }
284