diff options
author | George Hazan <ghazan@miranda.im> | 2017-01-20 23:19:29 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2017-01-20 23:19:29 +0300 |
commit | 4b3ab972d3109f4014746fc8b1ea5b443697861c (patch) | |
tree | 7b5eb03f1b7c3a66fce857ffd30b5774e2cd268e /protocols/Discord/src/gateway.cpp | |
parent | be6e15b71fcf555aad8bfd9054ca66ec71b91408 (diff) |
- valid (but totally undocumented) way of reading guild users;
- fix for decoding several replies from the single packet;
Diffstat (limited to 'protocols/Discord/src/gateway.cpp')
-rw-r--r-- | protocols/Discord/src/gateway.cpp | 167 |
1 files changed, 106 insertions, 61 deletions
diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp index d17ccf4952..694e30982c 100644 --- a/protocols/Discord/src/gateway.cpp +++ b/protocols/Discord/src/gateway.cpp @@ -17,6 +17,53 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" +struct WSHeader +{ + WSHeader() + { + memset(this, 0, sizeof(*this)); + } + + bool init(BYTE *buf, int bufSize) + { + bIsFinal = (buf[0] & 0x80) != 0; + bIsMasked = (buf[1] & 0x80) != 0; + opCode = buf[0] & 0x0F; + firstByte = buf[1] & 0x7F; + headerSize = 2 + (firstByte == 0x7E ? 2 : 0) + (firstByte == 0x7F ? 8 : 0) + (bIsMasked ? 4 : 0); + if (bufSize < headerSize) + return false; + + payloadSize = 0; + switch (firstByte) { + case 0x7F: + payloadSize += ((uint64_t)buf[2]) << 56; + payloadSize += ((uint64_t)buf[3]) << 48; + payloadSize += ((uint64_t)buf[4]) << 40; + payloadSize += ((uint64_t)buf[5]) << 32; + payloadSize += ((uint64_t)buf[6]) << 24; + payloadSize += ((uint64_t)buf[7]) << 16; + payloadSize += ((uint64_t)buf[8]) << 8; + payloadSize += ((uint64_t)buf[9]); + break; + + case 0x7E: + payloadSize += ((uint64_t)buf[2]) << 8; + payloadSize += ((uint64_t)buf[3]); + break; + + default: + payloadSize = firstByte; + } + return true; + } + + bool bIsFinal, bIsMasked; + int opCode, firstByte; + int headerSize; + uint64_t payloadSize; +}; + ////////////////////////////////////////////////////////////////////////////////////// // sends a piece of JSON to a server via a websocket, masked @@ -152,7 +199,7 @@ void CDiscordProto::GatewayThreadWorker() break; unsigned char buf[2048]; - int bufSize = Netlib_Recv(m_hGatewayConnection, (char*)buf + offset, _countof(buf) - offset, 0); + int bufSize = Netlib_Recv(m_hGatewayConnection, (char*)buf + offset, _countof(buf) - offset, MSG_NODUMP); if (bufSize == 0) { debugLogA("Gateway connection gracefully closed"); break; @@ -167,58 +214,29 @@ void CDiscordProto::GatewayThreadWorker() } offset = 0; - bool bIsFinal = (buf[0] & 0x80) != 0; - bool bIsMasked = (buf[1] & 0x80) != 0; - int opCode = buf[0] & 0x0F, firstByte = buf[1] & 0x7F; - int headerSize = 2 + (firstByte == 0x7E ? 2 : 0) + (firstByte == 0x7F ? 8 : 0) + (bIsMasked ? 4 : 0); - if (bufSize < headerSize) { + WSHeader hdr; + if (!hdr.init(buf, bufSize)) { offset = bufSize; continue; } - int dataShift; - uint64_t payloadSize = 0; - switch (firstByte) { - case 0x7F: - payloadSize += ((uint64_t)buf[2]) << 56; - payloadSize += ((uint64_t)buf[3]) << 48; - payloadSize += ((uint64_t)buf[4]) << 40; - payloadSize += ((uint64_t)buf[5]) << 32; - payloadSize += ((uint64_t)buf[6]) << 24; - payloadSize += ((uint64_t)buf[7]) << 16; - payloadSize += ((uint64_t)buf[8]) << 8; - payloadSize += ((uint64_t)buf[9]); - dataShift = 10; - break; - - case 0x7E: - payloadSize += ((uint64_t)buf[2]) << 8; - payloadSize += ((uint64_t)buf[3]); - dataShift = 4; - break; - - default: - payloadSize = firstByte; - dataShift = 2; - } - - debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, final = %d, masked = %d", bufSize, opCode, headerSize, bIsFinal, bIsMasked); + debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, final = %d, masked = %d", bufSize, hdr.opCode, hdr.headerSize, hdr.bIsFinal, hdr.bIsMasked); // we have some additional data, not only opcode - if (bufSize > headerSize) { - if (bIsFinal && payloadSize < _countof(buf)) { // it fits, no need to reallocate a buffer + if (bufSize > hdr.headerSize) { + if (hdr.bIsFinal && hdr.payloadSize < _countof(buf)) { // it fits, no need to reallocate a buffer bDataBufAllocated = false; - dataBuf = (char*)buf + headerSize; - dataBufSize = bufSize - headerSize; + dataBuf = (char*)buf + hdr.headerSize; + dataBufSize = bufSize - hdr.headerSize; } else { bDataBufAllocated = true; - size_t newSize = dataBufSize + payloadSize; - size_t currPacketSize = bufSize - headerSize; + size_t newSize = dataBufSize + hdr.payloadSize; + size_t currPacketSize = bufSize - hdr.headerSize; dataBuf = (char*)mir_realloc(dataBuf, newSize+1); - memcpy(dataBuf + dataBufSize, buf + headerSize, currPacketSize); - while (currPacketSize < payloadSize) { - int result = Netlib_Recv(m_hGatewayConnection, dataBuf + dataBufSize + currPacketSize, int(payloadSize - currPacketSize), 0); + memcpy(dataBuf + dataBufSize, buf + hdr.headerSize, currPacketSize); + while (currPacketSize < hdr.payloadSize) { + int result = Netlib_Recv(m_hGatewayConnection, dataBuf + dataBufSize + currPacketSize, int(hdr.payloadSize - currPacketSize), MSG_NODUMP); if (result == 0) { debugLogA("Gateway connection gracefully closed"); break; @@ -236,30 +254,47 @@ void CDiscordProto::GatewayThreadWorker() dataBuf[dataBufSize] = 0; } - switch (opCode){ - case 0: // text packet - case 1: // binary packet - case 2: // continuation - if (bIsFinal) { - // process a packet here - JSONNode root = JSONNode::parse(dataBuf); - if (root) - GatewayProcess(root); + // read all payloads from the current buffer, one by one + int iOffset = 0; + while (true) { + switch (hdr.opCode) { + case 0: // text packet + case 1: // binary packet + case 2: // continuation + if (hdr.bIsFinal) { + // process a packet here + char c = dataBuf[iOffset + hdr.payloadSize + 1]; dataBuf[iOffset + hdr.payloadSize + 1] = 0; + debugLogA("JSON received:\n%s", dataBuf + iOffset); + dataBuf[iOffset + hdr.payloadSize + 1] = c; + + JSONNode root = JSONNode::parse(dataBuf + iOffset); + if (root) + GatewayProcess(root); + } + break; + + case 8: // close + debugLogA("server required to exit"); + bExit = true; + break; + + case 9: // ping + debugLogA("ping received"); + Netlib_Send(m_hGatewayConnection, (char*)buf + hdr.headerSize, bufSize - hdr.headerSize, 0); + break; } - break; - case 8: // close - debugLogA("server required to exit", dataBufSize); - bExit = true; - break; + if (iOffset + hdr.payloadSize >= dataBufSize) + break; - case 9: // ping - debugLogA("ping received", dataBufSize); - Netlib_Send(m_hGatewayConnection, (char*)buf + headerSize, bufSize - headerSize, 0); - break; + iOffset += hdr.payloadSize; + if (!hdr.init((BYTE*)dataBuf + iOffset, (int)dataBufSize - iOffset)) + break; + + iOffset += hdr.headerSize; } - if (bIsFinal) { + if (hdr.bIsFinal) { if (bDataBufAllocated) mir_free(dataBuf); dataBuf = NULL; @@ -340,3 +375,13 @@ void CDiscordProto::GatewaySendIdentify() root << INT_PARAM("op", 2) << payload; GatewaySend(root); } + +void CDiscordProto::GatewaySendGuildInfo(SnowFlake id) +{ + JSONNode payload(JSON_ARRAY); payload.set_name("d"); + payload << INT64_PARAM("", id); + + JSONNode root; + root << INT_PARAM("op", 12) << payload; + GatewaySend(root); +} |