Quote: "On discord you said you got this worked out. "
Well, I can do the handshake (thanks to nachoz12341), and then I can read a message coming from Tier1 HTML5 or Postman, however, I can't read a message from Tier2 going to Tier1 HTML5 or Postman. Postman says opcode is 0. I've looked inside the packet, the last bit of data looks the same each way, but it only works one way.
Here comes AppGameKit Tier1 HTML5 client part:
// Project: WebSocket HTML5 Client
// Created: 2024-08-26
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "WebSocket HTML5 Client" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
socketID = ConnectSocket("Host IP v4 address goes here",50079,6000)
repeat
print("Connecting...")
print(GetSocketConnected(socketID))
sync()
until not GetSocketConnected(socketID) = 0
while GetSocketConnected(socketID) = -1
print("Timed out...")
sync()
endwhile
do
if GetRawKeyPressed(32)
SendSocketByte(socketID,84)
SendSocketByte(socketID,84)
SendSocketByte(socketID,84)
FlushSocket(socketID)
endif
if GetSocketBytesAvailable(socketID) > 0 then end
Print( ScreenFPS() )
Sync()
loop
function SendString(inputString as string)
stringLength = len(inputString)
endfunction
And here comes AppGameKit Tier2 host part:
// Includes
#include "template.h"
// Namespace
using namespace AGK;
app App;
typedef struct client {
int socket_id;
bool connected = false;
};
std::string encryptDecrypt(char inpString[], int length);
int RetrieveMessageLength(char inputChar);
bool RetrieveMessageFinalStatus(char inputChar);
int RetrieveOpcode(char inputChar);
bool RetrieveMaskBit(char inputChar);
void SetBits(char byte);
char GetByte();
void agklog(std::string s);
void SendHandshake(int socket_id, std::string message);
int socket_listener;
std::vector<client> client_sockets;
char msg[65535];
int bits[64];
int messageLength = 0;
std::string textReceived = "";
int opcode = 0;
bool finalMessage = false;
bool maskBit = false;
int testByte1;
int testByte2;
int testByte3;
void app::Begin(void)
{
agk::SetVirtualResolution(1280, 720);
agk::SetClearColor(151, 170, 204); // light blue
agk::SetSyncRate(60, 0);
agk::SetScissor(0, 0, 0, 0);
agk::SetPrintSize(18);
//Start server
socket_listener = agk::CreateSocketListener("anyip4", 50079);
//Debug string
msg[0] = 'H';
msg[1] = 'i';
msg[2] = '\0';
msg[65534] = '\0';
}
int app::Loop(void)
{
agk::Print(agk::ScreenFPS());
std::string socketString = "Clients connected: " + std::to_string(client_sockets.size());
agk::Print(socketString.c_str());
//Look for new connections
int socket_connection = agk::GetSocketListenerConnection(socket_listener);
while (socket_connection != 0)
{
client c;
c.socket_id = socket_connection;
c.connected = false;
client_sockets.push_back(c); //Add to client list
std::string s = "Added a new socket: " + std::to_string(socket_connection);
agklog(s);
socket_connection = agk::GetSocketListenerConnection(socket_listener);//Look for next client
}
//Get new messages
for (int i = 0; i < client_sockets.size(); i++)
{
int msg_it = 0;
int socket = client_sockets.at(i).socket_id;
bool new_message = false;
while (agk::GetSocketBytesAvailable(socket))
{
msg[msg_it] = (char)agk::GetSocketByte(socket);
msg_it++;
msg[msg_it] = '\0';
new_message = true;
}
if (new_message)
agklog("Received new message");
/*if (agk::GetSocketConnected(socket) == 1)
{
std::string s = "Socket " + std::to_string(i) + " Status: " + std::to_string(agk::GetSocketConnected(socket));
agk::Print(s.c_str());
}*/
if (new_message)
{
if (!client_sockets.at(i).connected)
{
std::string message = msg;
SendHandshake(socket, message);
client_sockets.at(i).connected = true;
}
else
{
finalMessage = RetrieveMessageFinalStatus(msg[0]); //This seems to be false even tough I only send a message containing "Test" from Postman. It should be true.
opcode = RetrieveOpcode(msg[0]);
maskBit = RetrieveMaskBit(msg[1]);
messageLength = RetrieveMessageLength(msg[1]);
if (opcode == 1 || opcode == 2) textReceived = encryptDecrypt(msg, messageLength);
bits[0] = 1; //FIN bit
bits[1] = 0; //RSV1 bit
bits[2] = 0; //RSV2 bit
bits[3] = 0; //RSV3 bit
bits[4] = 0; //Opcode bit 4
bits[5] = 0; //Opcode bit 3
bits[6] = 0; //Opcode bit 2
bits[7] = 1; //Opcode bit 1
testByte1 = GetByte();
agk::SendSocketByte(socket, testByte1);
bits[0] = 1; //Mask bit
bits[1] = 0; //Lenght bit 7
bits[2] = 0; //Lenght bit 6
bits[3] = 0; //Lenght bit 5
bits[4] = 0; //Lenght bit 4
bits[5] = 0; //Lenght bit 3
bits[6] = 0; //Lenght bit 2
bits[7] = 1; //Lenght bit 1
testByte2 = GetByte();
agk::SendSocketByte(socket, testByte2);
bits[0] = 0; //Payload bit 8
bits[1] = 1; //Payload bit 7
bits[2] = 0; //Payload bit 6
bits[3] = 1; //Payload bit 5
bits[4] = 0; //Payload bit 4
bits[5] = 1; //Payload bit 3
bits[6] = 0; //Payload bit 2
bits[7] = 0; //Payload bit 1
testByte3 = GetByte(); //Set to 84 which is the uppercase letter T
agk::SendSocketByte(socket, testByte3);
agk::FlushSocket(socket);
}
}
}
/*DEBUG*/
agk::Print("Test bytes:");
agk::Print(testByte1);
agk::Print(testByte2);
agk::Print(testByte3);
agk::Print("Message bytes:");
agk::Print(msg[0]);
agk::Print(msg[1]);
agk::Print(msg[2]);
agk::Print(msg[3]);
agk::Print(msg[4]);
agk::Print(msg[5]);
agk::Print(msg[6]);
agk::Print(msg[7]);
agk::Print("Bits:");
for (int t = 0; t < 8; ++t)
{
agk::Print(bits[t]);
}
agk::Print(" ");
agk::Print("*Parameters received*");
std::string finalMessageString = "Final message: " + std::to_string(finalMessage);
agk::Print(finalMessageString.c_str());
std::string opcodeString = "Opcode: " + std::to_string(opcode);
agk::Print(opcodeString.c_str());
std::string maskBitString = "Mask bit: " + std::to_string(maskBit);
agk::Print(maskBitString.c_str());
std::string messageLengthtString = "Message length: " + std::to_string(messageLength);
agk::Print(messageLengthtString.c_str());
std::string textReceivedString = "Text received: " + textReceived;
agk::Print(textReceivedString.c_str());
agk::Sync();
return 0; // return 1 to close app
}
void app::End(void)
{
}
void SendHandshake(int socket_id, std::string message)
{
//Get client key
std::string headerKeyString = "Sec-WebSocket-Key: ";
std::string client_key = message.substr(message.find(headerKeyString) + headerKeyString.length(), 24);
//Get protocol
bool protocolBinaryFound = false;
std::string headerProtocolString = "Sec-WebSocket-Protocol: binary";
if (message.find(headerProtocolString) != std::string::npos)
{
protocolBinaryFound = true;
}
//Concatonate and hash new key
std::string server_key = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string new_key = client_key + server_key;
new_key = agk::Sha1(new_key.c_str());
new_key = agk::HexToBase64(new_key.c_str());
std::string handshake = "";
//Send handshake for connection
if (protocolBinaryFound)
{
handshake = "HTTP/1.1 101 Switching Protocols\r\nUpgrade:websocket\r\nConnection:Upgrade\r\nSec-WebSocket-Accept:" + new_key + "\r\n\Sec-WebSocket-Protocol: binary" + "\r\n\r\n";
}
else
{
handshake = "HTTP/1.1 101 Switching Protocols\r\nUpgrade:websocket\r\nConnection:Upgrade\r\nSec-WebSocket-Accept:" + new_key + "\r\n\r\n";
}
const char* handshake_array = handshake.c_str();
for (int i = 0; i < handshake.size() + 1; i++)
agk::SendSocketByte(socket_id, handshake_array[i]);
agk::FlushSocket(socket_id);
agk::Print("SENT HANDSHAKE");
}
void agklog(std::string s)
{
s = s + "\n";
OutputDebugStringA(s.c_str());
}
std::string encryptDecrypt(char inpString[], int length)
{
std::string returnString = "";
int startPos = 0;
if (length <= 125) startPos = 6;
// perform XOR operation of key
// with every character in string
int cycleKey = 2;
for (int i = 6; i < 6 + length; i++)
{
msg[i] = msg[i] ^ msg[cycleKey];
returnString = returnString + msg[i];
++cycleKey;
if (cycleKey == 6) cycleKey = 2;
}
return returnString;
}
void SetBits(char byte)
{
if (byte < 0)
{
bits[0] = 1;
byte = agk::Abs(-128 + agk::Abs(byte));
}
int nominator = 64;
for (int t = 1; t < 8; ++t)
{
bits[t] = 0;
if (byte >= nominator)
{
bits[t] = 1;
byte = byte - nominator;
}
nominator = nominator / 2;
}
}
char GetByte()
{
int nominator = 64;
char value = 0;
for (int t = 1; t < 8; ++t)
{
if (bits[t] == 1)
{
value = value + nominator;
}
nominator = nominator / 2;
}
if (bits[0] == 1)
{
value = -128 + value;
}
return value;
}
int RetrieveMessageLength(char inputChar)
{
inputChar |= 1 << 7; //remove mask bit
//If 125 or less, this is the payload length. If 126 the length is the next two bytes as a 16 bit unsigned integer. If 127 the length is the next 4 bytes as a 64 bit unsigned integer. I am not handling the last two cases, only the first.
return inputChar + 128; //inputChar is signed, move range up to 0-127
}
int RetrieveOpcode(char byte)
{
SetBits(byte);
int nominator = 8;
char value = 0;
for (int t = 4; t < 8; ++t)
{
if (bits[t] == 1)
{
value = value + nominator;
}
nominator = nominator / 2;
}
return value;
}
bool RetrieveMaskBit(char inputChar)
{
return (bool)((inputChar >> 7) & 1);
}
bool RetrieveMessageFinalStatus(char inputChar)
{
return (bool)((inputChar >> 7) & 1);
}
13/0