Start hooking up various modules
This commit is contained in:
@@ -18,7 +18,8 @@ HEADERS += \
|
||||
src/Loop.h \
|
||||
src/App.h \
|
||||
src/HttpSocket.h \
|
||||
src/HttpParser.h
|
||||
src/HttpParser.h \
|
||||
src/libwshandshake.hpp
|
||||
|
||||
INCLUDEPATH += uSockets/src src
|
||||
#QMAKE_CXXFLAGS += -fsanitize=address
|
||||
|
||||
@@ -62,9 +62,39 @@ int main(int argc, char **argv) {
|
||||
uWS::App app;
|
||||
#endif
|
||||
|
||||
// todo: add timeouts and socket shutdown!
|
||||
struct UserData {
|
||||
|
||||
auto serve = [](auto *s, auto *req, auto *args) {
|
||||
};
|
||||
|
||||
// serve a chat page with pub/sub and index.html and get (should be the main app of use)
|
||||
// basically take the old web chat page and upgrade it
|
||||
|
||||
uWS::App a; // or uWS::SSLApp(options) for SSL
|
||||
|
||||
a/*.onGet("/", [](auto *s, auto *req, auto *args) {
|
||||
std::cout << "URL: /" << std::endl;
|
||||
std::cout << "user-agent: " << req->getHeader("user-agent") << std::endl;
|
||||
|
||||
std::cout << "upgrade: " << req->getHeader("upgrade") << std::endl;
|
||||
|
||||
|
||||
})*/.onWebSocket<UserData>("/", [](auto *ws, auto *req, auto *args) {
|
||||
|
||||
std::cout << "WebSocket connected to /wsApi" << std::endl;
|
||||
|
||||
}).onMessage([](auto *ws, auto message/*, auto opCode*/) {
|
||||
|
||||
std::cout << "WebSocket data: " << message << std::endl;
|
||||
|
||||
//ws->send(message, opCode);
|
||||
|
||||
}).onClose([](/*auto *ws, int code, auto message*/) {
|
||||
|
||||
std::cout << "WebSocket disconnected from /wsApi" << std::endl;
|
||||
|
||||
}).listen("localhost", 3000, 0);
|
||||
|
||||
/*auto serve = [](auto *s, auto *req, auto *args) {
|
||||
|
||||
//std::cout << "URL: " << req->getUrl() << std::endl;
|
||||
|
||||
@@ -82,7 +112,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/*writeHeader("Content-type", "text/html; charset=utf-8")->*/s->write([file](int offset) {
|
||||
s->write([file](int offset) {
|
||||
return std::string_view(file.data() + offset, file.size() - offset);
|
||||
}, file.size());
|
||||
|
||||
@@ -112,7 +142,7 @@ int main(int argc, char **argv) {
|
||||
std::cout << "Connections: " << ++connections << std::endl;
|
||||
}).onHttpDisconnection([](auto *s) {
|
||||
std::cout << "Connections: " << --connections << std::endl;
|
||||
}).listen(nullptr, 3000, 0);
|
||||
}).listen(nullptr, 3000, 0);*/
|
||||
|
||||
uWS::run();
|
||||
// loop.run();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Loop.h"
|
||||
#include "HttpSocket.h"
|
||||
#include "HttpRouter.h"
|
||||
#include "libwshandshake.hpp"
|
||||
|
||||
namespace uWS {
|
||||
|
||||
@@ -25,9 +26,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
typedef typename std::conditional<SSL, us_ssl_socket, us_socket>::type SOCKET_TYPE;
|
||||
typedef typename std::conditional<SSL, us_ssl_socket_context, us_socket_context>::type SOCKET_CONTEXT_TYPE;
|
||||
typedef typename HttpSocket<SSL>::Data HTTP_SOCKET_DATA_TYPE;
|
||||
|
||||
// todo_ rename to HttpContextData
|
||||
struct Data {
|
||||
Data() {
|
||||
|
||||
@@ -51,96 +54,116 @@ protected:
|
||||
std::function<void(HttpSocket<SSL> *, HttpRequest *)> onHttpRequest;
|
||||
} *data;
|
||||
|
||||
struct WebSocketServerContextData {
|
||||
|
||||
WebSocketServerContextData() {
|
||||
|
||||
}
|
||||
|
||||
std::function<void(HttpSocket<SSL> *, std::string_view)> onMessage;
|
||||
|
||||
} *webSocketServerContextData;
|
||||
|
||||
// server protocols
|
||||
SOCKET_CONTEXT_TYPE *httpServerContext;
|
||||
SOCKET_CONTEXT_TYPE *webSocketServerContext;
|
||||
|
||||
// a us_socket_context can be constructed from another us_socket_context and will then act purely as a behavior (shared SSL_CTX)
|
||||
// only socket contexts that come from construction from the start can be listened or connected to
|
||||
// client protocols (todo?)
|
||||
|
||||
// us_create_derived_socket_context(us_socket_context)
|
||||
void initWebSocketContexts(us_loop *loop) {
|
||||
new (webSocketServerContextData = (WebSocketServerContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(webSocketServerContext)) WebSocketServerContextData();
|
||||
|
||||
// client protocols
|
||||
static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(webSocketServerContext, [](auto *s, char *data, int length) {
|
||||
WebSocketServerContextData *webSocketServerContextData = (WebSocketServerContextData *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
void init(us_loop *loop) {
|
||||
new (data = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(httpServerContext)) Data();
|
||||
// this is set via the setter?
|
||||
webSocketServerContextData->onMessage((HttpSocket<SSL> *) s, std::string_view(data, length));
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(httpServerContext, [](auto *s, int is_client) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
void initHttpContexts(us_loop *loop) {
|
||||
new (data = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(httpServerContext)) Data();
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_open, us_socket_context_on_open)(httpServerContext, [](auto *s, int is_client) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
|
||||
new (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s)) HTTP_SOCKET_DATA_TYPE;
|
||||
|
||||
if (appData->onHttpConnection) {
|
||||
appData->onHttpConnection((HttpSocket<SSL> *) s);
|
||||
}
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(httpServerContext, [](auto *s) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
((HTTP_SOCKET_DATA_TYPE *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s))->~HTTP_SOCKET_DATA_TYPE();
|
||||
|
||||
if (appData->onHttpDisconnection) {
|
||||
appData->onHttpDisconnection((HttpSocket<SSL> *) s);
|
||||
}
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(httpServerContext, [](auto *s, char *data, int length) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
// warning: should NOT reset timer on any data, ONLY reset data on full HTTP requests!
|
||||
// warning: if we are in shutdown state, resetting the timer is a security issue!
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
|
||||
// onHttpRequest should probably be hard-coded to HttpRouter
|
||||
((HttpSocket<SSL> *) s)->onData(data, length, appData->onHttpRequest);
|
||||
|
||||
// compared to routing directly
|
||||
//typename Data::UserData user = {(HttpSocket<SSL> *) s, nullptr};
|
||||
//appData->r.route("GET", 3, "/", 1, &user);
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(httpServerContext, [](auto *s) {
|
||||
|
||||
// what if the client
|
||||
|
||||
// I think it's fair to never mind this one -> if we keep writing data after shutting down then that's an issue for us
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
|
||||
((HttpSocket<SSL> *) s)->onWritable();
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_end, us_socket_context_on_end)(httpServerContext, [](auto *s) {
|
||||
std::cout << "Socket was half-closed!" << std::endl;
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(httpServerContext, [](auto *s) {
|
||||
|
||||
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)(s)) {
|
||||
std::cout << "Forcefully closing socket since shutdown was not answered in time" << std::endl;
|
||||
static_dispatch(us_ssl_socket_close, us_socket_close)(s);
|
||||
} else {
|
||||
std::cout << "Shutting down socket now" << std::endl;
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
static_dispatch(us_ssl_socket_shutdown, us_socket_shutdown)(s);
|
||||
}
|
||||
|
||||
new (static_dispatch(us_ssl_socket_ext, us_socket_ext)(s)) HTTP_SOCKET_DATA_TYPE;
|
||||
return s;
|
||||
|
||||
if (appData->onHttpConnection) {
|
||||
appData->onHttpConnection((HttpSocket<SSL> *) s);
|
||||
}
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_close, us_socket_context_on_close)(httpServerContext, [](auto *s) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
((HTTP_SOCKET_DATA_TYPE *) static_dispatch(us_ssl_socket_ext, us_socket_ext)(s))->~HTTP_SOCKET_DATA_TYPE();
|
||||
|
||||
if (appData->onHttpDisconnection) {
|
||||
appData->onHttpDisconnection((HttpSocket<SSL> *) s);
|
||||
}
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_data, us_socket_context_on_data)(httpServerContext, [](auto *s, char *data, int length) {
|
||||
Data *appData = (Data *) static_dispatch(us_ssl_socket_context_ext, us_socket_context_ext)(static_dispatch(us_ssl_socket_get_context, us_socket_get_context)(s));
|
||||
|
||||
// warning: should NOT reset timer on any data, ONLY reset data on full HTTP requests!
|
||||
// warning: if we are in shutdown state, resetting the timer is a security issue!
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
|
||||
// onHttpRequest should probably be hard-coded to HttpRouter
|
||||
((HttpSocket<SSL> *) s)->onData(data, length, appData->onHttpRequest);
|
||||
|
||||
// compared to routing directly
|
||||
//typename Data::UserData user = {(HttpSocket<SSL> *) s, nullptr};
|
||||
//appData->r.route("GET", 3, "/", 1, &user);
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_writable, us_socket_context_on_writable)(httpServerContext, [](auto *s) {
|
||||
|
||||
// what if the client
|
||||
|
||||
// I think it's fair to never mind this one -> if we keep writing data after shutting down then that's an issue for us
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
|
||||
((HttpSocket<SSL> *) s)->onWritable();
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_end, us_socket_context_on_end)(httpServerContext, [](auto *s) {
|
||||
std::cout << "Socket was half-closed!" << std::endl;
|
||||
|
||||
return s;
|
||||
});
|
||||
|
||||
static_dispatch(us_ssl_socket_context_on_timeout, us_socket_context_on_timeout)(httpServerContext, [](auto *s) {
|
||||
|
||||
if (static_dispatch(us_ssl_socket_is_shut_down, us_socket_is_shut_down)(s)) {
|
||||
std::cout << "Forcefully closing socket since shutdown was not answered in time" << std::endl;
|
||||
static_dispatch(us_ssl_socket_close, us_socket_close)(s);
|
||||
} else {
|
||||
std::cout << "Shutting down socket now" << std::endl;
|
||||
static_dispatch(us_ssl_socket_timeout, us_socket_timeout)(s, HTTP_IDLE_TIMEOUT_S);
|
||||
static_dispatch(us_ssl_socket_shutdown, us_socket_shutdown)(s);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -178,8 +201,49 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
// for client and server
|
||||
AppBase &onWebSocket(std::string pattern, std::function<void()> handler) {
|
||||
// for client and server? fuck no!
|
||||
template <class UserData>
|
||||
AppBase &onWebSocket(std::string pattern, std::function<void(HttpSocket<SSL> *, HttpRequest *, std::vector<std::string_view> *)> handler) {
|
||||
|
||||
// todo: GET should probably be get since the parser only leaves lower case
|
||||
data->r.add("GET", pattern.c_str(), [this, handler](typename Data::UserData *user, auto *args) {
|
||||
|
||||
std::string_view secWebSocketKey = user->httpRequest->getHeader("sec-websocket-key");
|
||||
if (secWebSocketKey.length()) {
|
||||
|
||||
// note: OpenSSL can be used here to speed this up somewhat
|
||||
char secWebSocketAccept[29] = {};
|
||||
WebSocketHandshake::generate(secWebSocketKey.data(), secWebSocketAccept);
|
||||
|
||||
user->httpSocket->writeStatus("101 Switching Protocols")
|
||||
->writeHeader("Upgrade", "websocket")
|
||||
->writeHeader("Connection", "Upgrade")
|
||||
->writeHeader("Sec-WebSocket-Accept", secWebSocketAccept)
|
||||
->end("");
|
||||
|
||||
// todo: transform the socket into a websocket and hand it over
|
||||
static_dispatch(us_ssl_socket_context_adopt_socket, us_socket_context_adopt_socket)(webSocketServerContext, (SOCKET_TYPE *) user->httpSocket, 0);
|
||||
|
||||
handler(user->httpSocket, user->httpRequest, args);
|
||||
} else {
|
||||
// note: this calls the http close handler inline
|
||||
user->httpSocket->close();
|
||||
}
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
AppBase &onMessage(std::function<void(HttpSocket<SSL> *, std::string_view)> handler) {
|
||||
|
||||
// actually we dynamically create a new server websocket context when we call onWebSocket!
|
||||
webSocketServerContextData->onMessage = handler;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
AppBase &onClose(std::function<void()>) {
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -192,7 +256,10 @@ class App : public AppBase<false> {
|
||||
public:
|
||||
App() {
|
||||
httpServerContext = us_create_socket_context(defaultLoop.loop, sizeof(Data));
|
||||
init(defaultLoop.loop);
|
||||
initHttpContexts(defaultLoop.loop);
|
||||
|
||||
webSocketServerContext = us_create_socket_context(defaultLoop.loop, sizeof(Data)); // this should not have Data! WebSocketData!
|
||||
initWebSocketContexts(defaultLoop.loop);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -225,7 +292,10 @@ class SSLApp : public AppBase<true> {
|
||||
public:
|
||||
SSLApp(SSLOptions &sslOptions) {
|
||||
httpServerContext = us_create_ssl_socket_context(defaultLoop.loop, sizeof(Data), sslOptions.options);
|
||||
init(defaultLoop.loop);
|
||||
initHttpContexts(defaultLoop.loop);
|
||||
|
||||
webSocketServerContext = us_create_ssl_socket_context(defaultLoop.loop, sizeof(Data), sslOptions.options); // this should not have Data! WebSocketData!
|
||||
initWebSocketContexts(defaultLoop.loop);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -174,6 +174,10 @@ struct HttpSocket {
|
||||
httpData->inStream = stream;
|
||||
}
|
||||
|
||||
void close() {
|
||||
static_dispatch(us_ssl_socket_close, us_socket_close)((SOCKET_TYPE *) this);
|
||||
}
|
||||
|
||||
HttpSocket() = delete;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2016 Alex Hultman and contributors
|
||||
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgement in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
#ifndef LIBWSHANDSHAKE_H
|
||||
#define LIBWSHANDSHAKE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
class WebSocketHandshake {
|
||||
template <int N, typename T>
|
||||
struct static_for {
|
||||
void operator()(uint32_t *a, uint32_t *b) {
|
||||
static_for<N - 1, T>()(a, b);
|
||||
T::template f<N - 1>(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct static_for<0, T> {
|
||||
void operator()(uint32_t *a, uint32_t *hash) {}
|
||||
};
|
||||
|
||||
template <int state>
|
||||
struct Sha1Loop {
|
||||
static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));}
|
||||
static inline uint32_t blk(uint32_t b[16], size_t i) {
|
||||
return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1);
|
||||
}
|
||||
|
||||
template <int i>
|
||||
static inline void f(uint32_t *a, uint32_t *b) {
|
||||
switch (state) {
|
||||
case 1:
|
||||
a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5);
|
||||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
|
||||
break;
|
||||
case 2:
|
||||
b[i] = blk(b, i);
|
||||
a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5);
|
||||
a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30);
|
||||
break;
|
||||
case 3:
|
||||
b[(i + 4) % 16] = blk(b, (i + 4) % 16);
|
||||
a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5);
|
||||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
|
||||
break;
|
||||
case 4:
|
||||
b[(i + 8) % 16] = blk(b, (i + 8) % 16);
|
||||
a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5);
|
||||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
|
||||
break;
|
||||
case 5:
|
||||
b[(i + 12) % 16] = blk(b, (i + 12) % 16);
|
||||
a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5);
|
||||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
|
||||
break;
|
||||
case 6:
|
||||
b[i] += a[4 - i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static inline void sha1(uint32_t hash[5], uint32_t b[16]) {
|
||||
uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]};
|
||||
static_for<16, Sha1Loop<1>>()(a, b);
|
||||
static_for<4, Sha1Loop<2>>()(a, b);
|
||||
static_for<20, Sha1Loop<3>>()(a, b);
|
||||
static_for<20, Sha1Loop<4>>()(a, b);
|
||||
static_for<20, Sha1Loop<5>>()(a, b);
|
||||
static_for<5, Sha1Loop<6>>()(a, hash);
|
||||
}
|
||||
|
||||
static inline void base64(unsigned char *src, char *dst) {
|
||||
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
for (int i = 0; i < 18; i += 3) {
|
||||
*dst++ = b64[(src[i] >> 2) & 63];
|
||||
*dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)];
|
||||
*dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)];
|
||||
*dst++ = b64[src[i + 2] & 63];
|
||||
}
|
||||
*dst++ = b64[(src[18] >> 2) & 63];
|
||||
*dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)];
|
||||
*dst++ = b64[((src[19] & 15) << 2)];
|
||||
*dst++ = '=';
|
||||
}
|
||||
|
||||
public:
|
||||
static inline void generate(const char input[24], char output[28]) {
|
||||
uint32_t b_output[5] = {
|
||||
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
|
||||
};
|
||||
uint32_t b_input[16] = {
|
||||
0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39,
|
||||
0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000
|
||||
};
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24;
|
||||
}
|
||||
sha1(b_output, b_input);
|
||||
uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480};
|
||||
sha1(b_output, last_b);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
uint32_t tmp = b_output[i];
|
||||
char *bytes = (char *) &b_output[i];
|
||||
bytes[3] = tmp & 0xff;
|
||||
bytes[2] = (tmp >> 8) & 0xff;
|
||||
bytes[1] = (tmp >> 16) & 0xff;
|
||||
bytes[0] = (tmp >> 24) & 0xff;
|
||||
}
|
||||
base64((unsigned char *) b_output, output);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LIBWSHANDSHAKE_H
|
||||
Reference in New Issue
Block a user