summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-06-26 23:07:24 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-06-26 23:07:24 +0300
commit718e96a95c5596fa6c7e21984cf8bdfb6d528e60 (patch)
treee36882173cfed94a825ae1f97b9916022bd5b98e
parent84b095e0faa33bd6af98f89dabf6b4e54312f113 (diff)
MQTT: proper MQTT payload preparation
-rw-r--r--protocols/Facebook/facebook.vcxproj3
-rw-r--r--protocols/Facebook/src/http.cpp3
-rw-r--r--protocols/Facebook/src/mqtt.cpp142
-rw-r--r--protocols/Facebook/src/mqtt.h39
-rw-r--r--protocols/Facebook/src/proto.cpp2
-rw-r--r--protocols/Facebook/src/proto.h5
-rw-r--r--protocols/Facebook/src/server.cpp36
-rw-r--r--protocols/Facebook/src/stdafx.h2
8 files changed, 202 insertions, 30 deletions
diff --git a/protocols/Facebook/facebook.vcxproj b/protocols/Facebook/facebook.vcxproj
index 9bf2597eb3..25c2fbe25a 100644
--- a/protocols/Facebook/facebook.vcxproj
+++ b/protocols/Facebook/facebook.vcxproj
@@ -29,5 +29,8 @@
<ProjectReference Include="..\..\libs\libjson\libjson.vcxproj">
<Project>{f6a9340e-b8d9-4c75-be30-47dc66d0abc7}</Project>
</ProjectReference>
+ <ProjectReference Include="..\..\libs\zlib\zlib.vcxproj">
+ <Project>{e2a369cd-eda3-414f-8ad0-e732cd7ee68c}</Project>
+ </ProjectReference>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/protocols/Facebook/src/http.cpp b/protocols/Facebook/src/http.cpp
index aa2d4a5c5e..88a73c4006 100644
--- a/protocols/Facebook/src/http.cpp
+++ b/protocols/Facebook/src/http.cpp
@@ -107,6 +107,9 @@ AsyncHttpRequest* FacebookProto::CreateRequest(const char *szName, const char *s
szLocale = "en";
pReq << CHAR_PARAM("locale", szLocale);
+ if (!m_szAuthToken.IsEmpty())
+ pReq->AddHeader("Authorization", "OAuth " + m_szAuthToken);
+
pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
unsigned int id;
diff --git a/protocols/Facebook/src/mqtt.cpp b/protocols/Facebook/src/mqtt.cpp
index ba81cbad32..5e3008def8 100644
--- a/protocols/Facebook/src/mqtt.cpp
+++ b/protocols/Facebook/src/mqtt.cpp
@@ -59,14 +59,14 @@ FbThrift& FbThrift::operator<<(uint8_t value)
FbThrift& FbThrift::operator<<(const char *str)
{
size_t len = mir_strlen(str);
- writeInt32((int)len);
+ writeIntV(len);
m_buf.append((void*)str, len);
return *this;
}
void FbThrift::writeBool(bool bValue)
{
- uint8_t b = (bValue) ? 1 : 2;
+ uint8_t b = (bValue) ? 0x11 : 0x12;
m_buf.append(&b, 1);
}
@@ -75,11 +75,10 @@ void FbThrift::writeBuf(const void *pData, size_t cbLen)
m_buf.append((void*)pData, cbLen);
}
-void FbThrift::writeField(int iType, int id)
+void FbThrift::writeField(int iType)
{
- uint8_t type = encodeType(iType);
+ uint8_t type = encodeType(iType) + 0x10;
m_buf.append(&type, 1);
- writeInt64(id);
}
void FbThrift::writeField(int iType, int id, int lastid)
@@ -96,17 +95,33 @@ void FbThrift::writeField(int iType, int id, int lastid)
}
}
-void FbThrift::writeInt32(__int32 value)
+void FbThrift::writeList(int iType, int size)
+{
+ uint8_t type = encodeType(iType);
+ if (size > 14) {
+ writeIntV(size);
+ *this << (type | 0xF0);
+ }
+ else *this << (type | (size << 4));
+}
+
+void FbThrift::writeInt16(uint16_t value)
+{
+ value = htons(value);
+ m_buf.append(&value, sizeof(value));
+}
+
+void FbThrift::writeInt32(int32_t value)
{
writeIntV((value << 1) ^ (value >> 31));
}
-void FbThrift::writeInt64(__int64 value)
+void FbThrift::writeInt64(int64_t value)
{
writeIntV((value << 1) ^ (value >> 63));
}
-void FbThrift::writeIntV(__int64 value)
+void FbThrift::writeIntV(uint64_t value)
{
bool bLast;
do {
@@ -120,50 +135,129 @@ void FbThrift::writeIntV(__int64 value)
} while (!bLast);
}
+MqttMessage::MqttMessage(FbMqttMessageType type, uint8_t flags, size_t payloadSize)
+{
+ uint8_t byte = ((type & 0x0F) << 4) | (flags & 0x0F);
+ *this << byte;
+
+ writeIntV(payloadSize);
+}
+
+void MqttMessage::writeStr(const char *str)
+{
+ size_t len = mir_strlen(str);
+ writeInt16((int)len);
+ writeBuf(str, len);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// MQTT functions
+bool FacebookProto::MqttConnect()
+{
+ NETLIBOPENCONNECTION nloc = {};
+ nloc.cbSize = sizeof(nloc);
+ nloc.szHost = "mqtt.facebook.com";
+ nloc.wPort = 443;
+ m_mqttConn = Netlib_OpenConnection(m_hNetlibUser, &nloc);
+ if (m_mqttConn == nullptr) {
+ debugLogA("connection failed, exiting");
+ return false;
+ }
+
+ memset(&zStreamIn, 0, sizeof(zStreamOut));
+ memset(&zStreamOut, 0, sizeof(zStreamOut));
+
+ if (deflateInit(&zStreamOut, Z_BEST_COMPRESSION) == Z_OK)
+ if (inflateInit(&zStreamIn) == Z_OK)
+ m_zlibAvailable = true;
+
+ return true;
+}
+
void FacebookProto::MqttOpen()
{
+ Utils_GetRandom(&m_iMqttId, sizeof(m_iMqttId));
+
FbThrift thrift;
- thrift.writeField(FB_THRIFT_TYPE_STRING, 1); // Client identifier
+ thrift.writeField(FB_THRIFT_TYPE_STRING); // Client identifier
thrift << m_szClientID;
thrift.writeField(FB_THRIFT_TYPE_STRUCT, 4, 1);
- thrift.writeField(FB_THRIFT_TYPE_I64, 1); // User identifier
+ thrift.writeField(FB_THRIFT_TYPE_I64); // User identifier
thrift.writeInt64(m_uid);
- thrift.writeField(FB_THRIFT_TYPE_STRING, 2); // User agent
+ thrift.writeField(FB_THRIFT_TYPE_STRING); // User agent
thrift << NETLIB_USER_AGENT;
- thrift.writeField(FB_THRIFT_TYPE_I64, 3);
+ thrift.writeField(FB_THRIFT_TYPE_I64);
thrift.writeInt64(23);
- thrift.writeField(FB_THRIFT_TYPE_I64, 4);
+ thrift.writeField(FB_THRIFT_TYPE_I64);
thrift.writeInt64(26);
- thrift.writeField(FB_THRIFT_TYPE_I32, 5);
+ thrift.writeField(FB_THRIFT_TYPE_I32);
thrift.writeInt32(1);
- thrift.writeField(FB_THRIFT_TYPE_BOOL, 6);
+
thrift.writeBool(true);
- thrift.writeField(FB_THRIFT_TYPE_BOOL, 7); // visibility
- thrift.writeBool(m_iStatus != ID_STATUS_INVISIBLE);
+ thrift.writeBool(m_iStatus != ID_STATUS_INVISIBLE); // visibility
- thrift.writeField(FB_THRIFT_TYPE_STRING, 8); // device id
+ thrift.writeField(FB_THRIFT_TYPE_STRING); // device id
thrift << m_szDeviceID;
- thrift.writeField(FB_THRIFT_TYPE_BOOL, 9);
thrift.writeBool(true);
- thrift.writeField(FB_THRIFT_TYPE_I32, 10);
+ thrift.writeField(FB_THRIFT_TYPE_I32);
thrift.writeInt32(1);
- thrift.writeField(FB_THRIFT_TYPE_I32, 11);
+ thrift.writeField(FB_THRIFT_TYPE_I32);
thrift.writeInt32(0);
- thrift.writeField(FB_THRIFT_TYPE_I64, 12);
+ thrift.writeField(FB_THRIFT_TYPE_I64);
thrift.writeInt64(m_iMqttId);
thrift.writeField(FB_THRIFT_TYPE_LIST, 14, 12);
- thrift.writeField(FB_THRIFT_TYPE_I32, 0);
+ thrift.writeList(FB_THRIFT_TYPE_I32, 0);
thrift << (BYTE)0;
- thrift.writeField(FB_THRIFT_TYPE_LIST, 15);
+ thrift.writeField(FB_THRIFT_TYPE_STRING);
thrift << m_szAuthToken << (BYTE)0;
+
+ FILE *out = fopen("C:\\qq.out", "wb");
+ fwrite(thrift.data(), 1, thrift.size(), out);
+ fclose(out);
+
+ BYTE *pData;
+ size_t dataSize;
+ if (m_zlibAvailable) {
+ dataSize = thrift.size() + 100;
+ pData = (BYTE *)mir_alloc(dataSize);
+
+ zStreamOut.avail_in = (unsigned)thrift.size();
+ zStreamOut.next_in = (BYTE *)thrift.data();
+ zStreamOut.avail_out = (unsigned)dataSize;
+ zStreamOut.next_out = (BYTE *)pData;
+
+ switch (deflate(&zStreamOut, Z_SYNC_FLUSH)) {
+ case Z_OK: debugLogA("Deflate: Z_OK"); break;
+ case Z_BUF_ERROR: debugLogA("Deflate: Z_BUF_ERROR"); break;
+ case Z_DATA_ERROR: debugLogA("Deflate: Z_DATA_ERROR"); break;
+ case Z_MEM_ERROR: debugLogA("Deflate: Z_MEM_ERROR"); break;
+ }
+
+ dataSize = dataSize - zStreamOut.avail_out;
+ }
+ else {
+ dataSize = thrift.size();
+ pData = (BYTE *)thrift.data();
+ }
+
+ uint8_t protocolVersion = 3;
+ uint8_t flags = FB_MQTT_CONNECT_FLAG_USER | FB_MQTT_CONNECT_FLAG_PASS | FB_MQTT_CONNECT_FLAG_CLR | FB_MQTT_CONNECT_FLAG_QOS1;
+ MqttMessage payload(FB_MQTT_MESSAGE_TYPE_CONNECT, 0, dataSize - 3);
+ payload.writeStr("MQTToT");
+ payload << protocolVersion << flags;
+ payload.writeInt16(60); // timeout
+ payload.writeBuf(pData, dataSize);
+
+ if (pData != thrift.data())
+ mir_free(pData);
+
+ Netlib_Send(m_mqttConn, (char*)payload.data(), (int)payload.size());
}
diff --git a/protocols/Facebook/src/mqtt.h b/protocols/Facebook/src/mqtt.h
index 5b8147e5f2..55c071d0e3 100644
--- a/protocols/Facebook/src/mqtt.h
+++ b/protocols/Facebook/src/mqtt.h
@@ -34,21 +34,52 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define FB_THRIFT_TYPE_SET 14
#define FB_THRIFT_TYPE_LIST 15
+enum FbMqttMessageType
+{
+ FB_MQTT_MESSAGE_TYPE_CONNECT = 1,
+ FB_MQTT_MESSAGE_TYPE_CONNACK = 2,
+ FB_MQTT_MESSAGE_TYPE_PUBLISH = 3,
+ FB_MQTT_MESSAGE_TYPE_PUBACK = 4,
+ FB_MQTT_MESSAGE_TYPE_PUBREC = 5,
+ FB_MQTT_MESSAGE_TYPE_PUBREL = 6,
+ FB_MQTT_MESSAGE_TYPE_PUBCOMP = 7,
+ FB_MQTT_MESSAGE_TYPE_SUBSCRIBE = 8,
+ FB_MQTT_MESSAGE_TYPE_SUBACK = 9,
+ FB_MQTT_MESSAGE_TYPE_UNSUBSCRIBE = 10,
+ FB_MQTT_MESSAGE_TYPE_UNSUBACK = 11,
+ FB_MQTT_MESSAGE_TYPE_PINGREQ = 12,
+ FB_MQTT_MESSAGE_TYPE_PINGRESP = 13,
+ FB_MQTT_MESSAGE_TYPE_DISCONNECT = 14
+};
+
class FbThrift
{
MBinBuffer m_buf;
public:
+ __inline void* data() { return m_buf.data(); }
+ __inline size_t size() { return m_buf.length(); }
+
FbThrift& operator<<(uint8_t);
FbThrift& operator<<(const char *);
void writeBool(bool value);
void writeBuf(const void *pData, size_t cbLen);
- void writeInt32(__int32 value);
- void writeInt64(__int64 value);
- void writeIntV(__int64 value);
- void writeField(int type, int id);
+ void writeInt16(uint16_t value);
+ void writeInt32(int32_t value);
+ void writeInt64(int64_t value);
+ void writeIntV(uint64_t value);
+ void writeField(int type);
void writeField(int type, int id, int lastid);
+ void writeList(int iType, int size);
+};
+
+class MqttMessage : public FbThrift
+{
+public:
+ MqttMessage(FbMqttMessageType type, uint8_t flags, size_t payloadSize);
+
+ void writeStr(const char *str);
};
#define FB_MQTT_CONNECT_FLAG_CLR 0x0002
diff --git a/protocols/Facebook/src/proto.cpp b/protocols/Facebook/src/proto.cpp
index a30b7c1ac1..6fe0d5acd4 100644
--- a/protocols/Facebook/src/proto.cpp
+++ b/protocols/Facebook/src/proto.cpp
@@ -70,6 +70,8 @@ FacebookProto::FacebookProto(const char *proto_name, const wchar_t *username) :
FacebookProto::~FacebookProto()
{
+ deflateEnd(&zStreamOut);
+ inflateEnd(&zStreamIn);
}
void FacebookProto::OnModulesLoaded()
diff --git a/protocols/Facebook/src/proto.h b/protocols/Facebook/src/proto.h
index aa8a9e60ab..153749776a 100644
--- a/protocols/Facebook/src/proto.h
+++ b/protocols/Facebook/src/proto.h
@@ -68,8 +68,12 @@ class FacebookProto : public PROTO<FacebookProto>
NETLIBHTTPREQUEST* ExecuteRequest(AsyncHttpRequest *pReq);
// MQTT functions
+ bool MqttConnect();
void MqttOpen();
+ HNETLIBCONN m_mqttConn;
+ z_stream zStreamIn, zStreamOut;
+
// internal data
CMStringA m_szDeviceID; // stored, GUID that identifies this miranda's account
CMStringA m_szClientID; // stored, random alphanumeric string of 20 chars
@@ -78,6 +82,7 @@ class FacebookProto : public PROTO<FacebookProto>
bool m_invisible;
bool m_bOnline;
+ bool m_zlibAvailable;
CMStringA m_szAuthToken; // calculated
diff --git a/protocols/Facebook/src/server.cpp b/protocols/Facebook/src/server.cpp
index dba8178fa8..162c6f9fa6 100644
--- a/protocols/Facebook/src/server.cpp
+++ b/protocols/Facebook/src/server.cpp
@@ -36,8 +36,7 @@ void FacebookProto::ServerThread(void *)
pReq->flags = NLHRF_HTTP11 | NLHRF_REDIRECT;
pReq->m_szUrl = "https://www.facebook.com/v3.3/dialog/oauth?client_id=478386432928815&redirect_uri=https://oauth.miranda-ng.org/facebook.php&state=qq";
- JsonReply reply(ExecuteRequest(pReq));
- if (reply.error()) {
+ if (JsonReply(ExecuteRequest(pReq)).error()) {
FAIL:
ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)m_iStatus, m_iDesiredStatus);
@@ -46,4 +45,37 @@ FAIL:
return;
}
}
+
+ auto *pReq = CreateRequest("FetchContactsFullQuery", "get");
+ pReq->m_szUrl = "https://graph.facebook.com/me/friends";
+ pReq->CalcSig();
+
+ JsonReply reply(ExecuteRequest(pReq));
+ if (reply.error())
+ goto FAIL;
+
+ if (!MqttConnect())
+ goto FAIL;
+
+ MqttOpen();
+
+ int bufSize = 2048;
+ char *buf = (char*)mir_alloc(bufSize);
+
+ while (!Miranda_IsTerminated()) {
+ int ret = Netlib_Recv(m_mqttConn, buf, bufSize);
+ if (ret == SOCKET_ERROR) {
+ debugLogA("Netlib_Recv() failed, error=%d", WSAGetLastError());
+ break;
+ }
+ if (ret == 0) {
+ debugLogA("Connection closed gracefully");
+ break;
+ }
+ }
+
+ debugLogA("exiting ServerThread");
+ int oldStatus = m_iStatus;
+ m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
}
diff --git a/protocols/Facebook/src/stdafx.h b/protocols/Facebook/src/stdafx.h
index dca99fc578..36af3e8128 100644
--- a/protocols/Facebook/src/stdafx.h
+++ b/protocols/Facebook/src/stdafx.h
@@ -50,6 +50,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <m_messagestate.h>
#include <m_gui.h>
+#include "../../libs/zlib/src/zlib.h"
+
#include "db.h"
#include "mqtt.h"
#include "proto.h"