diff --git a/a8/websocketclient.cc b/a8/websocketclient.cc index 1d04213..ee5d689 100644 --- a/a8/websocketclient.cc +++ b/a8/websocketclient.cc @@ -61,9 +61,13 @@ namespace a8 { }; tcp_client_->on_socketread = - [] (a8::AsioTcpClient* socket, char* buf, unsigned int buf_len) + [this] (a8::AsioTcpClient* socket, char* buf, unsigned int buflen) { - int i = 0; + if (!handshook_) { + buf[buflen] = '\0'; + } else { + + } }; } @@ -116,6 +120,162 @@ namespace a8 } } + void WebSocketClient::ProcessHandShake(char* buf, int& offset, unsigned int buflen) + { + char* pend = strstr(buf + offset, "\r\n\r\n"); + if (!pend) { + return; + } + if (strstr(buf + offset, WEB_SOCKET_KEY) || strstr(buf + offset, WEB_SOCKET_KEY2)) { + ProcessWsHandShake(buf, offset, buflen); + } else { + //ProcessHttpHandShake(buf, offset, buflen); + } + } + + void WebSocketClient::ProcessWsHandShake(char* buf, int& offset, unsigned int buflen) + { + char* pend = strstr(buf + offset, "\r\n\r\n"); + if (!pend) { + return; + } + if (strncmp(buf + offset, "GET ", strlen("GET ")) == 0) { + std::string url; + std::string querystr; + std::string location; + + a8::ParserQueryStr(buf + offset + 4, url, querystr); + } + std::string server_key; + { + char* p1 = strstr(buf + offset, WEB_SOCKET_KEY); + if (!p1) { + p1 = strstr(buf + offset, WEB_SOCKET_KEY2); + } + if (p1) { + p1 += strlen(WEB_SOCKET_KEY); + char* p2 = strstr(p1 , "\r\n"); + if (p2) { + server_key.append(p1, p2-p1); + } + } + } + #if 0 + server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + std::string sha1_data = a8::openssl::Sha1Encode(server_key); + std::string hash_data; + a8::openssl::Base64Encode(sha1_data, hash_data); + + std::string response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + hash_data + "\r\n" + + "\r\n"; + SendBuff(response.data(), response.size()); + handshook_ = true; + #endif + offset += pend - buf - offset + strlen("\r\n\r\n"); + } + + void WebSocketClient::ProcessUserPacket() + { + int offset = 0; + int prev_offset = 0; + do { + prev_offset = offset; + //DecodeUserPacket(decoded_buff_, offset, decoded_bufflen_); + } while (prev_offset < offset && offset < decoded_bufflen_); + + if (offset > 0 && offset < decoded_bufflen_){ + memmove(decoded_buff_, decoded_buff_ + offset, decoded_bufflen_ - offset); + } + decoded_bufflen_ -= offset; + #if 0 + if (decoded_bufflen_ >= max_packet_len_) { + //收到超长包 + Close(); + return; + } + #endif + } + + void WebSocketClient::DecodeFrame(char* buf, int& offset, unsigned int buflen) + { + if (offset + 2 > (int)buflen) { + return; + } + char* real_buf = buf + offset; + unsigned int ava_len = buflen - offset; + unsigned char header = real_buf[0]; + unsigned char mask_payloadlen = real_buf[1]; + + bool is_final_frame = (header & FIN) == FIN; + #if 0 + bool reserved_bits = (header & FIN) == RSV_MASK; + #endif + unsigned char opcode = header & OPCODE_MASK; + #if 0 + bool opcode_is_control = opcode & 0x8; + #endif + + if (opcode == WEBSOCKET_FRAME_CLOSE) { + Close(); + return; + } + if (opcode != BINARY_MODE) { + if (opcode != WEBSOCKET_FRAME_PING) { + Close(); + return; + } + } + if (!is_final_frame) { + Close(); + return; + } + + bool is_masked = (mask_payloadlen & 0x80) == 0x80; + if (!is_masked) { + Close(); + return; + } + + unsigned char payloadlen = mask_payloadlen & 0x7F; + unsigned int framelen = 0; + int mask_offset = 0; + + if (payloadlen < 126) { + framelen = payloadlen; + mask_offset = 2; + } else if (payloadlen == 126 && ava_len >= 4) { + framelen = ntohs( *(u_short*) (real_buf + 2) ); + mask_offset = 4; + } else if (payloadlen == 127 && ava_len >= 8) { + //int32 or int64? + framelen = ntohl( *(u_long*) (real_buf + 2) ); + mask_offset = 8; + } else { + return; + } + unsigned int real_pkg_len = mask_offset + framelen + (is_masked ? 4 : 0); + if (ava_len < real_pkg_len) { + return; + } + + if (is_masked) { + unsigned char *frame_mask = (unsigned char*)(real_buf + mask_offset); + memcpy(&decoded_buff_[decoded_bufflen_], real_buf + mask_offset + 4, framelen); + for (unsigned int i = 0; i < framelen; i++) { + decoded_buff_[decoded_bufflen_ + i] = (decoded_buff_[i] ^ frame_mask[i%4]); + } + } else { + memcpy(&decoded_buff_[decoded_bufflen_], real_buf + mask_offset, framelen); + } + decoded_bufflen_ += framelen; + + ProcessUserPacket(); + offset += real_pkg_len; + } + } #endif diff --git a/a8/websocketclient.h b/a8/websocketclient.h index 20be4cc..6c0c97e 100644 --- a/a8/websocketclient.h +++ b/a8/websocketclient.h @@ -28,6 +28,12 @@ namespace a8 bool Connected(); void SendBuff(const char* buff, unsigned int bufflen); + private: + void ProcessHandShake(char* buf, int& offset, unsigned int buflen); + void ProcessWsHandShake(char* buf, int& offset, unsigned int buflen); + void ProcessUserPacket(); + void DecodeFrame(char* buf, int& offset, unsigned int buflen); + private: std::shared_ptr tcp_client_; char *decoded_buff_ = nullptr;