Initial Commit
This commit is contained in:
commit
7764a6ab0b
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
Debug/
|
||||
Release/
|
||||
*.vcxproj
|
||||
*.vcxproj.*
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "GSock-Pro"]
|
||||
path = GSock-Pro
|
||||
url = http://kiritow.com:3000/kiritow/GSock-Pro
|
1
GSock-Pro
Submodule
1
GSock-Pro
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit bd3bd376f6903ca681d8eba15bfbb30f1c6392f7
|
BIN
KChatWSServer.cpp
Normal file
BIN
KChatWSServer.cpp
Normal file
Binary file not shown.
164
base64.hpp
Normal file
164
base64.hpp
Normal file
|
@ -0,0 +1,164 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// base64 encode list
|
||||
// 0-25 A-Z
|
||||
// 26-51 a-z
|
||||
// 52-61 0-9
|
||||
inline char _base64_encode_char(unsigned int c, char c62, char c63)
|
||||
{
|
||||
static const char* _base64_encode_list =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789";
|
||||
if (c < 62) return _base64_encode_list[c];
|
||||
else if (c == 62) return c62;
|
||||
else return c63;
|
||||
}
|
||||
|
||||
// base64 decode list
|
||||
// A-Z 0-25
|
||||
// a-z 26-51
|
||||
// 0-9 52-61
|
||||
inline unsigned int _base64_decode_char(char c, char c62, char c63)
|
||||
{
|
||||
if (c >= 'A'&&c <= 'Z') return c - 'A';
|
||||
else if (c >= 'a'&&c <= 'z') return c - 'a' + 26;
|
||||
else if (c >= '0'&&c <= '9') return c - '0' + 52;
|
||||
else if (c == c62) return 62;
|
||||
else return 63;
|
||||
}
|
||||
|
||||
std::string base64_encode(const unsigned char* data, int len, char c62, char c63, char cfill)
|
||||
{
|
||||
std::string ans;
|
||||
int nGroup = len / 3;
|
||||
int nLeft = len % 3;
|
||||
|
||||
for (int i = 0; i < nGroup; i++)
|
||||
{
|
||||
unsigned int xa = data[i * 3];
|
||||
unsigned int xb = data[i * 3 + 1];
|
||||
unsigned int xc = data[i * 3 + 2];
|
||||
|
||||
unsigned int ya = (xa & 0xfc) >> 2; // 11111100,...
|
||||
unsigned int yb = ((xa & 0x3) << 4) | ((xb & 0xf0) >> 4); // 00000011,11110000,....
|
||||
unsigned int yc = ((xb & 0xf) << 2) | ((xc & 0xc0) >> 6); // ...,00001111,11000000
|
||||
unsigned int yd = xc & 0x3f; // ...,00111111
|
||||
|
||||
ans.push_back(_base64_encode_char(ya, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yb, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yc, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yd, c62, c63));
|
||||
}
|
||||
|
||||
switch (nLeft)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
unsigned int xa = data[nGroup * 3];
|
||||
|
||||
unsigned int ya = (xa & 0xfc) >> 2;
|
||||
unsigned int yb = (xa & 0x3) << 4;
|
||||
|
||||
ans.push_back(_base64_encode_char(ya, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yb, c62, c63));
|
||||
ans.push_back(cfill);
|
||||
ans.push_back(cfill);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
unsigned int xa = data[nGroup * 3];
|
||||
unsigned int xb = data[nGroup * 3 + 1];
|
||||
|
||||
unsigned int ya = (xa & 0xfc) >> 2;
|
||||
unsigned int yb = ((xa & 0x3) << 4) | ((xb & 0xf0) >> 4);
|
||||
unsigned int yc = (xb & 0xf) << 2;
|
||||
|
||||
ans.push_back(_base64_encode_char(ya, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yb, c62, c63));
|
||||
ans.push_back(_base64_encode_char(yc, c62, c63));
|
||||
ans.push_back(cfill);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> base64_decode(const std::string& str, char c62, char c63, char cfill)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
int nGroup = str.size() / 4;
|
||||
for (int i = 0; i < nGroup; i++)
|
||||
{
|
||||
unsigned int ya = _base64_decode_char(str[i * 4], c62, c63);
|
||||
unsigned int yb = _base64_decode_char(str[i * 4 + 1], c62, c63);
|
||||
unsigned int xa = (ya << 2) | (yb >> 4); // 6 + 2
|
||||
data.push_back(xa);
|
||||
|
||||
if (str[i * 4 + 3] != cfill)
|
||||
{
|
||||
unsigned int yc = _base64_decode_char(str[i * 4 + 2], c62, c63);
|
||||
unsigned int yd = _base64_decode_char(str[i * 4 + 3], c62, c63);
|
||||
|
||||
unsigned int xb = ((yb & 0xf) << 4) | (yc >> 2); // 4 + 4
|
||||
unsigned int xc = ((yc & 0x3) << 6) | yd; // 2 + 6
|
||||
|
||||
data.push_back(xb);
|
||||
data.push_back(xc);
|
||||
}
|
||||
else // (str[i * 4 + 3] == cfill)
|
||||
{
|
||||
if (str[i * 4 + 2] == cfill)
|
||||
{
|
||||
unsigned int xb = (yb & 0xf) << 4; // 4 + 4
|
||||
|
||||
data.push_back(xb);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int yc = _base64_decode_char(str[i * 4 + 2], c62, c63);
|
||||
unsigned int xb = ((yb & 0xf) << 4) | (yc >> 2); // 4 + 4
|
||||
unsigned int xc = (yc & 0x3) << 6; // 2 + 6
|
||||
|
||||
data.push_back(xb);
|
||||
data.push_back(xc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::string base64_encode_std(const unsigned char* data, int len)
|
||||
{
|
||||
return base64_encode(data, len, '+', '/', '=');
|
||||
}
|
||||
|
||||
std::string base64_encode_std(const std::string& data)
|
||||
{
|
||||
return base64_encode_std((const unsigned char*)data.data(), data.size());
|
||||
}
|
||||
|
||||
std::string base64_encode_url(const unsigned char* data, int len)
|
||||
{
|
||||
return base64_encode(data, len, '-', '_', '=');
|
||||
}
|
||||
|
||||
std::string base64_encode_url(const std::string& data)
|
||||
{
|
||||
return base64_encode_std((const unsigned char*)data.data(), data.size());
|
||||
}
|
||||
|
||||
std::vector<unsigned char> base64_decode_std(const std::string& str)
|
||||
{
|
||||
return base64_decode(str, '+', '/', '=');
|
||||
}
|
||||
|
||||
std::vector<unsigned char> base64_decode_url(const std::string& str)
|
||||
{
|
||||
return base64_decode(str, '-', '_', '=');
|
||||
}
|
311
sha1.cpp
Normal file
311
sha1.cpp
Normal file
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
sha1.cpp - source code of
|
||||
============
|
||||
SHA-1 in C++
|
||||
============
|
||||
100% Public Domain.
|
||||
Original C Code
|
||||
-- Steve Reid <steve@edmweb.com>
|
||||
Small changes to fit into bglibs
|
||||
-- Bruce Guenter <bruce@untroubled.org>
|
||||
Translation to simpler C++ Code
|
||||
-- Volker Diels-Grabsch <v@njh.eu>
|
||||
Safety fixes
|
||||
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
|
||||
static const size_t BLOCK_BYTES = BLOCK_INTS * 4;
|
||||
|
||||
|
||||
static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
digest[0] = 0x67452301;
|
||||
digest[1] = 0xefcdab89;
|
||||
digest[2] = 0x98badcfe;
|
||||
digest[3] = 0x10325476;
|
||||
digest[4] = 0xc3d2e1f0;
|
||||
|
||||
/* Reset counters */
|
||||
buffer = "";
|
||||
transforms = 0;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t rol(const uint32_t value, const size_t bits)
|
||||
{
|
||||
return (value << bits) | (value >> (32 - bits));
|
||||
}
|
||||
|
||||
|
||||
static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i)
|
||||
{
|
||||
return rol(block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i], 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations used in SHA1
|
||||
*/
|
||||
|
||||
static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
{
|
||||
z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (((w | x)&y) | (w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
|
||||
static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms)
|
||||
{
|
||||
/* Copy digest[] to working vars */
|
||||
uint32_t a = digest[0];
|
||||
uint32_t b = digest[1];
|
||||
uint32_t c = digest[2];
|
||||
uint32_t d = digest[3];
|
||||
uint32_t e = digest[4];
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(block, a, b, c, d, e, 0);
|
||||
R0(block, e, a, b, c, d, 1);
|
||||
R0(block, d, e, a, b, c, 2);
|
||||
R0(block, c, d, e, a, b, 3);
|
||||
R0(block, b, c, d, e, a, 4);
|
||||
R0(block, a, b, c, d, e, 5);
|
||||
R0(block, e, a, b, c, d, 6);
|
||||
R0(block, d, e, a, b, c, 7);
|
||||
R0(block, c, d, e, a, b, 8);
|
||||
R0(block, b, c, d, e, a, 9);
|
||||
R0(block, a, b, c, d, e, 10);
|
||||
R0(block, e, a, b, c, d, 11);
|
||||
R0(block, d, e, a, b, c, 12);
|
||||
R0(block, c, d, e, a, b, 13);
|
||||
R0(block, b, c, d, e, a, 14);
|
||||
R0(block, a, b, c, d, e, 15);
|
||||
R1(block, e, a, b, c, d, 0);
|
||||
R1(block, d, e, a, b, c, 1);
|
||||
R1(block, c, d, e, a, b, 2);
|
||||
R1(block, b, c, d, e, a, 3);
|
||||
R2(block, a, b, c, d, e, 4);
|
||||
R2(block, e, a, b, c, d, 5);
|
||||
R2(block, d, e, a, b, c, 6);
|
||||
R2(block, c, d, e, a, b, 7);
|
||||
R2(block, b, c, d, e, a, 8);
|
||||
R2(block, a, b, c, d, e, 9);
|
||||
R2(block, e, a, b, c, d, 10);
|
||||
R2(block, d, e, a, b, c, 11);
|
||||
R2(block, c, d, e, a, b, 12);
|
||||
R2(block, b, c, d, e, a, 13);
|
||||
R2(block, a, b, c, d, e, 14);
|
||||
R2(block, e, a, b, c, d, 15);
|
||||
R2(block, d, e, a, b, c, 0);
|
||||
R2(block, c, d, e, a, b, 1);
|
||||
R2(block, b, c, d, e, a, 2);
|
||||
R2(block, a, b, c, d, e, 3);
|
||||
R2(block, e, a, b, c, d, 4);
|
||||
R2(block, d, e, a, b, c, 5);
|
||||
R2(block, c, d, e, a, b, 6);
|
||||
R2(block, b, c, d, e, a, 7);
|
||||
R3(block, a, b, c, d, e, 8);
|
||||
R3(block, e, a, b, c, d, 9);
|
||||
R3(block, d, e, a, b, c, 10);
|
||||
R3(block, c, d, e, a, b, 11);
|
||||
R3(block, b, c, d, e, a, 12);
|
||||
R3(block, a, b, c, d, e, 13);
|
||||
R3(block, e, a, b, c, d, 14);
|
||||
R3(block, d, e, a, b, c, 15);
|
||||
R3(block, c, d, e, a, b, 0);
|
||||
R3(block, b, c, d, e, a, 1);
|
||||
R3(block, a, b, c, d, e, 2);
|
||||
R3(block, e, a, b, c, d, 3);
|
||||
R3(block, d, e, a, b, c, 4);
|
||||
R3(block, c, d, e, a, b, 5);
|
||||
R3(block, b, c, d, e, a, 6);
|
||||
R3(block, a, b, c, d, e, 7);
|
||||
R3(block, e, a, b, c, d, 8);
|
||||
R3(block, d, e, a, b, c, 9);
|
||||
R3(block, c, d, e, a, b, 10);
|
||||
R3(block, b, c, d, e, a, 11);
|
||||
R4(block, a, b, c, d, e, 12);
|
||||
R4(block, e, a, b, c, d, 13);
|
||||
R4(block, d, e, a, b, c, 14);
|
||||
R4(block, c, d, e, a, b, 15);
|
||||
R4(block, b, c, d, e, a, 0);
|
||||
R4(block, a, b, c, d, e, 1);
|
||||
R4(block, e, a, b, c, d, 2);
|
||||
R4(block, d, e, a, b, c, 3);
|
||||
R4(block, c, d, e, a, b, 4);
|
||||
R4(block, b, c, d, e, a, 5);
|
||||
R4(block, a, b, c, d, e, 6);
|
||||
R4(block, e, a, b, c, d, 7);
|
||||
R4(block, d, e, a, b, c, 8);
|
||||
R4(block, c, d, e, a, b, 9);
|
||||
R4(block, b, c, d, e, a, 10);
|
||||
R4(block, a, b, c, d, e, 11);
|
||||
R4(block, e, a, b, c, d, 12);
|
||||
R4(block, d, e, a, b, c, 13);
|
||||
R4(block, c, d, e, a, b, 14);
|
||||
R4(block, b, c, d, e, a, 15);
|
||||
|
||||
/* Add the working vars back into digest[] */
|
||||
digest[0] += a;
|
||||
digest[1] += b;
|
||||
digest[2] += c;
|
||||
digest[3] += d;
|
||||
digest[4] += e;
|
||||
|
||||
/* Count the number of transformations */
|
||||
transforms++;
|
||||
}
|
||||
|
||||
|
||||
static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
|
||||
{
|
||||
/* Convert the std::string (byte buffer) to a uint32_t array (MSB) */
|
||||
for (size_t i = 0; i < BLOCK_INTS; i++)
|
||||
{
|
||||
block[i] = (buffer[4 * i + 3] & 0xff)
|
||||
| (buffer[4 * i + 2] & 0xff) << 8
|
||||
| (buffer[4 * i + 1] & 0xff) << 16
|
||||
| (buffer[4 * i + 0] & 0xff) << 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SHA1::SHA1()
|
||||
{
|
||||
reset(digest, buffer, transforms);
|
||||
}
|
||||
|
||||
|
||||
void SHA1::update(const std::string &s)
|
||||
{
|
||||
std::istringstream is(s);
|
||||
update(is);
|
||||
}
|
||||
|
||||
|
||||
void SHA1::update(std::istream &is)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
char sbuf[BLOCK_BYTES];
|
||||
is.read(sbuf, BLOCK_BYTES - buffer.size());
|
||||
buffer.append(sbuf, (std::size_t)is.gcount());
|
||||
if (buffer.size() != BLOCK_BYTES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint32_t block[BLOCK_INTS];
|
||||
buffer_to_block(buffer, block);
|
||||
transform(digest, block, transforms);
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add padding and return the message digest.
|
||||
*/
|
||||
|
||||
int SHA1::final(uint32_t* arr)
|
||||
{
|
||||
/* Total number of hashed bits */
|
||||
uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
|
||||
|
||||
/* Padding */
|
||||
buffer += (char)0x80;
|
||||
size_t orig_size = buffer.size();
|
||||
while (buffer.size() < BLOCK_BYTES)
|
||||
{
|
||||
buffer += (char)0x00;
|
||||
}
|
||||
|
||||
uint32_t block[BLOCK_INTS];
|
||||
buffer_to_block(buffer, block);
|
||||
|
||||
if (orig_size > BLOCK_BYTES - 8)
|
||||
{
|
||||
transform(digest, block, transforms);
|
||||
for (size_t i = 0; i < BLOCK_INTS - 2; i++)
|
||||
{
|
||||
block[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append total_bits, split this uint64_t into two uint32_t */
|
||||
block[BLOCK_INTS - 1] = (uint32_t)total_bits;
|
||||
block[BLOCK_INTS - 2] = (uint32_t)(total_bits >> 32);
|
||||
transform(digest, block, transforms);
|
||||
|
||||
memcpy(arr, digest, sizeof(digest));
|
||||
|
||||
/* Reset for next run */
|
||||
reset(digest, buffer, transforms);
|
||||
|
||||
return sizeof(digest) / sizeof(digest[0]);
|
||||
}
|
||||
|
||||
std::string SHA1::final()
|
||||
{
|
||||
uint32_t arr[5];
|
||||
final(arr);
|
||||
/* Hex std::string */
|
||||
std::ostringstream result;
|
||||
for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
|
||||
{
|
||||
result << std::hex << std::setfill('0') << std::setw(8);
|
||||
result << arr[i];
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
std::string SHA1::from_file(const std::string &filename)
|
||||
{
|
||||
std::ifstream stream(filename.c_str(), std::ios::binary);
|
||||
SHA1 checksum;
|
||||
checksum.update(stream);
|
||||
return checksum.final();
|
||||
}
|
43
sha1.h
Normal file
43
sha1.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
sha1.hpp - header of
|
||||
============
|
||||
SHA-1 in C++
|
||||
============
|
||||
100% Public Domain.
|
||||
Original C Code
|
||||
-- Steve Reid <steve@edmweb.com>
|
||||
Small changes to fit into bglibs
|
||||
-- Bruce Guenter <bruce@untroubled.org>
|
||||
Translation to simpler C++ Code
|
||||
-- Volker Diels-Grabsch <v@njh.eu>
|
||||
Safety fixes
|
||||
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HPP
|
||||
#define SHA1_HPP
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
SHA1();
|
||||
void update(const std::string &s);
|
||||
void update(std::istream &is);
|
||||
std::string final();
|
||||
int final(uint32_t* arr);
|
||||
static std::string from_file(const std::string &filename);
|
||||
|
||||
private:
|
||||
uint32_t digest[5];
|
||||
std::string buffer;
|
||||
uint64_t transforms;
|
||||
};
|
||||
|
||||
|
||||
#endif /* SHA1_HPP */
|
245
websocket.cpp
Normal file
245
websocket.cpp
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include "websocket.h"
|
||||
#include "gsock_helper.h"
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include "base64.hpp"
|
||||
#include "sha1.h"
|
||||
#include <WinSock2.h>
|
||||
using namespace std;
|
||||
|
||||
int HandleKey(sock& s, const string& key)
|
||||
{
|
||||
string server_key = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
SHA1 sha;
|
||||
sha.update(server_key);
|
||||
uint32_t arr[5];
|
||||
sha.final(arr);
|
||||
for (int i = 0; i < 5; i++) arr[i] = htonl(arr[i]); // 重要
|
||||
string response_key = base64_encode_std((const unsigned char*)arr, sizeof(arr));
|
||||
sock_helper sp(s);
|
||||
string response_header = string("HTTP/1.1 101 Switching Protocols\r\n") +
|
||||
"Connection: upgrade\r\n" +
|
||||
"Sec-WebSocket-Accept: " + response_key + "\r\n" +
|
||||
"Upgrade: websocket\r\n\r\n";
|
||||
if (sp.sendall(response_header) <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Handshake(sock& s)
|
||||
{
|
||||
sock_helper sp(s);
|
||||
vector<string> lines;
|
||||
while (true)
|
||||
{
|
||||
string str;
|
||||
int ret = sp.recvline(str);
|
||||
if (ret <= 0) return -1;
|
||||
if (str.empty()) break;
|
||||
lines.push_back(str);
|
||||
// cout << str << endl;
|
||||
}
|
||||
|
||||
for (auto& str : lines)
|
||||
{
|
||||
string target("Sec-WebSocket-Key");
|
||||
if (str.find(target) != string::npos)
|
||||
{
|
||||
string key = str.substr(str.find(target) + 19, 24);
|
||||
if (HandleKey(s, key) == 0)
|
||||
{
|
||||
// Handshake OK
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handshake Failed: Key is not ok
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not websocket protocol
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ReadFrame(sock& s, WSFrame& f)
|
||||
{
|
||||
sock_helper sp(s);
|
||||
unsigned char c;
|
||||
if (s.recv(&c, 1) <= 0) return -1;
|
||||
f.fin = c & 0x80; // 1000 0000
|
||||
f.rsv1 = c & 0x40; // 0100 0000
|
||||
f.rsv2 = c & 0x20; // 0010 0000
|
||||
f.rsv3 = c & 0x10; // 0001 0000
|
||||
f.opcode = c & 0xF; // 0000 1111
|
||||
|
||||
if (s.recv(&c, 1) <= 0) return -1;
|
||||
f.ismask = c & 0x80; // 1000 0000
|
||||
int payload_head = c & 0x7F; // 0111 1111
|
||||
if (payload_head < 126)
|
||||
{
|
||||
f.len = payload_head;
|
||||
}
|
||||
else if (payload_head == 126)
|
||||
{
|
||||
uint16_t x;
|
||||
if (sp.recvall(&x, sizeof(x)) <= 0) return -1;
|
||||
f.len = ntohs(x);
|
||||
}
|
||||
else if (payload_head == 127)
|
||||
{
|
||||
uint64_t x;
|
||||
if (sp.recvall(&x, sizeof(x)) <= 0) return -1;
|
||||
f.len = ntohll(x);
|
||||
}
|
||||
if (f.ismask)
|
||||
{
|
||||
if (sp.recvall(f.mask, sizeof(f.mask)) <= 0) return -1;
|
||||
}
|
||||
unique_ptr<char[]> xp(new char[f.len]);
|
||||
if (xp.get() == nullptr) return -2;
|
||||
memset(xp.get(), 0, f.len);
|
||||
if (sp.recvall(xp.get(), f.len) <= 0) return -1;
|
||||
if (f.ismask)
|
||||
{
|
||||
// 处理掩码问题
|
||||
for (unsigned long long i = 0; i < f.len; i++)
|
||||
{
|
||||
xp[i] ^= f.mask[i % 4];
|
||||
}
|
||||
}
|
||||
f.data = string(xp.get(), f.len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SendFrame(sock& s, const WSFrame& f)
|
||||
{
|
||||
sock_helper sp(s);
|
||||
unsigned char c = 0;
|
||||
if (f.fin) c = 0x80; // 1000 0000
|
||||
if (f.rsv1) c |= 0x40; // 0100 0000
|
||||
if (f.rsv2) c |= 0x20; // 0010 0000
|
||||
if (f.rsv3) c |= 0x10; // 0001 0000
|
||||
c |= (f.opcode & 0xF); // 0000 1111
|
||||
if (s.send(&c, 1) <= 0) return -1;
|
||||
|
||||
if (f.ismask) c = 0x80; // 1000 0000
|
||||
else c = 0;
|
||||
|
||||
if (f.len < 126)
|
||||
{
|
||||
c |= (f.len & 0x7F);
|
||||
if (s.send(&c, 1) <= 0) return -1;
|
||||
}
|
||||
else if (f.len < (2 << 16))
|
||||
{
|
||||
c |= 126;
|
||||
if (s.send(&c, 1) <= 0) return -1;
|
||||
uint16_t len = f.len;
|
||||
if (sp.sendall(&len, sizeof(len)) <= 0) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
c |= 127;
|
||||
if (s.send(&c, 1) <= 0) return -1;
|
||||
uint64_t len = f.len;
|
||||
if (sp.sendall(&len, sizeof(len)) <= 0) return -1;
|
||||
}
|
||||
if (f.ismask)
|
||||
{
|
||||
if (sp.sendall(&(f.mask), sizeof(f.mask)) <= 0) return -1;
|
||||
vector<char> vec(f.data.begin(), f.data.end());
|
||||
for (uint64_t i = 0; i < f.len; i++)
|
||||
{
|
||||
vec[i] ^= f.mask[i % 4];
|
||||
}
|
||||
if (sp.sendall(vec.data(), vec.size()) <= 0) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp.sendall(f.data) <= 0) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SendPong(sock& s, const WSFrame& ping)
|
||||
{
|
||||
cout << "Sending pong to " << (&s) << endl;
|
||||
|
||||
WSFrame f;
|
||||
f.fin = true;
|
||||
f.rsv1 = false;
|
||||
f.rsv2 = false;
|
||||
f.rsv3 = false;
|
||||
f.ismask = false;
|
||||
f.len = ping.len;
|
||||
f.data = ping.data;
|
||||
f.opcode = 0xA;
|
||||
|
||||
return SendFrame(s, f);
|
||||
}
|
||||
|
||||
int ReadMsg(sock& s, string& out_data)
|
||||
{
|
||||
string data;
|
||||
WSFrame f;
|
||||
int pack_cnt = 0;
|
||||
while (true)
|
||||
{
|
||||
int ret = ReadFrame(s, f);
|
||||
if (ret < 0) return -1;
|
||||
if (f.opcode == 0x9) // ping包则回复一个pong包
|
||||
{
|
||||
cout << "Received ping from " << (&s) << endl;
|
||||
if (SendPong(s, f) < 0) return -2;
|
||||
continue;
|
||||
}
|
||||
else if (f.opcode == 0xA) // pong包则什么都不做
|
||||
{
|
||||
cout << "Received pong from " << (&s) << endl;
|
||||
continue;
|
||||
}
|
||||
else if (f.opcode == 0x8) // 连接主动关闭
|
||||
{
|
||||
cout << "Websocket is closing " << (&s) << endl;
|
||||
return 0;
|
||||
}
|
||||
pack_cnt++;
|
||||
data.append(f.data);
|
||||
if (f.fin) break;
|
||||
}
|
||||
out_data = data;
|
||||
return pack_cnt;
|
||||
}
|
||||
|
||||
int SendMsg(sock& s, const string& data, bool is_text)
|
||||
{
|
||||
WSFrame f;
|
||||
f.fin = true;
|
||||
f.rsv1 = false;
|
||||
f.rsv2 = false;
|
||||
f.rsv3 = false;
|
||||
f.ismask = false;
|
||||
f.len = data.size();
|
||||
f.data = data;
|
||||
f.opcode = is_text ? 0x1 : 0x2;
|
||||
|
||||
if (SendFrame(s, f) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
40
websocket.h
Normal file
40
websocket.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "gsock.h"
|
||||
|
||||
int HandleKey(sock& s, const std::string& key);
|
||||
int Handshake(sock& s);
|
||||
|
||||
struct WSFrame
|
||||
{
|
||||
// 1 bit
|
||||
bool fin;
|
||||
// 1 bit
|
||||
bool rsv1, rsv2, rsv3;
|
||||
|
||||
// 0x0 附加数据帧
|
||||
// 0x1 文本数据帧
|
||||
// 0x2 二进制数据帧
|
||||
// 0x3~7 保留
|
||||
// 0x8 连接关闭
|
||||
// 0x9 ping
|
||||
// 0xA pong
|
||||
// 0xB~F 保留
|
||||
// 4 bit
|
||||
int opcode;
|
||||
|
||||
// 1 bit
|
||||
bool ismask;
|
||||
unsigned long long len;
|
||||
// 4 byte
|
||||
char mask[4];
|
||||
|
||||
// data是未经过编码处理的数据(如果源数据是带掩码的则已经经过解掩码处理)
|
||||
std::string data;
|
||||
};
|
||||
|
||||
int ReadFrame(sock& s, WSFrame& f);
|
||||
int SendFrame(sock& s, const WSFrame& f);
|
||||
int SendPong(sock& s, const WSFrame& ping);
|
||||
int ReadMsg(sock& s, std::string& out_data);
|
||||
int SendMsg(sock& s, const std::string& data, bool is_text = true);
|
Reference in New Issue
Block a user