summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ByteBuffer.cpp35
-rw-r--r--src/Crypto.cpp3
-rw-r--r--src/OSSupport/Socket.cpp27
-rw-r--r--src/OSSupport/Socket.h9
-rw-r--r--src/OSSupport/SocketThreads.cpp172
-rw-r--r--src/OSSupport/SocketThreads.h26
-rw-r--r--src/OSSupport/Timer.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp45
-rw-r--r--src/Root.cpp2
-rw-r--r--src/StringUtils.cpp6
-rw-r--r--src/WorldStorage/WSSAnvil.cpp12
-rw-r--r--src/main.cpp34
12 files changed, 279 insertions, 94 deletions
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index e06f63a0e..d2d3beb97 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -54,6 +54,7 @@ public:
{
TestRead();
TestWrite();
+ TestWrap();
}
void TestRead(void)
@@ -61,11 +62,11 @@ public:
cByteBuffer buf(50);
buf.Write("\x05\xac\x02\x00", 4);
UInt32 v1;
- ASSERT(buf.ReadVarInt(v1) && (v1 == 5));
+ assert(buf.ReadVarInt(v1) && (v1 == 5));
UInt32 v2;
- ASSERT(buf.ReadVarInt(v2) && (v2 == 300));
+ assert(buf.ReadVarInt(v2) && (v2 == 300));
UInt32 v3;
- ASSERT(buf.ReadVarInt(v3) && (v3 == 0));
+ assert(buf.ReadVarInt(v3) && (v3 == 0));
}
void TestWrite(void)
@@ -76,9 +77,30 @@ public:
buf.WriteVarInt(0);
AString All;
buf.ReadAll(All);
- ASSERT(All.size() == 4);
- ASSERT(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
+ assert(All.size() == 4);
+ assert(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
}
+
+ void TestWrap(void)
+ {
+ cByteBuffer buf(3);
+ for (int i = 0; i < 1000; i++)
+ {
+ int FreeSpace = buf.GetFreeSpace();
+ assert(buf.GetReadableSpace() == 0);
+ assert(FreeSpace > 0);
+ assert(buf.Write("a", 1));
+ assert(buf.CanReadBytes(1));
+ assert(buf.GetReadableSpace() == 1);
+ unsigned char v = 0;
+ assert(buf.ReadByte(v));
+ assert(v == 'a');
+ assert(buf.GetReadableSpace() == 0);
+ buf.CommitRead();
+ assert(buf.GetFreeSpace() == FreeSpace); // We're back to normal
+ }
+ }
+
} g_ByteBufferTest;
#endif
@@ -159,7 +181,7 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
int CurReadableSpace = GetReadableSpace();
int WrittenBytes = 0;
- if (GetFreeSpace() < a_Count)
+ if (CurFreeSpace < a_Count)
{
return false;
}
@@ -864,3 +886,4 @@ void cByteBuffer::CheckValid(void) const
+
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
index 2045d0385..540b5cfde 100644
--- a/src/Crypto.cpp
+++ b/src/Crypto.cpp
@@ -214,7 +214,6 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte
ASSERT(!"Invalid a_PlainLength!");
return -1;
}
- size_t DecryptedLength;
int res = rsa_pkcs1_encrypt(
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PUBLIC,
a_PlainLength, a_PlainData, a_EncryptedData
@@ -223,7 +222,7 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte
{
return -1;
}
- return (int)DecryptedLength;
+ return (int)m_Rsa.len;
}
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index 4226a7535..6afaceedf 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -6,7 +6,8 @@
#ifndef _WIN32
#include <netdb.h>
#include <unistd.h>
- #include <arpa/inet.h> //inet_ntoa()
+ #include <arpa/inet.h> // inet_ntoa()
+ #include <sys/ioctl.h> // ioctl()
#else
#define socklen_t int
#endif
@@ -320,7 +321,7 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
-int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags)
+int cSocket::Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags)
{
return recv(m_Socket, a_Buffer, a_Length, a_Flags);
}
@@ -354,3 +355,25 @@ unsigned short cSocket::GetPort(void) const
+
+void cSocket::SetNonBlocking(void)
+{
+ #ifdef _WIN32
+ u_long NonBlocking = 1;
+ int res = ioctlsocket(m_Socket, FIONBIO, &NonBlocking);
+ #else
+ int NonBlocking = 1;
+ int res = ioctl(m_Socket, FIONBIO, (char *)&NonBlocking);
+ #endif
+ if (res != 0)
+ {
+ LOGERROR("Cannot set socket to non-blocking. This would make the server deadlock later on, aborting.\nErr: %d, %d, %s",
+ res, GetLastError(), GetLastErrorString().c_str()
+ );
+ abort();
+ }
+}
+
+
+
+
diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h
index 4ca3d61f4..bdc2babf5 100644
--- a/src/OSSupport/Socket.h
+++ b/src/OSSupport/Socket.h
@@ -24,6 +24,12 @@ public:
{
IPv4 = AF_INET,
IPv6 = AF_INET6,
+
+ #ifdef _WIN32
+ ErrWouldBlock = WSAEWOULDBLOCK,
+ #else
+ ErrWouldBlock = EWOULDBLOCK,
+ #endif
} ;
#ifdef _WIN32
@@ -110,6 +116,9 @@ public:
unsigned short GetPort(void) const; // Returns 0 on failure
const AString & GetIPString(void) const { return m_IPString; }
+
+ /** Sets the socket into non-blocking mode */
+ void SetNonBlocking(void);
private:
xSocket m_Socket;
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index 74932daf8..3e2631733 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -175,6 +175,7 @@ void cSocketThreads::cSocketThread::AddClient(const cSocket & a_Socket, cCallbac
m_Slots[m_NumSlots].m_Client = a_Client;
m_Slots[m_NumSlots].m_Socket = a_Socket;
+ m_Slots[m_NumSlots].m_Socket.SetNonBlocking();
m_Slots[m_NumSlots].m_Outgoing.clear();
m_Slots[m_NumSlots].m_State = sSlot::ssNormal;
m_NumSlots++;
@@ -213,7 +214,9 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client)
else
{
// Query and queue the last batch of outgoing data:
- m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing);
+ AString Data;
+ m_Slots[i].m_Client->GetOutgoingData(Data);
+ m_Slots[i].m_Outgoing.append(Data);
if (m_Slots[i].m_Outgoing.empty())
{
// No more outgoing data, shut the socket down immediately:
@@ -386,38 +389,28 @@ void cSocketThreads::cSocketThread::Execute(void)
// The main thread loop:
while (!m_ShouldTerminate)
{
- // Put all sockets into the Read set:
+ // Read outgoing data from the clients:
+ QueueOutgoingData();
+
+ // Put sockets into the sets
fd_set fdRead;
+ fd_set fdWrite;
cSocket::xSocket Highest = m_ControlSocket1.GetSocket();
-
- PrepareSet(&fdRead, Highest, false);
+ PrepareSets(&fdRead, &fdWrite, Highest);
// Wait for the sockets:
timeval Timeout;
Timeout.tv_sec = 5;
Timeout.tv_usec = 0;
- if (select(Highest + 1, &fdRead, NULL, NULL, &Timeout) == -1)
+ if (select(Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1)
{
- LOG("select(R) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
+ LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
continue;
}
+ // Perform the IO:
ReadFromSockets(&fdRead);
-
- // Test sockets for writing:
- fd_set fdWrite;
- Highest = m_ControlSocket1.GetSocket();
- PrepareSet(&fdWrite, Highest, true);
- Timeout.tv_sec = 0;
- Timeout.tv_usec = 0;
- if (select(Highest + 1, NULL, &fdWrite, NULL, &Timeout) == -1)
- {
- LOG("select(W) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
- continue;
- }
-
WriteToSockets(&fdWrite);
-
CleanUpShutSockets();
} // while (!mShouldTerminate)
}
@@ -426,10 +419,11 @@ void cSocketThreads::cSocketThread::Execute(void)
-void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting)
+void cSocketThreads::cSocketThread::PrepareSets(fd_set * a_Read, fd_set * a_Write, cSocket::xSocket & a_Highest)
{
- FD_ZERO(a_Set);
- FD_SET(m_ControlSocket1.GetSocket(), a_Set);
+ FD_ZERO(a_Read);
+ FD_ZERO(a_Write);
+ FD_SET(m_ControlSocket1.GetSocket(), a_Read);
cCSLock Lock(m_Parent->m_CS);
for (int i = m_NumSlots - 1; i >= 0; --i)
@@ -444,11 +438,16 @@ void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket
continue;
}
cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket();
- FD_SET(s, a_Set);
+ FD_SET(s, a_Read);
if (s > a_Highest)
{
a_Highest = s;
}
+ if (!m_Slots[i].m_Outgoing.empty())
+ {
+ // There's outgoing data for the socket, put it in the Write set
+ FD_SET(s, a_Write);
+ }
} // for i - m_Slots[]
}
@@ -480,34 +479,37 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read)
int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0);
if (Received <= 0)
{
- // The socket has been closed by the remote party
- switch (m_Slots[i].m_State)
+ if (cSocket::GetLastError() != cSocket::ErrWouldBlock)
{
- case sSlot::ssNormal:
- {
- // Notify the callback that the remote has closed the socket; keep the slot
- m_Slots[i].m_Client->SocketClosed();
- m_Slots[i].m_State = sSlot::ssRemoteClosed;
- break;
- }
- case sSlot::ssWritingRestOut:
- case sSlot::ssShuttingDown:
- case sSlot::ssShuttingDown2:
- {
- // Force-close the socket and remove the slot:
- m_Slots[i].m_Socket.CloseSocket();
- m_Slots[i] = m_Slots[--m_NumSlots];
- break;
- }
- default:
+ // The socket has been closed by the remote party
+ switch (m_Slots[i].m_State)
{
- LOG("%s: Unexpected socket state: %d (%s)",
- __FUNCTION__, m_Slots[i].m_Socket.GetSocket(), m_Slots[i].m_Socket.GetIPString().c_str()
- );
- ASSERT(!"Unexpected socket state");
- break;
- }
- } // switch (m_Slots[i].m_State)
+ case sSlot::ssNormal:
+ {
+ // Notify the callback that the remote has closed the socket; keep the slot
+ m_Slots[i].m_Client->SocketClosed();
+ m_Slots[i].m_State = sSlot::ssRemoteClosed;
+ break;
+ }
+ case sSlot::ssWritingRestOut:
+ case sSlot::ssShuttingDown:
+ case sSlot::ssShuttingDown2:
+ {
+ // Force-close the socket and remove the slot:
+ m_Slots[i].m_Socket.CloseSocket();
+ m_Slots[i] = m_Slots[--m_NumSlots];
+ break;
+ }
+ default:
+ {
+ LOG("%s: Unexpected socket state: %d (%s)",
+ __FUNCTION__, m_Slots[i].m_Socket.GetSocket(), m_Slots[i].m_Socket.GetIPString().c_str()
+ );
+ ASSERT(!"Unexpected socket state");
+ break;
+ }
+ } // switch (m_Slots[i].m_State)
+ }
}
else
{
@@ -539,7 +541,9 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
// Request another chunk of outgoing data:
if (m_Slots[i].m_Client != NULL)
{
- m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing);
+ AString Data;
+ m_Slots[i].m_Client->GetOutgoingData(Data);
+ m_Slots[i].m_Outgoing.append(Data);
}
if (m_Slots[i].m_Outgoing.empty())
{
@@ -553,8 +557,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
}
} // if (outgoing data is empty)
- int Sent = m_Slots[i].m_Socket.Send(m_Slots[i].m_Outgoing.data(), m_Slots[i].m_Outgoing.size());
- if (Sent < 0)
+ if (!SendDataThroughSocket(m_Slots[i].m_Socket, m_Slots[i].m_Outgoing))
{
int Err = cSocket::GetLastError();
LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), GetOSErrorString(Err).c_str());
@@ -565,7 +568,6 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
}
return;
}
- m_Slots[i].m_Outgoing.erase(0, Sent);
if (m_Slots[i].m_Outgoing.empty() && (m_Slots[i].m_State == sSlot::ssWritingRestOut))
{
@@ -590,8 +592,41 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
+bool cSocketThreads::cSocketThread::SendDataThroughSocket(cSocket & a_Socket, AString & a_Data)
+{
+ // Send data in smaller chunks, so that the OS send buffers aren't overflown easily
+ while (!a_Data.empty())
+ {
+ size_t NumToSend = std::min(a_Data.size(), (size_t)1024);
+ int Sent = a_Socket.Send(a_Data.data(), NumToSend);
+ if (Sent < 0)
+ {
+ int Err = cSocket::GetLastError();
+ if (Err == cSocket::ErrWouldBlock)
+ {
+ // The OS send buffer is full, leave the outgoing data for the next time
+ return true;
+ }
+ // An error has occured
+ return false;
+ }
+ if (Sent == 0)
+ {
+ a_Socket.CloseSocket();
+ return true;
+ }
+ a_Data.erase(0, Sent);
+ }
+ return true;
+}
+
+
+
+
+
void cSocketThreads::cSocketThread::CleanUpShutSockets(void)
{
+ cCSLock Lock(m_Parent->m_CS);
for (int i = m_NumSlots - 1; i >= 0; i--)
{
switch (m_Slots[i].m_State)
@@ -617,3 +652,32 @@ void cSocketThreads::cSocketThread::CleanUpShutSockets(void)
+void cSocketThreads::cSocketThread::QueueOutgoingData(void)
+{
+ cCSLock Lock(m_Parent->m_CS);
+ for (int i = 0; i < m_NumSlots; i++)
+ {
+ if (m_Slots[i].m_Client != NULL)
+ {
+ AString Data;
+ m_Slots[i].m_Client->GetOutgoingData(Data);
+ m_Slots[i].m_Outgoing.append(Data);
+ }
+ if (m_Slots[i].m_Outgoing.empty())
+ {
+ // No outgoing data is ready
+ if (m_Slots[i].m_State == sSlot::ssWritingRestOut)
+ {
+ // The socket doesn't want to be kept alive anymore, and doesn't have any remaining data to send.
+ // Shut it down and then close it after a timeout, or when the other side agrees
+ m_Slots[i].m_State = sSlot::ssShuttingDown;
+ m_Slots[i].m_Socket.ShutdownReadWrite();
+ }
+ continue;
+ }
+ }
+}
+
+
+
+
diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h
index 9e1947ab6..fcd2ce11f 100644
--- a/src/OSSupport/SocketThreads.h
+++ b/src/OSSupport/SocketThreads.h
@@ -66,7 +66,8 @@ public:
/** Called when data is received from the remote party */
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
- /** Called when data can be sent to remote party; the function is supposed to *append* outgoing data to a_Data */
+ /** Called when data can be sent to remote party
+ The function is supposed to *set* outgoing data to a_Data (overwrite) */
virtual void GetOutgoingData(AString & a_Data) = 0;
/** Called when the socket has been closed for any reason */
@@ -156,16 +157,27 @@ private:
virtual void Execute(void) override;
- /** Puts all sockets into the set, along with m_ControlSocket1.
- Only sockets that are able to send and receive data are put in the Set.
- Is a_IsForWriting is true, the ssWritingRestOut sockets are added as well. */
- void PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting);
+ /** Prepares the Read and Write socket sets for select()
+ Puts all sockets into the read set, along with m_ControlSocket1.
+ Only sockets that have outgoing data queued on them are put in the write set.*/
+ void PrepareSets(fd_set * a_ReadSet, fd_set * a_WriteSet, cSocket::xSocket & a_Highest);
- void ReadFromSockets(fd_set * a_Read); // Reads from sockets indicated in a_Read
- void WriteToSockets (fd_set * a_Write); // Writes to sockets indicated in a_Write
+ /** Reads from sockets indicated in a_Read */
+ void ReadFromSockets(fd_set * a_Read);
+ /** Writes to sockets indicated in a_Write */
+ void WriteToSockets (fd_set * a_Write);
+
+ /** Sends data through the specified socket, trying to fill the OS send buffer in chunks.
+ Returns true if there was no error while sending, false if an error has occured.
+ Modifies a_Data to contain only the unsent data. */
+ bool SendDataThroughSocket(cSocket & a_Socket, AString & a_Data);
+
/** Removes those slots in ssShuttingDown2 state, sets those with ssShuttingDown state to ssShuttingDown2 */
void CleanUpShutSockets(void);
+
+ /** Calls each client's callback to retrieve outgoing data for that client. */
+ void QueueOutgoingData(void);
} ;
typedef std::list<cSocketThread *> cSocketThreadList;
diff --git a/src/OSSupport/Timer.cpp b/src/OSSupport/Timer.cpp
index ed16f9e3a..fd838dd0d 100644
--- a/src/OSSupport/Timer.cpp
+++ b/src/OSSupport/Timer.cpp
@@ -28,7 +28,7 @@ long long cTimer::GetNowTime(void)
#else
struct timeval now;
gettimeofday(&now, NULL);
- return (long long)(now.tv_sec * 1000 + now.tv_usec / 1000);
+ return (long long)now.tv_sec * 1000 + (long long)now.tv_usec / 1000;
#endif
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 9bb2cfbf0..0d349de03 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -54,7 +54,7 @@ Implements the 1.7.x protocol classes:
// fwd: main.cpp:
-extern bool g_ShouldLogComm;
+extern bool g_ShouldLogCommIn, g_ShouldLogCommOut;
@@ -74,7 +74,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
m_IsEncrypted(false)
{
// Create the comm log file, if so requested:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommIn || g_ShouldLogCommOut)
{
cFile::CreateFolder("CommLogs");
AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
@@ -1083,7 +1083,7 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property
void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
{
// Write the incoming data into the comm log file:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommIn)
{
if (m_ReceivedData.GetReadableSpace() > 0)
{
@@ -1092,9 +1092,10 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
+ ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
- m_CommLogFile.Printf("Incoming data, %d (0x%x) bytes unparsed already present in buffer:\n%s\n",
+ m_CommLogFile.Printf("Incoming data, %d (0x%x) unparsed bytes already present in buffer:\n%s\n",
AllData.size(), AllData.size(), Hex.c_str()
);
}
@@ -1103,6 +1104,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n",
a_Size, a_Size, Hex.c_str()
);
+ m_CommLogFile.Flush();
}
if (!m_ReceivedData.Write(a_Data, a_Size))
@@ -1119,12 +1121,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (!m_ReceivedData.ReadVarInt(PacketLen))
{
// Not enough data
- return;
+ m_ReceivedData.ResetRead();
+ break;
}
if (!m_ReceivedData.CanReadBytes(PacketLen))
{
// The full packet hasn't been received yet
- return;
+ m_ReceivedData.ResetRead();
+ break;
}
cByteBuffer bb(PacketLen + 1);
VERIFY(m_ReceivedData.ReadToByteBuffer(bb, (int)PacketLen));
@@ -1137,11 +1141,11 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (!bb.ReadVarInt(PacketType))
{
// Not enough data
- return;
+ break;
}
// Log the packet info into the comm log file:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommIn)
{
AString PacketData;
bb.ReadAll(PacketData);
@@ -1173,7 +1177,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
#endif // _DEBUG
// Put a message in the comm log:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommIn)
{
m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
}
@@ -1189,7 +1193,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
);
// Put a message in the comm log:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommIn)
{
m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
1, bb.GetReadableSpace()
@@ -1200,7 +1204,24 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
}
- } // while (true)
+ } // for(ever)
+
+ // Log any leftover bytes into the logfile:
+ if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0))
+ {
+ AString AllData;
+ int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ m_ReceivedData.ReadAll(AllData);
+ m_ReceivedData.ResetRead();
+ m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
+ ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
+ AString Hex;
+ CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
+ m_CommLogFile.Printf("There are %d (0x%x) bytes of non-parse-able data left in the buffer:\n%s",
+ m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str()
+ );
+ m_CommLogFile.Flush();
+ }
}
@@ -1881,7 +1902,7 @@ cProtocol172::cPacketizer::~cPacketizer()
m_Out.CommitRead();
// Log the comm into logfile:
- if (g_ShouldLogComm)
+ if (g_ShouldLogCommOut)
{
AString Hex;
ASSERT(DataToSend.size() > 0);
diff --git a/src/Root.cpp b/src/Root.cpp
index fa1fdb37a..883bfe76e 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -200,7 +200,7 @@ void cRoot::Start(void)
long long finishmseconds = Time.GetNowTime();
finishmseconds -= mseconds;
- LOG("Startup complete, took %i ms!", finishmseconds);
+ LOG("Startup complete, took %lld ms!", finishmseconds);
#ifdef _WIN32
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
#endif
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 0dbd41c12..3fe75d611 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -833,7 +833,8 @@ AString Base64Encode(const AString & a_Input)
short GetBEShort(const char * a_Mem)
{
- return (((short)a_Mem[0]) << 8) | a_Mem[1];
+ const Byte * Bytes = (const Byte *)a_Mem;
+ return (Bytes[0] << 8) | Bytes[1];
}
@@ -842,7 +843,8 @@ short GetBEShort(const char * a_Mem)
int GetBEInt(const char * a_Mem)
{
- return (((int)a_Mem[0]) << 24) | (((int)a_Mem[1]) << 16) | (((int)a_Mem[2]) << 8) | a_Mem[3];
+ const Byte * Bytes = (const Byte *)a_Mem;
+ return (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | Bytes[3];
}
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index e2a882f65..a0f9136d8 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -611,12 +611,18 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
{
- int ID = a_NBT.FindChildByName(a_TagIdx, "id");
- if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
+ int Type = a_NBT.FindChildByName(a_TagIdx, "id");
+ if ((Type < 0) || (a_NBT.GetType(Type) != TAG_Short))
{
return false;
}
- a_Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
+ a_Item.m_ItemType = a_NBT.GetShort(Type);
+ if (a_Item.m_ItemType < 0)
+ {
+ LOGD("Encountered an item with negative type (%d). Replacing with an empty item.", a_NBT.GetShort(Type));
+ a_Item.Empty();
+ return true;
+ }
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
diff --git a/src/main.cpp b/src/main.cpp
index 06b344c25..c8cd2d4fe 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,8 +19,11 @@ bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so
-/** If set to true, the protocols will log each player's communication to a separate logfile */
-bool g_ShouldLogComm;
+/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
+bool g_ShouldLogCommIn;
+
+/** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */
+bool g_ShouldLogCommOut;
@@ -66,11 +69,13 @@ void NonCtrlHandler(int a_Signal)
std::signal(a_Signal, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
+ exit(EXIT_FAILURE);
break;
}
+ case SIGINT:
case SIGTERM:
{
- std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it...
+ std::signal(a_Signal, SIG_IGN); // Server is shutting down, wait for it...
break;
}
default: break;
@@ -224,6 +229,10 @@ int main( int argc, char **argv )
std::signal(SIGSEGV, NonCtrlHandler);
std::signal(SIGTERM, NonCtrlHandler);
std::signal(SIGINT, NonCtrlHandler);
+ std::signal(SIGABRT, NonCtrlHandler);
+ #ifdef SIGABRT_COMPAT
+ std::signal(SIGABRT_COMPAT, NonCtrlHandler);
+ #endif // SIGABRT_COMPAT
#endif
// DEBUG: test the dumpfile creation:
@@ -237,7 +246,24 @@ int main( int argc, char **argv )
(NoCaseCompare(argv[i], "/logcomm") == 0)
)
{
- g_ShouldLogComm = true;
+ g_ShouldLogCommIn = true;
+ g_ShouldLogCommOut = true;
+ }
+ if (
+ (NoCaseCompare(argv[i], "/commlogin") == 0) ||
+ (NoCaseCompare(argv[i], "/comminlog") == 0) ||
+ (NoCaseCompare(argv[i], "/logcommin") == 0)
+ )
+ {
+ g_ShouldLogCommIn = true;
+ }
+ if (
+ (NoCaseCompare(argv[i], "/commlogout") == 0) ||
+ (NoCaseCompare(argv[i], "/commoutlog") == 0) ||
+ (NoCaseCompare(argv[i], "/logcommout") == 0)
+ )
+ {
+ g_ShouldLogCommOut = true;
}
}