|
- #include "stdafx.h"
- #include <stdint.h>
- #include "WebSocket.h"
-
- #include "utility/SHA1.h"
- #include "utility/Base64.h"
- //#include "Logger.h"
-
- namespace zl {
- namespace net {
- namespace ws {
-
- uint16_t ntoh16(uint16_t x) {
- return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
- }
- uint16_t hton16(uint16_t x) {
- return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
- }
- uint64_t ntoh64(uint64_t x) {
- return (x >> 56) |
- ((x << 40) & 0x00ff000000000000LL) |
- ((x << 24) & 0x0000ff0000000000LL) |
- ((x << 8) & 0x000000ff00000000LL) |
- ((x >> 8) & 0x00000000ff000000LL) |
- ((x >> 24) & 0x0000000000ff0000LL) |
- ((x >> 40) & 0x000000000000ff00LL) |
- (x << 56);
- }
- uint64_t hton64(uint64_t x) {
- return (x >> 56) |
- ((x << 40) & 0x00ff000000000000LL) |
- ((x << 24) & 0x0000ff0000000000LL) |
- ((x << 8) & 0x000000ff00000000LL) |
- ((x >> 8) & 0x00000000ff000000LL) |
- ((x >> 24) & 0x0000000000ff0000LL) |
- ((x >> 40) & 0x000000000000ff00LL) |
- (x << 56);
- }
-
- std::string makeHandshakeResponse(const char* seckey, std::string protocol) {
- std::string answer("");
- answer += "HTTP/1.1 101 Switching Protocols\r\n";
- answer += "Upgrade: WebSocket\r\n";
- answer += "Connection: Upgrade\r\n";
- //answer += "Sec-WebSocket-Version: 13\r\n";
- answer += "Sec-WebSocket-Protocol:" + protocol + "\r\n";
- if (seckey) {
- std::string key(seckey);
- key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- char shakey[20] = { 0 };
- zl::util::SHA1 sha1;
- sha1.update(key);
- sha1.final(shakey);
- //LOG_WARN("get SHA1 : %s, %s", key.c_str(), shakey);
- key = zl::util::base64Encode(shakey, 20);
- //LOG_WARN("get base64 : %s", key.c_str());
- answer += ("Sec-WebSocket-Accept: " + key + "\r\n");
- }
- answer += "\r\n";
- return answer;
- }
-
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-------+-+-------------+-------------------------------+
- |F|R|R|R| opcode|M| Payload len | Extended payload length |
- |I|S|S|S| (4) |A| (7) | (16/64) |
- |N|V|V|V| |S| | (if payload len==126/127) |
- | |1|2|3| |K| | |
- +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
- | Extended payload length continued, if payload len == 127 |
- + - - - - - - - - - - - - - - - +-------------------------------+
- | |Masking-key, if MASK set to 1 |
- +-------------------------------+-------------------------------+
- | Masking-key (continued) | Payload Data |
- +-------------------------------- - - - - - - - - - - - - - - - +
- : Payload Data continued ... :
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
- | Payload Data continued ... |
- +---------------------------------------------------------------+
- opcode:
- * %x0 denotes a continuation frame
- * %x1 denotes a text frame
- * %x2 denotes a binary frame
- * %x3-7 are reserved for further non-control frames
- * %x8 denotes a connection close
- * %x9 denotes a ping
- * %xA denotes a pong
- * %xB-F are reserved for further control frames
- Payload length: 7 bits, 7+16 bits, or 7+64 bits
- Masking-key: 0 or 4 bytes
- */
- WsFrameType decodeFrame(const char* inbuf, int inlength, char* outbuf, int* outlen, int* frameSize) {
- if (inlength < 3) return WS_INCOMPLETE_FRAME;
-
- const unsigned char* inp = (const unsigned char*)(inbuf);
-
- unsigned char msg_opcode = inp[0] & 0x0F;
- unsigned char msg_fin = (inp[0] >> 7) & 0x01;
- unsigned char msg_masked = (inp[1] >> 7) & 0x01;
-
- if (msg_fin == 0) {
- return WS_ERROR_FRAME;
- }
-
- int payload_length = 0;
- int pos = 2;
- int length_field = inp[1] & (~0x80);
- unsigned int mask = 0;
-
- if (length_field <= PAYLOAD_SIZE_BASIC) {
- payload_length = length_field;
- }
- else if (length_field == 126) { //msglen is 16bit!
- uint16_t tmp16 = 0;
- memcpy(&tmp16, inp + 2, 2);
- payload_length = ntoh16(tmp16);
- //payload_length = inp[2] + (inp[3] << 8);
- pos += 2;
- }
- else if (length_field == 127) { //msglen is 64bit!
- uint64_t tmp64 = 0;
- memcpy(&tmp64, inp + 2, 8);
- payload_length = ntoh64(tmp64);
- //payload_length = inp[2] + (inp[3] << 8);
- pos += 8;
- }
- int frameLength = payload_length + pos;
- if (msg_masked == true) {
- frameLength += 4;
- }
- if (inlength < frameLength) {
- //printf("warn: inlengh<frameLength\n");
- return WS_INCOMPLETE_FRAME;
- }
- else if (inlength>frameLength) {
- //printf("warn: inlengh>frameLength:%d>%d\n", inlength, frameLength);
- }
- //else if (payload_length >(int)outbuf->size())
- //{
- // outbuf->resize(payload_length);
- //}
-
- if (msg_masked&&payload_length>0) {
- mask = *((unsigned int*)(inp + pos));
- pos += 4;
- memcpy(outbuf, (void*)(inp + pos), payload_length);
- // unmask data:
- char* c = outbuf;
- for (int i = 0; i < payload_length; i++) {
- c[i] = c[i] ^ ((unsigned char*)(&mask))[i % 4];
- }
- }
-
- *frameSize = frameLength;
- *outlen = payload_length;
- // (*outbuf)[payload_length] = 0;
-
- if (msg_opcode == 0x0) return (msg_fin) ? WS_TEXT_FRAME : WS_INCOMPLETE_TEXT_FRAME; // continuation frame ?
- if (msg_opcode == 0x1) return (msg_fin) ? WS_TEXT_FRAME : WS_INCOMPLETE_TEXT_FRAME;
- if (msg_opcode == 0x2) return (msg_fin) ? WS_BINARY_FRAME : WS_INCOMPLETE_BINARY_FRAME;
- if (msg_opcode == 0x8) return WS_CLOSE_FRAME;
- if (msg_opcode == 0x9) return WS_PING_FRAME;
- if (msg_opcode == 0xA) return WS_PONG_FRAME;
-
- return WS_ERROR_FRAME;
- }
- int encodeFrame(WsFrameType frame_type, const char* msg, int msg_length, char* outbuf, int bufsize) {
- //std::cout << "makeFrame : " << frame_type << "\t" << msg << "\t" << msg_length << "\n";
- int pos = 0;
- int size = msg_length;
- outbuf[pos++] = (unsigned char)frame_type; // text frame
- if (size <= PAYLOAD_SIZE_BASIC) { // 125
- outbuf[pos++] = size;
- }
- else if (size <= PAYLOAD_SIZE_EXTENDED) { // 65535
- outbuf[pos++] = 126; //16 bit length
- outbuf[pos++] = (size >> 8) & 0xFF; // rightmost first
- outbuf[pos++] = size & 0xFF;
- }
- else { // >2^16-1
- outbuf[pos++] = 127; //64 bit length
-
- // write 8 bytes length (significant first)
- // since msg_length is int it can be no longer than 4 bytes = 2^32-1
- // padd zeroes for the first 4 bytes
- for (int i = 3; i >= 0; i--) {
- outbuf[pos++] = 0;
- }
- // write the actual 32bit msg_length in the next 4 bytes
- for (int i = 3; i >= 0; i--) {
- outbuf[pos++] = ((size >> 8 * i) & 0xFF);
- }
- }
- //fix by xujialong Êý¾Ý³¤¶È¼ì²é
- if (size > 0 && (size + pos)<bufsize) {
- memcpy((void*)(outbuf + pos), msg, size);
- }
- return (size + pos);
- }
-
- } // namespace zl { namespace net { namespace ws {
- }
- }
|