X Tutup
#include "WebSocket.h" #include "../../utils/Utils.h" #include "../../socket/Socket.h" #ifdef POSIX #include #endif namespace HttpClient { WebSocket::WebSocket(const WebSocket &obj) noexcept : sock(obj.sock) { } WebSocket::WebSocket(Socket::Adapter *adapter) noexcept : sock(adapter) { } std::vector WebSocket::packDataToMessageFrame(const void *data, const size_t size) { std::vector frame; if (0 == size) { return frame; } constexpr size_t header_max_size = 14; frame.reserve(size + header_max_size); frame.resize(header_max_size); frame[0] = 0x81; size_t cur_pos = sizeof(uint8_t) * 2; if (size <= 125) { frame[1] = size; } else if (size <= 65536) { frame[1] = 126; *reinterpret_cast(&frame[2]) = htons(size); cur_pos += sizeof(uint16_t); } else // More { frame[1] = 127; *reinterpret_cast(&frame[2]) = Utils::hton64(size); cur_pos += sizeof(uint64_t); } frame.erase(frame.cbegin() + cur_pos, frame.cend() ); frame.insert(frame.cend(), reinterpret_cast(data), reinterpret_cast(data) + size); return frame; } Socket::Adapter *WebSocket::getSocket() noexcept { return this->sock; } const Socket::Adapter *WebSocket::getSocket() const noexcept { return this->sock; } long WebSocket::nonblock_recv(std::vector &frame, const std::chrono::milliseconds &timeout) const { std::vector buf(4096); const long recv_size = this->sock->nonblock_recv(buf, timeout); if (recv_size <= 0) { return recv_size; } // See @link: http://tools.ietf.org/html/rfc6455#page-28 const uint8_t info_frame = buf[0]; if ( (info_frame & 0x08) == 0x08) // opcode 0x08 — close connection { return -1; } uint8_t info_size = buf[1]; const bool is_mask_set = info_size & uint8_t(1 << 7); info_size &= ~uint8_t(1 << 7); // Unset first bit size_t cur_pos = sizeof(uint8_t) * 2; uint64_t frame_size; if (info_size <= 125) { frame_size = info_size; } else if (info_size == 126) { frame_size = ntohs(*reinterpret_cast(&buf[cur_pos]) ); cur_pos += sizeof(uint16_t); } else // if (info_size == 127) { frame_size = Utils::ntoh64(*reinterpret_cast(&buf[cur_pos]) ); cur_pos += sizeof(uint64_t); } if (frame_size > (buf.size() - cur_pos) ) { return -1; // Close connection } uint32_t mask; if (is_mask_set) { mask = *reinterpret_cast(&buf[cur_pos]); cur_pos += sizeof(uint32_t); } const uint8_t align = (recv_size - cur_pos) % sizeof(uint32_t); frame.reserve(recv_size - cur_pos + align); frame.assign(buf.cbegin() + cur_pos, buf.cbegin() + recv_size); if (is_mask_set) { if (align) { frame.insert(frame.cend(), align, 0); } uint32_t *addr = reinterpret_cast(frame.data() ); for (size_t i = 0; i < frame.size() / sizeof(uint32_t); ++i) { addr[i] ^= mask; } if (align) { frame.erase(frame.cend() - align, frame.cend() ); } } return recv_size - cur_pos; } long WebSocket::nonblock_send(const void *data, const size_t length, const std::chrono::milliseconds &timeout) const { const std::vector frame = WebSocket::packDataToMessageFrame(data, length); if (frame.empty() ) { return 0; } return this->sock->nonblock_send(frame.data(), frame.size(), timeout); } long WebSocket::nonblock_send(const std::string &str, const std::chrono::milliseconds &timeout) const { const std::vector frame = WebSocket::packDataToMessageFrame(str.data(), str.length() ); if (frame.empty() ) { return 0; } return this->sock->nonblock_send(frame.data(), frame.size(), timeout); } void WebSocket::close() noexcept { this->sock->close(); } };
X Tutup