Bug Summary

File:rootdir/src/libs/ec/cpp/ECSocket.cpp
Warning:line 172, column 2
Memory copy function overflows the destination buffer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ECSocket.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src/libs/ec/cpp -fcoverage-compilation-dir=/rootdir/src/libs/ec/cpp -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I ../../../.. -D USE_WX_EXTENSIONS -I ../../../../src -I ../../../../src/libs -I ../../../../src/include -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D wxUSE_GUI=0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-17-082348-14898-1 -x c++ ECSocket.cpp
1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24//
25
26#include "ECSocket.h"
27
28#include <sstream>
29#include <iostream>
30#include <algorithm>
31
32using namespace std;
33
34#include "ECPacket.h" // Needed for CECPacket
35#include "../../../Logger.h"
36#include <common/Format.h> // Needed for CFormat
37#include "ECLog.h"
38
39#define EC_COMPRESSION_LEVEL(-1) Z_DEFAULT_COMPRESSION(-1)
40#define EC_MAX_UNCOMPRESSED1024 1024
41
42#ifndef __GNUC__4
43#define __attribute__(x)
44#endif
45
46// If your compiler gives errors on these lines, just remove them.
47int utf8_mbtowc(wchar_t *p, const unsigned char *s, int n) __attribute__((__visibility__("internal")));
48int utf8_wctomb(unsigned char *s, wchar_t wc, int maxlen) __attribute__((__visibility__("internal")));
49int utf8_mb_remain(char c) __attribute__((__pure__));
50
51/*----------=> Import from the Linux kernel <=----------*/
52/*
53 * linux/fs/nls_base.c
54 */
55
56/*
57 * Sample implementation from Unicode home page.
58 * http://www.stonehand.com/unicode/standard/fss-utf.html
59 */
60struct utf8_table {
61 int cmask;
62 int cval;
63 int shift;
64 uint32_t lmask;
65 uint32_t lval;
66};
67
68static const struct utf8_table utf8_table[] =
69{
70 {0x80, 0x00, 0*6, 0x7F, 0, /* 1 byte sequence */},
71 {0xE0, 0xC0, 1*6, 0x7FF, 0x80, /* 2 byte sequence */},
72 {0xF0, 0xE0, 2*6, 0xFFFF, 0x800, /* 3 byte sequence */},
73 {0xF8, 0xF0, 3*6, 0x1FFFFF, 0x10000, /* 4 byte sequence */},
74 {0xFC, 0xF8, 4*6, 0x3FFFFFF, 0x200000, /* 5 byte sequence */},
75 {0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */},
76 {0, 0, 0, 0, 0, /* end of table */}
77};
78
79static int utf8_mbtowc(uint32_t *p, const unsigned char *s, int n)
80{
81 uint32_t l;
82 int c0, nc;
83 const struct utf8_table *t;
84
85 nc = 0;
86 c0 = *s;
87 l = c0;
88 for (t = utf8_table; t->cmask; t++) {
89 int c;
90 nc++;
91 if ((c0 & t->cmask) == t->cval) {
92 l &= t->lmask;
93 if (l < t->lval)
94 return -1;
95 *p = l;
96 return nc;
97 }
98 if (n <= nc)
99 return -1;
100 s++;
101 c = (*s ^ 0x80) & 0xFF;
102 if (c & 0xC0)
103 return -1;
104 l = (l << 6) | c;
105 }
106 return -1;
107}
108
109static int utf8_wctomb(unsigned char *s, uint32_t wc, int maxlen)
110{
111 uint32_t l;
112 int c, nc;
113 const struct utf8_table *t;
114
115 l = wc;
116 nc = 0;
117 for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
118 nc++;
119 if (l <= t->lmask) {
120 c = t->shift;
121 *s = t->cval | (l >> c);
122 while (c > 0) {
123 c -= 6;
124 s++;
125 *s = 0x80 | ((l >> c) & 0x3F);
126 }
127 return nc;
128 }
129 }
130 return -1;
131}
132/*----------=> End of Import <=----------*/
133
134int utf8_mb_remain(char c)
135{
136 int i;
137 for (i = 0; i < 5; ++i) {
138 if ((c & utf8_table[i].cmask) == utf8_table[i].cval) break;
139 }
140 return i;
141}
142
143
144void CQueuedData::Write(const void *data, size_t len)
145{
146 const size_t canWrite = std::min(GetRemLength(), len);
147 wxASSERT(len == canWrite)do { if ( len == canWrite ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("ECSocket.cpp", 147, __FUNCTION__, "len == canWrite"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
148
149 memcpy(m_wr_ptr, data, canWrite);
150 m_wr_ptr += canWrite;
151}
152
153
154void CQueuedData::WriteAt(const void *data, size_t len, size_t offset)
155{
156 wxASSERT(len + offset <= m_data.size())do { if ( len + offset <= m_data.size() ) { } else if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 156, __FUNCTION__, "len + offset <= m_data.size()"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
157 if (offset > m_data.size()) {
158 return;
159 } else if (offset + len > m_data.size()) {
160 len = m_data.size() - offset;
161 }
162
163 memcpy(&m_data[0] + offset, data, len);
164}
165
166
167void CQueuedData::Read(void *data, size_t len)
168{
169 const size_t canRead = std::min(GetUnreadDataLength(), len);
170 wxASSERT(len == canRead)do { if ( len == canRead ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("ECSocket.cpp", 170, __FUNCTION__, "len == canRead"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
15
Taking true branch
16
Loop condition is false. Exiting loop
171
172 memcpy(data, m_rd_ptr, canRead);
17
Memory copy function overflows the destination buffer
173 m_rd_ptr += canRead;
174}
175
176
177uint32 CQueuedData::WriteToSocket(CECSocket *sock)
178{
179 wxCHECK_MSG(m_rd_ptr < m_wr_ptr, 0,if ( m_rd_ptr < m_wr_ptr ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 180, __FUNCTION__, "\"m_rd_ptr < m_wr_ptr\""
, L"Reading past written data in WriteToSocket"), wxTrapInAssert
) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while
( (void)0, 0 ); return 0; } struct wxDummyCheckStruct180
180 wxT("Reading past written data in WriteToSocket"))if ( m_rd_ptr < m_wr_ptr ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 180, __FUNCTION__, "\"m_rd_ptr < m_wr_ptr\""
, L"Reading past written data in WriteToSocket"), wxTrapInAssert
) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while
( (void)0, 0 ); return 0; } struct wxDummyCheckStruct180
;
181
182 uint32 write = sock->SocketWrite(m_rd_ptr, GetUnreadDataLength());
183 m_rd_ptr += write;
184 return write;
185}
186
187
188uint32 CQueuedData::ReadFromSocket(CECSocket *sock, size_t len)
189{
190 const size_t canWrite = std::min(GetRemLength(), len);
191 wxASSERT(len == canWrite)do { if ( len == canWrite ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("ECSocket.cpp", 191, __FUNCTION__, "len == canWrite"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
192
193 uint32 read = sock->SocketRead(m_wr_ptr, canWrite);
194 m_wr_ptr += read;
195 return read;
196}
197
198
199size_t CQueuedData::ReadFromSocketAll(CECSocket *sock, size_t len)
200{
201 size_t read_rem = std::min(GetRemLength(), len);
202 wxASSERT(read_rem == len)do { if ( read_rem == len ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("ECSocket.cpp", 202, __FUNCTION__, "read_rem == len"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
203
204 // We get here when socket is truly blocking
205 do {
206 // Give socket a 10 sec chance to recv more data.
207 if ( !sock->WaitSocketRead(10, 0) ) {
208 AddDebugLogLineN(logEC, wxT("ReadFromSocketAll: socket is blocking"))do {} while (false);
209 break;
210 }
211
212 wxASSERT(m_wr_ptr + read_rem <= &m_data[0] + m_data.size())do { if ( m_wr_ptr + read_rem <= &m_data[0] + m_data.size
() ) { } else if ( wxTheAssertHandler && (wxOnAssert(
"ECSocket.cpp", 212, __FUNCTION__, "m_wr_ptr + read_rem <= &m_data[0] + m_data.size()"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
213 uint32 read = sock->SocketRead(m_wr_ptr, read_rem);
214 m_wr_ptr += read;
215 read_rem -= read;
216
217 if (sock->SocketRealError()) {
218 AddDebugLogLineN(logEC, wxT("ReadFromSocketAll: socket error"))do {} while (false);
219 break;
220 }
221 } while (read_rem);
222
223 return len - read_rem;
224}
225
226
227size_t CQueuedData::GetLength() const
228{
229 return m_data.size();
230}
231
232
233size_t CQueuedData::GetDataLength() const
234{
235 const size_t len = m_wr_ptr - &m_data[0];
236 wxCHECK_MSG(len <= m_data.size(), m_data.size(),if ( len <= m_data.size() ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 237, __FUNCTION__, "\"len <= m_data.size()\""
, L"Write-pointer past end of buffer"), wxTrapInAssert) ) { wxTrapInAssert
= false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return
m_data.size(); } struct wxDummyCheckStruct237
237 wxT("Write-pointer past end of buffer"))if ( len <= m_data.size() ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 237, __FUNCTION__, "\"len <= m_data.size()\""
, L"Write-pointer past end of buffer"), wxTrapInAssert) ) { wxTrapInAssert
= false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return
m_data.size(); } struct wxDummyCheckStruct237
;
238
239 return len;
240}
241
242
243size_t CQueuedData::GetRemLength() const
244{
245 return m_data.size() - GetDataLength();
246}
247
248
249size_t CQueuedData::GetUnreadDataLength() const
250{
251 wxCHECK_MSG(m_wr_ptr >= m_rd_ptr, 0,if ( m_wr_ptr >= m_rd_ptr ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 252, __FUNCTION__, "\"m_wr_ptr >= m_rd_ptr\""
, L"Read position past write position."), wxTrapInAssert) ) {
wxTrapInAssert = false; asm volatile ("int $3"); } } while (
(void)0, 0 ); return 0; } struct wxDummyCheckStruct252
252 wxT("Read position past write position."))if ( m_wr_ptr >= m_rd_ptr ) {} else { do { if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 252, __FUNCTION__, "\"m_wr_ptr >= m_rd_ptr\""
, L"Read position past write position."), wxTrapInAssert) ) {
wxTrapInAssert = false; asm volatile ("int $3"); } } while (
(void)0, 0 ); return 0; } struct wxDummyCheckStruct252
;
253
254 return m_wr_ptr - m_rd_ptr;
255}
256
257
258
259//
260// CECSocket API - User interface functions
261//
262
263CECSocket::CECSocket(bool use_events)
264 : m_use_events(use_events),
265 m_in_ptr(EC_SOCKET_BUFFER_SIZE),
266 m_out_ptr(EC_SOCKET_BUFFER_SIZE),
267 m_curr_rx_data(new CQueuedData(EC_SOCKET_BUFFER_SIZE)),
268 m_curr_tx_data(new CQueuedData(EC_SOCKET_BUFFER_SIZE)),
269 m_rx_flags(0),
270 m_tx_flags(0),
271 // setup initial state: 4 flags + 4 length
272 m_bytes_needed(EC_HEADER_SIZE),
273 m_in_header(true),
274 m_curr_packet_len(0),
275 m_my_flags(0x20),
276 m_haveNotificationSupport(false)
277{}
278
279CECSocket::~CECSocket()
280{
281 while (!m_output_queue.empty()) {
282 CQueuedData *data = m_output_queue.front();
283 m_output_queue.pop_front();
284 delete data;
285 }
286}
287
288bool CECSocket::ConnectSocket(uint32_t ip, uint16_t port)
289{
290 bool res = InternalConnect(ip, port, !m_use_events);
291 return !SocketError() && res;
292}
293
294void CECSocket::SendPacket(const CECPacket *packet)
295{
296 uint32 len = WritePacket(packet);
297 packet->DebugPrint(false, len);
298 OnOutput();
299}
300
301const CECPacket *CECSocket::SendRecvPacket(const CECPacket *packet)
302{
303 SendPacket(packet);
304
305 if (m_curr_rx_data->ReadFromSocketAll(this, EC_HEADER_SIZE) != EC_HEADER_SIZE
306 || SocketError() // This is a synchronous read, so WouldBlock is an error too.
307 || !ReadHeader()) {
308 OnError();
309 AddDebugLogLineN(logEC, wxT("SendRecvPacket: error"))do {} while (false);
310 return 0;
311 }
312 if (m_curr_rx_data->ReadFromSocketAll(this, m_curr_packet_len) != m_curr_packet_len
313 || SocketError()) {
314 OnError();
315 AddDebugLogLineN(logEC, wxT("SendRecvPacket: error"))do {} while (false);
316 return 0;
317 }
318 const CECPacket *reply = ReadPacket();
319 m_curr_rx_data->Rewind();
320 return reply;
321}
322
323std::string CECSocket::GetLastErrorMsg()
324{
325 int code = InternalGetLastError();
326 switch(code) {
327 case EC_ERROR_NOERROR:
328 return "No error happened";
329 case EC_ERROR_INVOP:
330 return "Invalid operation";
331 case EC_ERROR_IOERR:
332 return "Input/Output error";
333 case EC_ERROR_INVADDR:
334 return "Invalid address passed to wxSocket";
335 case EC_ERROR_INVSOCK:
336 return "Invalid socket (uninitialized)";
337 case EC_ERROR_NOHOST:
338 return "No corresponding host";
339 case EC_ERROR_INVPORT:
340 return "Invalid port";
341 case EC_ERROR_WOULDBLOCK:
342 return "The socket is non-blocking and the operation would block";
343 case EC_ERROR_TIMEDOUT:
344 return "The timeout for this operation expired";
345 case EC_ERROR_MEMERR:
346 return "Memory exhausted";
347 }
348 ostringstream error_string;
349 error_string << "Error code " << code << " unknown.";
350 return error_string.str();
351}
352
353bool CECSocket::SocketRealError()
354{
355 bool ret = false;
356 if (InternalError()) {
357 int lastError = InternalGetLastError();
358 ret = lastError != EC_ERROR_NOERROR && lastError != EC_ERROR_WOULDBLOCK;
359 }
360 return ret;
361}
362
363void CECSocket::OnError()
364{
365#ifdef __DEBUG__
366 cout << GetLastErrorMsg() << endl;
367#endif
368}
369
370void CECSocket::OnLost()
371{
372}
373
374//
375// Event handlers
376//
377void CECSocket::OnConnect()
378{
379}
380
381void CECSocket::OnInput()
382{
383 size_t bytes_rx = 0;
384 do {
385 bytes_rx = m_curr_rx_data->ReadFromSocket(this, m_bytes_needed);
386 if (SocketRealError()) {
387 AddDebugLogLineN(logEC, wxT("OnInput: socket error"))do {} while (false);
388 OnError();
389 // socket already disconnected in this point
390 return;
391 }
392 m_bytes_needed -= bytes_rx;
393
394 if (m_bytes_needed == 0) {
395 if (m_in_header) {
396 m_in_header = false;
397 if (!ReadHeader()) {
398 AddDebugLogLineN(logEC, wxT("OnInput: header error"))do {} while (false);
399 return;
400 }
401 } else {
402 CSmartPtr<const CECPacket> packet(ReadPacket());
403 m_curr_rx_data->Rewind();
404 if (packet.get()) {
405 CSmartPtr<const CECPacket> reply(OnPacketReceived(packet.get(), m_curr_packet_len));
406 if (reply.get()) {
407 SendPacket(reply.get());
408 }
409 } else {
410 AddDebugLogLineN(logEC, wxT("OnInput: no packet"))do {} while (false);
411 }
412 m_bytes_needed = EC_HEADER_SIZE;
413 m_in_header = true;
414 }
415 }
416 } while (bytes_rx);
417}
418
419void CECSocket::OnOutput()
420{
421 while (!m_output_queue.empty()) {
422 CQueuedData* data = m_output_queue.front();
423 data->WriteToSocket(this);
424 if (!data->GetUnreadDataLength()) {
425 m_output_queue.pop_front();
426 delete data;
427 }
428 if (SocketError()) {
429 if (!WouldBlock()) {
430 // real error, abort
431 AddDebugLogLineN(logEC, wxT("OnOutput: socket error"))do {} while (false);
432 OnError();
433 return;
434 }
435 // Now it's just a blocked socket.
436 if ( m_use_events ) {
437 // Event driven logic: return, OnOutput() will be called again later
438 return;
439 }
440 // Synchronous call: wait (for max 10 secs)
441 if ( !WaitSocketWrite(10, 0) ) {
442 // Still not through ?
443 if (WouldBlock()) {
444 // WouldBlock() is only EAGAIN or EWOULD_BLOCK,
445 // and those shouldn't create an infinite wait.
446 // So give it another chance.
447 continue;
448 } else {
449 AddDebugLogLineN(logEC, wxT("OnOutput: socket error in sync wait"))do {} while (false);
450 OnError();
451 break;
452 }
453 }
454 }
455 }
456 //
457 // All outstanding data sent to socket
458 // (used for push clients)
459 //
460 WriteDoneAndQueueEmpty();
461}
462
463bool CECSocket::DataPending()
464{
465 return !m_output_queue.empty();
466}
467
468//
469// Socket I/O
470//
471
472size_t CECSocket::ReadBufferFromSocket(void *buffer, size_t required_len)
473{
474 wxASSERT(required_len)do { if ( required_len ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("ECSocket.cpp", 474, __FUNCTION__, "required_len"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
10
Taking true branch
11
Loop condition is false. Exiting loop
475
476 if (m_curr_rx_data->GetUnreadDataLength() < required_len) {
12
Assuming the condition is false
13
Taking false branch
477 // need more data that we have. Looks like nothing will help here
478 AddDebugLogLineN(logEC, CFormat(wxT("ReadBufferFromSocket: not enough data (%d < %d)"))do {} while (false)
479 % m_curr_rx_data->GetUnreadDataLength() % required_len)do {} while (false);
480 return 0;
481 }
482 m_curr_rx_data->Read(buffer, required_len);
14
Calling 'CQueuedData::Read'
483 return required_len;
484}
485
486void CECSocket::WriteBufferToSocket(const void *buffer, size_t len)
487{
488 unsigned char *wr_ptr = (unsigned char *)buffer;
489 while ( len ) {
490 size_t curr_free = m_curr_tx_data->GetRemLength();
491 if ( len > curr_free ) {
492
493 m_curr_tx_data->Write(wr_ptr, curr_free);
494 len -= curr_free;
495 wr_ptr += curr_free;
496 m_output_queue.push_back(m_curr_tx_data.release());
497 m_curr_tx_data.reset(new CQueuedData(EC_SOCKET_BUFFER_SIZE));
498 } else {
499 m_curr_tx_data->Write(wr_ptr, len);
500 break;
501 }
502 }
503}
504
505
506//
507// ZLib "error handler"
508//
509
510static void ShowZError(int zerror, z_streamp strm)
511{
512 const char *p = NULL__null;
513
514 switch (zerror) {
515 case Z_STREAM_END1: p = "Z_STREAM_END"; break;
516 case Z_NEED_DICT2: p = "Z_NEED_DICT"; break;
517 case Z_ERRNO(-1): p = "Z_ERRNO"; break;
518 case Z_STREAM_ERROR(-2): p = "Z_STREAM_ERROR"; break;
519 case Z_DATA_ERROR(-3): p = "Z_DATA_ERROR"; break;
520 case Z_MEM_ERROR(-4): p = "Z_MEM_ERROR"; break;
521 case Z_BUF_ERROR(-5): p = "Z_BUF_ERROR"; break;
522 case Z_VERSION_ERROR(-6): p = "Z_VERSION_ERROR"; break;
523 }
524 printf("ZLib operation returned %s\n", p);
525 printf("ZLib error message: %s\n", strm->msg);
526 printf("zstream state:\n\tnext_in=%p\n\tavail_in=%u\n\ttotal_in=%lu\n\tnext_out=%p\n\tavail_out=%u\n\ttotal_out=%lu\n",
527 strm->next_in, strm->avail_in, strm->total_in, strm->next_out, strm->avail_out, strm->total_out);
528 AddDebugLogLineN(logEC, wxT("ZLib error"))do {} while (false);
529}
530
531
532bool CECSocket::ReadHeader()
533{
534 m_curr_rx_data->Read(&m_rx_flags, 4);
535 m_rx_flags = ENDIAN_NTOHL(m_rx_flags)( ((wxUint32) ( (((wxUint32) (m_rx_flags) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (m_rx_flags) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (m_rx_flags) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (m_rx_flags) & (wxUint32) 0xff000000U
) >> 24))) )
;
536 m_curr_rx_data->Read(&m_curr_packet_len, 4);
537 m_curr_packet_len = ENDIAN_NTOHL(m_curr_packet_len)( ((wxUint32) ( (((wxUint32) (m_curr_packet_len) & (wxUint32
) 0x000000ffU) << 24) | (((wxUint32) (m_curr_packet_len
) & (wxUint32) 0x0000ff00U) << 8) | (((wxUint32) (m_curr_packet_len
) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (m_curr_packet_len
) & (wxUint32) 0xff000000U) >> 24))) )
;
538 m_bytes_needed = m_curr_packet_len;
539 // packet bigger that 16Mb looks more like broken request
540 if (m_bytes_needed > 16*1024*1024) {
541 AddDebugLogLineN(logEC, CFormat(wxT("ReadHeader: packet too big: %d")) % m_bytes_needed)do {} while (false);
542 CloseSocket();
543 return false;
544 }
545 m_curr_rx_data->Rewind();
546 size_t currLength = m_curr_rx_data->GetLength();
547 // resize input buffer if
548 // a) too small or
549 if (currLength < m_bytes_needed
550 // b) way too large (free data again after receiving huge packets)
551 || m_bytes_needed + EC_SOCKET_BUFFER_SIZE * 10 < currLength) {
552 // Client socket: IsAuthorized() is always true
553 // Server socket: do not allow growing of internal buffers before successful login.
554 // Otherwise sending a simple header with bogus length of 16MB-1 will crash an embedded
555 // client with memory exhaustion.
556 if (!IsAuthorized()) {
557 AddDebugLogLineN(logEC, CFormat(wxT("ReadHeader: resize (%d -> %d) on non autorized socket")) % currLength % m_bytes_needed)do {} while (false);
558 CloseSocket();
559 return false;
560 }
561 // Don't make buffer smaller than EC_SOCKET_BUFFER_SIZE
562 size_t bufSize = m_bytes_needed;
563 if (bufSize < EC_SOCKET_BUFFER_SIZE) {
564 bufSize = EC_SOCKET_BUFFER_SIZE;
565 }
566 m_curr_rx_data.reset(new CQueuedData(bufSize));
567 }
568 if (ECLogIsEnabled()false) {
569 DoECLogLine(CFormat(wxT("< %d ...")) % m_bytes_needed)do {} while(0);
570 }
571 return true;
572}
573
574
575bool CECSocket::ReadNumber(void *buffer, size_t len)
576{
577 if (m_rx_flags & EC_FLAG_UTF8_NUMBERS) {
1
Assuming the condition is true
2
Taking true branch
578 unsigned char mb[6];
579 uint32_t wc;
580 if (!ReadBuffer(mb, 1)) return false;
3
Taking false branch
581 int remains = utf8_mb_remain(mb[0]);
582 if (remains) if (!ReadBuffer(&(mb[1]), remains)) return false;
4
Assuming 'remains' is not equal to 0
5
Taking true branch
6
Calling 'CECSocket::ReadBuffer'
583 if (utf8_mbtowc(&wc, mb, 6) == -1) return false; // Invalid UTF-8 code sequence
584 switch (len) {
585 case 1: PokeUInt8( buffer, wc ); break;
586 case 2: RawPokeUInt16( buffer, wc ); break;
587 case 4: RawPokeUInt32( buffer, wc ); break;
588 }
589 } else {
590 if ( !ReadBuffer(buffer, len) ) {
591 return false;
592 }
593 switch (len) {
594 case 2:
595 RawPokeUInt16( buffer, ENDIAN_NTOHS( RawPeekUInt16( buffer ) )( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( buffer )) & (
wxUint16) 0x00ffU) << 8) | (((wxUint16) (RawPeekUInt16(
buffer )) & (wxUint16) 0xff00U) >> 8))) )
);
596 break;
597 case 4:
598 RawPokeUInt32( buffer, ENDIAN_NTOHL( RawPeekUInt32( buffer ) )( ((wxUint32) ( (((wxUint32) (RawPeekUInt32( buffer )) & (
wxUint32) 0x000000ffU) << 24) | (((wxUint32) (RawPeekUInt32
( buffer )) & (wxUint32) 0x0000ff00U) << 8) | (((wxUint32
) (RawPeekUInt32( buffer )) & (wxUint32) 0x00ff0000U) >>
8) | (((wxUint32) (RawPeekUInt32( buffer )) & (wxUint32)
0xff000000U) >> 24))) )
);
599 break;
600 }
601 }
602 return true;
603}
604
605bool CECSocket::WriteNumber(const void *buffer, size_t len)
606{
607 if (m_tx_flags & EC_FLAG_UTF8_NUMBERS) {
608 unsigned char mb[6];
609 uint32_t wc = 0;
610 int mb_len;
611 switch (len) {
612 case 1: wc = PeekUInt8( buffer ); break;
613 case 2: wc = RawPeekUInt16( buffer ); break;
614 case 4: wc = RawPeekUInt32( buffer ); break;
615 default: return false;
616 }
617 if ((mb_len = utf8_wctomb(mb, wc, 6)) == -1) return false; // Something is terribly wrong...
618 return WriteBuffer(mb, mb_len);
619 } else {
620 char tmp[8];
621
622 switch (len) {
623 case 1: PokeUInt8( tmp, PeekUInt8( buffer ) ); break;
624 case 2: RawPokeUInt16( tmp, ENDIAN_NTOHS( RawPeekUInt16( buffer ) )( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( buffer )) & (
wxUint16) 0x00ffU) << 8) | (((wxUint16) (RawPeekUInt16(
buffer )) & (wxUint16) 0xff00U) >> 8))) )
); break;
625 case 4: RawPokeUInt32( tmp, ENDIAN_NTOHL( RawPeekUInt32( buffer ) )( ((wxUint32) ( (((wxUint32) (RawPeekUInt32( buffer )) & (
wxUint32) 0x000000ffU) << 24) | (((wxUint32) (RawPeekUInt32
( buffer )) & (wxUint32) 0x0000ff00U) << 8) | (((wxUint32
) (RawPeekUInt32( buffer )) & (wxUint32) 0x00ff0000U) >>
8) | (((wxUint32) (RawPeekUInt32( buffer )) & (wxUint32)
0xff000000U) >> 24))) )
); break;
626 }
627 return WriteBuffer(tmp, len);
628 }
629}
630
631bool CECSocket::ReadBuffer(void *buffer, size_t len)
632{
633 if (m_rx_flags & EC_FLAG_ZLIB) {
7
Assuming the condition is false
8
Taking false branch
634 if ( !m_z.avail_in ) {
635 // no reason for this situation: all packet should be
636 // buffered by now
637 AddDebugLogLineN(logEC, wxT("ReadBuffer: ZLib error"))do {} while (false);
638 return false;
639 }
640 m_z.avail_out = (uInt)len;
641 m_z.next_out = (Bytef*)buffer;
642 int zerror = inflate(&m_z, Z_SYNC_FLUSH2);
643 if ((zerror != Z_OK0) && (zerror != Z_STREAM_END1)) {
644 ShowZError(zerror, &m_z);
645 AddDebugLogLineN(logEC, wxT("ReadBuffer: ZLib error"))do {} while (false);
646 return false;
647 }
648 return true;
649 } else {
650 // using uncompressed buffered i/o
651 size_t read = ReadBufferFromSocket(buffer, len);
9
Calling 'CECSocket::ReadBufferFromSocket'
652 if (read == len) {
653 return true;
654 } else {
655 AddDebugLogLineN(logEC, CFormat(wxT("ReadBuffer: %d < %d")) % read % len)do {} while (false);
656 return false;
657 }
658 }
659}
660
661bool CECSocket::WriteBuffer(const void *buffer, size_t len)
662{
663 if (m_tx_flags & EC_FLAG_ZLIB) {
664
665 unsigned char *rd_ptr = (unsigned char *)buffer;
666 do {
667 unsigned int remain_in = EC_SOCKET_BUFFER_SIZE - m_z.avail_in;
668 if ( remain_in >= len ) {
669 memcpy(m_z.next_in+m_z.avail_in, rd_ptr, len);
670 m_z.avail_in += (uInt)len;
671 len = 0;
672 } else {
673 memcpy(m_z.next_in+m_z.avail_in, rd_ptr, remain_in);
674 m_z.avail_in += remain_in;
675 len -= remain_in;
676 rd_ptr += remain_in;
677 // buffer is full, calling zlib
678 do {
679 m_z.next_out = &m_out_ptr[0];
680 m_z.avail_out = EC_SOCKET_BUFFER_SIZE;
681 int zerror = deflate(&m_z, Z_NO_FLUSH0);
682 if ( zerror != Z_OK0 ) {
683 AddDebugLogLineN(logEC, wxT("WriteBuffer: ZLib error"))do {} while (false);
684 ShowZError(zerror, &m_z);
685 return false;
686 }
687 WriteBufferToSocket(&m_out_ptr[0],
688 EC_SOCKET_BUFFER_SIZE - m_z.avail_out);
689 } while ( m_z.avail_out == 0 );
690 // all input should be used by now
691 wxASSERT(m_z.avail_in == 0)do { if ( m_z.avail_in == 0 ) { } else if ( wxTheAssertHandler
&& (wxOnAssert("ECSocket.cpp", 691, __FUNCTION__, "m_z.avail_in == 0"
, (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
692 m_z.next_in = &m_in_ptr[0];
693 }
694 } while ( len );
695 return true;
696 } else {
697 // using uncompressed buffered i/o
698 WriteBufferToSocket(buffer, len);
699 return true;
700 }
701}
702
703bool CECSocket::FlushBuffers()
704{
705 if (m_tx_flags & EC_FLAG_ZLIB) {
706 do {
707 m_z.next_out = &m_out_ptr[0];
708 m_z.avail_out = EC_SOCKET_BUFFER_SIZE;
709 int zerror = deflate(&m_z, Z_FINISH4);
710 if ( zerror == Z_STREAM_ERROR(-2) ) {
711 AddDebugLogLineN(logEC, wxT("FlushBuffers: ZLib error"))do {} while (false);
712 ShowZError(zerror, &m_z);
713 return false;
714 }
715 WriteBufferToSocket(&m_out_ptr[0],
716 EC_SOCKET_BUFFER_SIZE - m_z.avail_out);
717 } while ( m_z.avail_out == 0 );
718 }
719 if ( m_curr_tx_data->GetDataLength() ) {
720 m_output_queue.push_back(m_curr_tx_data.release());
721 m_curr_tx_data.reset(new CQueuedData(EC_SOCKET_BUFFER_SIZE));
722 }
723 return true;
724}
725
726//
727// Packet I/O
728//
729
730uint32 CECSocket::WritePacket(const CECPacket *packet)
731{
732 if (SocketRealError()) {
733 OnError();
734 return 0;
735 }
736 // Check if output queue is empty. If not, memorize the current end.
737 std::list<CQueuedData*>::iterator outputStart = m_output_queue.begin();
738 uint32 outputQueueSize = m_output_queue.size();
739 for (uint32 i = 1; i < outputQueueSize; i++) {
740 ++outputStart;
741 }
742
743 uint32_t flags = 0x20;
744
745 if (packet->GetPacketLength() > EC_MAX_UNCOMPRESSED1024
746 && ((m_my_flags & EC_FLAG_ZLIB) > 0)) {
747 flags |= EC_FLAG_ZLIB;
748 } else {
749 flags |= EC_FLAG_UTF8_NUMBERS;
750 }
751
752 flags &= m_my_flags;
753 m_tx_flags = flags;
754
755 if (flags & EC_FLAG_ZLIB) {
756 m_z.zalloc = Z_NULL0;
757 m_z.zfree = Z_NULL0;
758 m_z.opaque = Z_NULL0;
759 m_z.avail_in = 0;
760 m_z.next_in = &m_in_ptr[0];
761 int zerror = deflateInit(&m_z, EC_COMPRESSION_LEVEL)deflateInit_((&m_z), ((-1)), "1.3.1", (int)sizeof(z_stream
))
;
762 if (zerror != Z_OK0) {
763 // don't use zlib if init failed
764 flags &= ~EC_FLAG_ZLIB;
765 ShowZError(zerror, &m_z);
766 }
767 }
768
769 uint32_t tmp_flags = ENDIAN_HTONL(flags)( ((wxUint32) ( (((wxUint32) (flags) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (flags) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (flags) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (flags) & (wxUint32) 0xff000000U
) >> 24))) )
;
770 WriteBufferToSocket(&tmp_flags, sizeof(uint32));
771
772 // preallocate 4 bytes in buffer for packet length
773 uint32_t packet_len = 0;
774 WriteBufferToSocket(&packet_len, sizeof(uint32));
775
776 packet->WritePacket(*this);
777
778 // Finalize zlib compression and move current data to output queue
779 FlushBuffers();
780
781 // find the beginning of our data in the output queue
782 if (outputQueueSize) {
783 ++outputStart;
784 } else {
785 outputStart = m_output_queue.begin();
786 }
787 // now calculate actual size of data
788 for(std::list<CQueuedData*>::iterator it = outputStart; it != m_output_queue.end(); ++it) {
789 packet_len += (uint32_t)(*it)->GetDataLength();
790 }
791 // header size is not counted
792 packet_len -= EC_HEADER_SIZE;
793 // now write actual length at offset 4
794 uint32 packet_len_E = ENDIAN_HTONL(packet_len)( ((wxUint32) ( (((wxUint32) (packet_len) & (wxUint32) 0x000000ffU
) << 24) | (((wxUint32) (packet_len) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) (packet_len) & (wxUint32) 0x00ff0000U
) >> 8) | (((wxUint32) (packet_len) & (wxUint32) 0xff000000U
) >> 24))) )
;
795 (*outputStart)->WriteAt(&packet_len_E, 4, 4);
796
797 if (flags & EC_FLAG_ZLIB) {
798 int zerror = deflateEnd(&m_z);
799 if ( zerror != Z_OK0 ) {
800 AddDebugLogLineN(logEC, wxT("WritePacket: ZLib error"))do {} while (false);
801 ShowZError(zerror, &m_z);
802 }
803 }
804 return packet_len;
805}
806
807
808const CECPacket *CECSocket::ReadPacket()
809{
810 CECPacket *packet = 0;
811
812 uint32_t flags = m_rx_flags;
813
814 if ( ((flags & 0x60) != 0x20) || (flags & EC_FLAG_UNKNOWN_MASK) ) {
815 // Protocol error - other end might use an older protocol
816 AddDebugLogLineN(logEC, wxT("ReadPacket: protocol error"))do {} while (false);
817 cout << "ReadPacket: packet have invalid flags " << flags << endl;
818 CloseSocket();
819 return 0;
820 }
821
822 if (flags & EC_FLAG_ZLIB) {
823
824 m_z.zalloc = Z_NULL0;
825 m_z.zfree = Z_NULL0;
826 m_z.opaque = Z_NULL0;
827 m_z.avail_in = 0;
828 m_z.next_in = 0;
829
830 int zerror = inflateInit(&m_z)inflateInit_((&m_z), "1.3.1", (int)sizeof(z_stream));
831 if (zerror != Z_OK0) {
832 AddDebugLogLineN(logEC, wxT("ReadPacket: zlib error"))do {} while (false);
833 ShowZError(zerror, &m_z);
834 cout << "ReadPacket: failed zlib init" << endl;
835 CloseSocket();
836 return 0;
837 }
838 }
839
840 m_curr_rx_data->ToZlib(m_z);
841 packet = new CECPacket();
842
843 if (!packet->ReadFromSocket(*this)) {
844 AddDebugLogLineN(logEC, wxT("ReadPacket: error in packet read"))do {} while (false);
845 cout << "ReadPacket: error in packet read" << endl;
846 delete packet;
847 packet = NULL__null;
848 CloseSocket();
849 }
850
851 if (flags & EC_FLAG_ZLIB) {
852 int zerror = inflateEnd(&m_z);
853 if ( zerror != Z_OK0 ) {
854 AddDebugLogLineN(logEC, wxT("ReadPacket: zlib error"))do {} while (false);
855 ShowZError(zerror, &m_z);
856 cout << "ReadPacket: failed zlib free" << endl;
857 CloseSocket();
858 }
859 }
860
861 return packet;
862}
863
864const CECPacket *CECSocket::OnPacketReceived(const CECPacket *, uint32)
865{
866 return 0;
867}
868// File_checked_for_headers