This commit is contained in:
DDVTech 2021-09-10 23:44:31 +02:00 committed by Thulinma
parent 5b79f296d6
commit fccf66fba2
280 changed files with 56975 additions and 71885 deletions

View file

@ -1,8 +1,8 @@
#include "websocket.h"
#include "bitfields.h"
#include "defines.h"
#include "encode.h"
#include "bitfields.h"
#include "timing.h"
#include "websocket.h"
#ifdef SSL
#include "mbedtls/sha1.h"
#endif
@ -14,16 +14,14 @@ namespace HTTP{
std::string connHeader = H.GetHeader("Connection");
Util::stringToLower(connHeader);
if (connHeader.find("upgrade") == std::string::npos){
FAIL_MSG("Could not negotiate websocket, connection header incorrect (%s).",
connHeader.c_str());
FAIL_MSG("Could not negotiate websocket, connection header incorrect (%s).", connHeader.c_str());
C.close();
return;
}
std::string upgradeHeader = H.GetHeader("Upgrade");
Util::stringToLower(upgradeHeader);
if (upgradeHeader != "websocket"){
FAIL_MSG("Could not negotiate websocket, upgrade header incorrect (%s).",
upgradeHeader.c_str());
FAIL_MSG("Could not negotiate websocket, upgrade header incorrect (%s).", upgradeHeader.c_str());
C.close();
return;
}
@ -49,20 +47,18 @@ namespace HTTP{
mbedtls_sha1_context ctx;
unsigned char outdata[20];
mbedtls_sha1_starts(&ctx);
mbedtls_sha1_update(&ctx, (const unsigned char*)client_key.data(), client_key.size());
mbedtls_sha1_update(&ctx, (const unsigned char *)client_key.data(), client_key.size());
mbedtls_sha1_finish(&ctx, outdata);
H.SetHeader("Sec-WebSocket-Accept", Encodings::Base64::encode(std::string((const char*)outdata, 20)));
H.SetHeader("Sec-WebSocket-Accept", Encodings::Base64::encode(std::string((const char *)outdata, 20)));
#endif
//H.SetHeader("Sec-WebSocket-Protocol", "json");
// H.SetHeader("Sec-WebSocket-Protocol", "json");
H.SendResponse("101", "Websocket away!", C);
}
/// Loops calling readFrame until the connection is closed, sleeping in between reads if needed.
bool Websocket::readLoop(){
while (C){
if (readFrame()){
return true;
}
if (readFrame()){return true;}
Util::sleep(500);
}
return false;
@ -70,105 +66,100 @@ namespace HTTP{
/// Loops reading from the socket until either there is no more data ready or a whole frame was read.
bool Websocket::readFrame(){
while(true){
//Check if we can receive the minimum frame size (2 header bytes, 0 payload)
while (true){
// Check if we can receive the minimum frame size (2 header bytes, 0 payload)
if (!C.Received().available(2)){
if (C.spool()){continue;}
return false;
}
std::string head = C.Received().copy(2);
//Read masked bit and payload length
// Read masked bit and payload length
bool masked = head[1] & 0x80;
uint64_t payLen = head[1] & 0x7F;
uint32_t headSize = 2 + (masked?4:0) + (payLen==126?2:0) + (payLen==127?8:0);
uint32_t headSize = 2 + (masked ? 4 : 0) + (payLen == 126 ? 2 : 0) + (payLen == 127 ? 8 : 0);
if (headSize > 2){
//Check if we can receive the whole header
// Check if we can receive the whole header
if (!C.Received().available(headSize)){
if (C.spool()){continue;}
return false;
}
//Read entire header, re-read real payload length
// Read entire header, re-read real payload length
head = C.Received().copy(headSize);
if (payLen == 126){
payLen = Bit::btohs(head.data()+2);
payLen = Bit::btohs(head.data() + 2);
}else if (payLen == 127){
payLen = Bit::btohll(head.data()+2);
payLen = Bit::btohll(head.data() + 2);
}
}
//Check if we can receive the whole frame (header + payload)
// Check if we can receive the whole frame (header + payload)
if (!C.Received().available(headSize + payLen)){
if (C.spool()){continue;}
return false;
}
C.Received().remove(headSize);//delete the header
C.Received().remove(headSize); // delete the header
std::string pl = C.Received().remove(payLen);
if (masked){
//If masked, apply the mask to the payload
const char * mask = head.data() + headSize - 4;//mask is last 4 bytes of header
for (uint32_t i = 0; i < payLen; ++i){
pl[i] ^= mask[i % 4];
}
// If masked, apply the mask to the payload
const char *mask = head.data() + headSize - 4; // mask is last 4 bytes of header
for (uint32_t i = 0; i < payLen; ++i){pl[i] ^= mask[i % 4];}
}
if ((head[0] & 0xF)){
//Non-continuation
// Non-continuation
frameType = (head[0] & 0xF);
data.assign(pl.data(), pl.size());
}else{
//Continuation
// Continuation
data.append(pl.data(), pl.size());
}
if (head[0] & 0x80){
//FIN
// FIN
switch (frameType){
case 0x0://Continuation, should not happen
WARN_MSG("Received unknown websocket frame - ignoring");
return false;
break;
case 0x8://Connection close
HIGH_MSG("Websocket close received");
C.close();
return false;
break;
case 0x9://Ping
HIGH_MSG("Websocket ping received");
sendFrame(data, data.size(), 0xA);//send pong
return false;
break;
case 0xA://Pong
HIGH_MSG("Websocket pong received");
return false;
break;
case 0x0: // Continuation, should not happen
WARN_MSG("Received unknown websocket frame - ignoring");
return false;
break;
case 0x8: // Connection close
HIGH_MSG("Websocket close received");
C.close();
return false;
break;
case 0x9: // Ping
HIGH_MSG("Websocket ping received");
sendFrame(data, data.size(), 0xA); // send pong
return false;
break;
case 0xA: // Pong
HIGH_MSG("Websocket pong received");
return false;
break;
}
return true;
}
}
}
void Websocket::sendFrame(const char * data, unsigned int len, unsigned int frameType){
void Websocket::sendFrame(const char *data, unsigned int len, unsigned int frameType){
char header[10];
header[0] = 0x80 + frameType;//FIN + frameType
header[0] = 0x80 + frameType; // FIN + frameType
if (len < 126){
header[1] = len;
C.SendNow(header, 2);
}else{
if (len <= 0xFFFF){
header[1] = 126;
Bit::htobs(header+2, len);
Bit::htobs(header + 2, len);
C.SendNow(header, 4);
}else{
header[1] = 127;
Bit::htobll(header+2, len);
Bit::htobll(header + 2, len);
C.SendNow(header, 10);
}
}
C.SendNow(data, len);
}
void Websocket::sendFrame(const std::string & data){
sendFrame(data.data(), data.size());
}
void Websocket::sendFrame(const std::string &data){sendFrame(data.data(), data.size());}
Websocket::operator bool() const{return C;}
}// namespace HTTP