websocket.C 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * websocket.C
  3. *
  4. * Created on: Jun 1, 2013
  5. * Author: xaxaxa
  6. */
  7. #include "include/websocket.H"
  8. #include "include/page.H"
  9. #include <cryptopp/cryptlib.h>
  10. #include <cryptopp/sha.h>
  11. #include <cryptopp/filters.h>
  12. #include <cryptopp/base64.h>
  13. using namespace CryptoPP;
  14. using namespace CP;
  15. using namespace std;
  16. namespace cppsp
  17. {
  18. static uint64_t htonll(uint64_t value) {
  19. // The answer is 42
  20. static const int32_t num = 42;
  21. // Check the endianness
  22. if (*reinterpret_cast<const char*>(&num) == num) {
  23. const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
  24. const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));
  25. return (static_cast<uint64_t>(low_part) << 32) | high_part;
  26. } else {
  27. return value;
  28. }
  29. }
  30. //len must be known in advance; you can not pass a subString of the returned buffer to ws_endWriteFrame()
  31. String ws_beginWriteFrame(FrameWriter& fw, int len) {
  32. int hdrlen = sizeof(WebSocketParser::ws_header1);
  33. if (len > 125 && len <= 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended16);
  34. if (len > 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended64);
  35. String buf = fw.beginInsert(hdrlen + len);
  36. return buf.subString(hdrlen, len);
  37. }
  38. void ws_endWriteFrame(FrameWriter& fw, String buf, int opcode) {
  39. int hdrlen = sizeof(WebSocketParser::ws_header1);
  40. if (buf.length() > 125 && buf.length() <= 0xFFFF) hdrlen +=
  41. sizeof(WebSocketParser::ws_header_extended16);
  42. if (buf.length() > 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended64);
  43. WebSocketParser::ws_header1* h1 = ((WebSocketParser::ws_header1*) (buf.data() - hdrlen));
  44. memset(h1, 0, sizeof(*h1));
  45. h1->fin = true;
  46. h1->mask = false;
  47. h1->opcode = opcode;
  48. if (buf.length() > 125 && buf.length() <= 0xFFFF) {
  49. h1->payload_len = 126;
  50. WebSocketParser::ws_header_extended16* h2 = (WebSocketParser::ws_header_extended16*) (h1
  51. + 1);
  52. h2->payload_len = htons((uint16_t) buf.length());
  53. } else if (buf.length() > 0xFFFF) {
  54. h1->payload_len = 127;
  55. WebSocketParser::ws_header_extended64* h2 = (WebSocketParser::ws_header_extended64*) (h1
  56. + 1);
  57. h2->payload_len = htonll((uint64_t) buf.length());
  58. } else {
  59. h1->payload_len = (char) buf.length();
  60. }
  61. fw.endInsert(hdrlen + buf.length());
  62. }
  63. void ws_init(Page& p, CP::Callback cb) {
  64. p.response->statusCode = 101;
  65. p.response->statusName = "Switching Protocols";
  66. p.response->headers["Connection"] = "Upgrade";
  67. p.response->headers["Upgrade"] = "WebSocket";
  68. //response->headers["Sec-WebSocket-Protocol"]="chat";
  69. String s = concat(*p.sp, p.request->headers["Sec-WebSocket-Key"],
  70. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  71. SHA1 sha1;
  72. byte tmp[sha1.DigestSize()];
  73. sha1.CalculateDigest(tmp, (const byte*) s.data(), s.length());
  74. string encoded;
  75. StringSource src(tmp, sizeof(tmp), true, new Base64Encoder(new StringSink(encoded), false));
  76. //printf("Sec-WebSocket-Accept: %s\n",encoded.c_str());
  77. p.response->headers["Sec-WebSocket-Accept"] = p.sp->addString(encoded);
  78. p.response->serializeHeaders(p.response->output);
  79. p.response->output.flush();
  80. p.response->outputStream->write(p.response->buffer, cb);
  81. }
  82. bool ws_iswebsocket(const Request& req) {
  83. return (ci_compare(req.headers["Connection"], "Upgrade") == 0
  84. && ci_compare(req.headers["Upgrade"], "websocket") == 0);
  85. }
  86. }