incremental
diff --git a/src/base64_test.cpp b/src/base64_test.cpp
index 2758dfa..e21655e 100644
--- a/src/base64_test.cpp
+++ b/src/base64_test.cpp
@@ -47,7 +47,7 @@
}
// Tests using pathalogical cases for all escapings
-TEST(Base64, NaugtyStrings) {
+TEST(Base64, NaugtyStringsEncodeDecode) {
std::string base64_string;
std::string decoded_string;
for (auto& str : naughty_strings) {
@@ -56,3 +56,12 @@
EXPECT_EQ(str, decoded_string);
}
}
+
+// Tests using pathalogical cases for all escapings
+TEST(Base64, NaugtyStringsPathological) {
+ std::string base64_string;
+ std::string decoded_string;
+ for (auto& str : naughty_strings) {
+ base64::base64_decode(str, base64_string);
+ }
+}
\ No newline at end of file
diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp
new file mode 100644
index 0000000..f73ee30
--- /dev/null
+++ b/src/getvideo_main.cpp
@@ -0,0 +1,67 @@
+#include <video.h>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+
+namespace AstVideo {
+class VideoPuller {
+ public:
+ VideoPuller() {}
+
+ void initialize() {
+ std::cout << "Opening /dev/video\n";
+ file.open("/dev/video", std::ios::out | std::ios::in | std::ios::binary);
+ if (!file.is_open()) {
+ std::cout << "Failed to open /dev/video\n";
+ }
+ IMAGE_INFO image_info{};
+
+ file.write(reinterpret_cast<char*>(&image_info), sizeof(image_info));
+
+ file.read(reinterpret_cast<char*>(&image_info), sizeof(image_info));
+
+ if (file){
+ std::cout << "Read succeeded\n";
+ }
+
+ auto pt = reinterpret_cast<char*>(&image_info);
+
+ for(int i=0; i<sizeof(image_info); i++){
+ std::cout << std::hex << std::setfill('0') << std::setw(2) << int(*(pt + i)) << " ";
+ }
+
+ std::cout << "\n";
+
+ std::cout << "typedef struct _video_features {\n";
+ std::cout << "short jpg_fmt: " << image_info.parameter.features.jpg_fmt << "\n";
+ std::cout << "short lumin_tbl;" << image_info.parameter.features.lumin_tbl << "\n";
+ std::cout << "short chrom_tbl;" << image_info.parameter.features.chrom_tbl << "\n";
+ std::cout << "short tolerance_noise;" << image_info.parameter.features.tolerance_noise << "\n";
+ std::cout << "int w;" << image_info.parameter.features.w << "\n";
+ std::cout << "int h;" << image_info.parameter.features.h << "\n";
+ //std::cout << "unsigned char *buf;" << image_info.parameter.features.buf << "\n";
+ std::cout << "} FEATURES_TAG;\n";
+
+ std::cout << "typedef struct _image_info {";
+ std::cout << "short do_image_refresh;" << image_info.do_image_refresh << "\n";
+ std::cout << "char qc_valid;" << image_info.qc_valid << "\n";
+ std::cout << "unsigned int len;" << image_info.len << "\n";
+ std::cout << "int crypttype;" << image_info.crypttype << "\n";
+ std::cout << "char cryptkey[16];" << image_info.cryptkey << "\n";
+ std::cout << "union {\n";
+ std::cout << " FEATURES_TAG features;\n";
+ std::cout << " AST_CURSOR_TAG cursor_info;\n";
+ std::cout << "} parameter;\n";
+ std::cout << "} IMAGE_INFO;\n";
+ std::cout << std::endl;
+ }
+ std::fstream file;
+};
+}
+
+int main() {
+ AstVideo::VideoPuller p;
+ p.initialize();
+
+ return 1;
+}
\ No newline at end of file
diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp
index 40ade75..30d12c5 100644
--- a/src/token_authorization_middleware.cpp
+++ b/src/token_authorization_middleware.cpp
@@ -1,9 +1,9 @@
+#include <random>
#include <unordered_map>
-
#include <boost/algorithm/string/predicate.hpp>
#include <token_authorization_middleware.hpp>
-
+#include <crow/logging.h>
#include <base64.hpp>
namespace crow {
@@ -17,16 +17,19 @@
res.code = 401;
res.end();
};
+
+ LOG(DEBUG) << "Got route " << req.url;
+
if (req.url == "/" || boost::starts_with(req.url, "/static/")){
//TODO this is total hackery to allow the login page to work before the user
// is authenticated. Also, it will be quite slow for all pages instead of
// a one time hit for the whitelist entries.
// Ideally, this should be done in the url router handler, with tagged routes
// for the whitelist entries.
+ // Another option would be to whitelist a minimal
return;
}
-
if (req.url == "/login") {
if (req.method != HTTPMethod::POST){
return_unauthorized();
@@ -39,8 +42,10 @@
}
auto username = login_credentials["username"].s();
auto password = login_credentials["password"].s();
-
+
+ // TODO(ed) pull real passwords from PAM
if (username == "dude" && password == "dude"){
+ //TODO(ed) the RNG should be initialized at start, not every time we want a token
std::random_device rand;
random_bytes_engine rbe;
std::string token('a', 20);
@@ -49,7 +54,6 @@
base64::base64_encode(token, encoded_token);
ctx.auth_token = encoded_token;
this->auth_token2 = encoded_token;
-
} else {
return_unauthorized();
return;
@@ -82,6 +86,7 @@
return_unauthorized();
return;
}
+ // else let the request continue unharmed
}
}
diff --git a/src/udpclient.cpp b/src/udpclient.cpp
new file mode 100644
index 0000000..5f04a9a
--- /dev/null
+++ b/src/udpclient.cpp
@@ -0,0 +1,99 @@
+//
+// client.cpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <array>
+#include <boost/array.hpp>
+#include <boost/asio.hpp>
+#include <iostream>
+
+using boost::asio::ip::udp;
+
+int main(int argc, char* argv[]) {
+ try {
+ boost::asio::io_service io_service;
+
+ udp::resolver resolver(io_service);
+ udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
+ udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ udp::socket socket(io_service);
+ socket.open(udp::v4());
+
+ std::string username = "root";
+ std::string password = "two";
+ uint8_t privilege_level = 4;
+ uint8_t seq_number = 1;
+ uint8_t command = 0x38; // AUTH_CAP_CMD
+ // std::array<uint8_t> ChannelAuthCap{0x80 | (0x0f & channel),
+ // privilege_level&0x0f};
+
+ uint8_t srcaddr = 0x81; // 0xC8?
+ uint8_t dstaddr = 0x20;
+
+ uint8_t net_function = 0x06;
+ uint8_t lun = 0;
+
+ uint8_t netfn_lun = static_cast<uint8_t>((net_function << 2) + lun);
+ uint8_t channel_number =
+ 0x0E + 0x80; // E is defined in spec as this channel
+ // 0x80 is requesting IPMI 2.0
+ uint8_t byte1 = static_cast<uint8_t>(channel_number | 0x80);
+ boost::array<uint8_t, 2> payload{byte1, privilege_level};
+
+ int payload_sum = 0;
+ for (auto element : payload) {
+ payload_sum += element;
+ }
+
+ uint8_t chk1 = (1 + ((~(dstaddr + netfn_lun)) & 0xff)) & 0xff;
+ uint8_t chk2 = srcaddr + (seq_number << 2) + command + payload_sum;
+ chk2 = (1 + ((~chk2) & 0xff)) & 0xff;
+
+ uint8_t ptype = 0;
+ uint8_t session_id = 0;
+
+ uint8_t seq_number2 = 0;
+ uint8_t seq_number_lun = seq_number << 2 + lun;
+
+ uint8_t seq2 = 0xff; //????
+ uint8_t rmcp_class = 0x07;
+
+ std::vector<uint8_t> send_buf = {
+ 0x06, 0x00, seq2,
+ rmcp_class, 0x06, ptype,
+ session_id, seq_number2, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x09,
+ 0x00, dstaddr, netfn_lun,
+ chk1, srcaddr, seq_number_lun,
+ command, channel_number, privilege_level,
+ chk2};
+
+ for (auto character : send_buf) {
+ std::cout << std::hex << static_cast<unsigned>(character) << " ";
+ }
+ std::cout << std::endl;
+ socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
+
+ boost::array<unsigned char, 32> recv_buf;
+ udp::endpoint sender_endpoint;
+ size_t len =
+ socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
+
+ for (auto character : recv_buf) {
+ std::cout << std::hex << static_cast<unsigned>(character) << " ";
+ }
+
+ std::cout << std::endl;
+ } catch (std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index c5c3eed..c55bd4d 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -20,6 +20,8 @@
#include "crow/utility.h"
#include "crow/websocket.h"
+#include "app_type.hpp"
+
#include "color_cout_g3_sink.hpp"
#include "token_authorization_middleware.hpp"
#include "webassets.hpp"
@@ -40,7 +42,11 @@
static const std::string rfb_3_7_version_string = "RFB 003.007\n";
static const std::string rfb_3_8_version_string = "RFB 003.008\n";
-enum class RfbAuthScheme : uint8_t { connection_failed = 0, no_authentication = 1, vnc_authentication = 2 };
+enum class RfbAuthScheme : uint8_t {
+ connection_failed = 0,
+ no_authentication = 1,
+ vnc_authentication = 2
+};
struct pixel_format_struct {
boost::endian::big_uint8_t bits_per_pixel;
@@ -163,12 +169,14 @@
serialized[i++] = 0; // Type
serialized[i++] = 0; // Pad byte
boost::endian::big_uint16_t number_of_rectangles;
- std::memcpy(&serialized[i], &number_of_rectangles, sizeof(number_of_rectangles));
+ std::memcpy(&serialized[i], &number_of_rectangles,
+ sizeof(number_of_rectangles));
i += sizeof(number_of_rectangles);
for (const auto& rect : msg.rectangles) {
// copy the first part of the struct
- size_t buffer_size = sizeof(framebuffer_rectangle) - sizeof(std::vector<uint8_t>);
+ size_t buffer_size =
+ sizeof(framebuffer_rectangle) - sizeof(std::vector<uint8_t>);
std::memcpy(&serialized[i], &rect, buffer_size);
i += buffer_size;
@@ -179,7 +187,13 @@
return serialized;
}
-enum class VncState { UNSTARTED, AWAITING_CLIENT_VERSION, AWAITING_CLIENT_AUTH_METHOD, AWAITING_CLIENT_INIT_MESSAGE, MAIN_LOOP };
+enum class VncState {
+ UNSTARTED,
+ AWAITING_CLIENT_VERSION,
+ AWAITING_CLIENT_AUTH_METHOD,
+ AWAITING_CLIENT_INIT_MESSAGE,
+ MAIN_LOOP
+};
class connection_metadata {
public:
@@ -190,15 +204,17 @@
int main(int argc, char** argv) {
auto worker(g3::LogWorker::createLogWorker());
-
- auto handle = worker->addDefaultLogger(argv[0], "/tmp/");
+ std::string logger_name("bmcweb");
+ std::string folder("/tmp/");
+ auto handle = worker->addDefaultLogger(logger_name, folder);
g3::initializeLogging(worker.get());
- auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(), &crow::ColorCoutSink::ReceiveLogMessage);
+ auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(),
+ &crow::ColorCoutSink::ReceiveLogMessage);
std::string ssl_pem_file("server.pem");
ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file);
- crow::App<crow::TokenAuthorizationMiddleware> app;
+ BmcAppType app;
crow::webassets::request_routes(app);
crow::logger::setLogLevel(crow::LogLevel::INFO);
@@ -213,7 +229,8 @@
CROW_ROUTE(app, "/login")
.methods("POST"_method)([&](const crow::request& req) {
- auto auth_token = app.get_context<crow::TokenAuthorizationMiddleware>(req).auth_token;
+ auto auth_token =
+ app.get_context<crow::TokenAuthorizationMiddleware>(req).auth_token;
crow::json::wvalue x;
x["token"] = auth_token;
@@ -262,21 +279,29 @@
meta.vnc_state = VncState::AWAITING_CLIENT_VERSION;
conn.send_binary(rfb_3_8_version_string);
})
- .onclose([&](crow::websocket::connection& conn, const std::string& reason) {
-
- })
- .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) {
+ .onclose(
+ [&](crow::websocket::connection& conn, const std::string& reason) {
+ meta.vnc_state = VncState::UNSTARTED;
+ })
+ .onmessage([&](crow::websocket::connection& conn, const std::string& data,
+ bool is_binary) {
switch (meta.vnc_state) {
case VncState::AWAITING_CLIENT_VERSION: {
- std::cout << "Client sent: " << data;
- if (data == rfb_3_8_version_string || data == rfb_3_7_version_string) {
- std::string auth_types{1, (uint8_t)RfbAuthScheme::no_authentication};
+ LOG(DEBUG) << "Client sent: " << data;
+ if (data == rfb_3_8_version_string ||
+ data == rfb_3_7_version_string) {
+ std::string auth_types{1,
+ (uint8_t)RfbAuthScheme::no_authentication};
conn.send_binary(auth_types);
meta.vnc_state = VncState::AWAITING_CLIENT_AUTH_METHOD;
} else if (data == rfb_3_3_version_string) {
- // TODO(ed)
+ // TODO(ed) Support older protocols
+ meta.vnc_state = VncState::UNSTARTED;
+ conn.close();
} else {
- // TODO(ed)
+ // TODO(ed) Support older protocols
+ meta.vnc_state = VncState::UNSTARTED;
+ conn.close();
}
} break;
case VncState::AWAITING_CLIENT_AUTH_METHOD: {
@@ -305,10 +330,12 @@
server_init_msg.pixel_format.green_shift = 8;
server_init_msg.pixel_format.blue_shift = 0;
server_init_msg.name_length = 0;
- std::cout << "size: " << sizeof(server_init_msg);
- // TODO(ed) this is ugly. Crow should really have a span type interface
+ LOG(DEBUG) << "size: " << sizeof(server_init_msg);
+ // TODO(ed) this is ugly. Crow should really have a span type
+ // interface
// to avoid the copy, but alas, today it does not.
- std::string s(reinterpret_cast<char*>(&server_init_msg), sizeof(server_init_msg));
+ std::string s(reinterpret_cast<char*>(&server_init_msg),
+ sizeof(server_init_msg));
LOG(DEBUG) << "s.size() " << s.size();
conn.send_binary(s);
meta.vnc_state = VncState::MAIN_LOOP;
@@ -316,7 +343,7 @@
case VncState::MAIN_LOOP: {
if (data.size() >= sizeof(client_to_server_message_type)) {
auto type = static_cast<client_to_server_message_type>(data[0]);
- std::cout << "Got type " << (uint32_t)type << "\n";
+ LOG(DEBUG) << "Got type " << (uint32_t)type << "\n";
switch (type) {
case client_to_server_message_type::set_pixel_format: {
} break;
@@ -325,21 +352,29 @@
} break;
case client_to_server_message_type::set_encodings: {
} break;
- case client_to_server_message_type::framebuffer_update_request: {
- // Make sure the buffer is long enough to handle what we're about to do
- if (data.size() >= sizeof(frame_buffer_update_request_message) + sizeof(client_to_server_message_type)) {
- auto msg = reinterpret_cast<const frame_buffer_update_request_message*>(data.data() + sizeof(client_to_server_message_type));
+ case client_to_server_message_type::
+ framebuffer_update_request: {
+ // Make sure the buffer is long enough to handle what we're
+ // about to do
+ if (data.size() >=
+ sizeof(frame_buffer_update_request_message) +
+ sizeof(client_to_server_message_type)) {
+ auto msg = reinterpret_cast<
+ const frame_buffer_update_request_message*>(
+ data.data() + sizeof(client_to_server_message_type));
- std::cout << "framebuffer_update_request_message\n";
- std::cout << " incremental=" << msg->incremental << "\n";
- std::cout << " x=" << msg->x_position;
- std::cout << " y=" << msg->y_position << "\n";
- std::cout << " width=" << msg->width;
- std::cout << " height=" << msg->height << "\n";
+ LOG(DEBUG) << "framebuffer_update_request_message\n";
+ LOG(DEBUG) << " incremental=" << msg->incremental
+ << "\n";
+ LOG(DEBUG) << " x=" << msg->x_position;
+ LOG(DEBUG) << " y=" << msg->y_position << "\n";
+ LOG(DEBUG) << " width=" << msg->width;
+ LOG(DEBUG) << " height=" << msg->height << "\n";
framebuffer_update_message buffer_update_message;
- // If the viewer is requesting a full update, force write of all
+ // If the viewer is requesting a full update, force write of
+ // all
// pixels
framebuffer_rectangle this_rect;
@@ -347,20 +382,29 @@
this_rect.y = msg->y_position;
this_rect.width = msg->width;
this_rect.height = msg->height;
- this_rect.encoding = static_cast<uint8_t>(encoding_type::raw);
+ this_rect.encoding =
+ static_cast<uint8_t>(encoding_type::raw);
- this_rect.data.reserve(this_rect.width * this_rect.height * 4);
+ this_rect.data.reserve(this_rect.width * this_rect.height *
+ 4);
- for (unsigned int x_index = 0; x_index < this_rect.width; x_index++) {
- for (unsigned int y_index = 0; y_index < this_rect.height; y_index++) {
- this_rect.data.push_back(static_cast<uint8_t>(0)); // Blue
- this_rect.data.push_back(static_cast<uint8_t>(0)); // Green
- this_rect.data.push_back(static_cast<uint8_t>(x_index * 0xFF / msg->width)); // RED
- this_rect.data.push_back(static_cast<uint8_t>(0)); // UNUSED
+ for (unsigned int x_index = 0; x_index < this_rect.width;
+ x_index++) {
+ for (unsigned int y_index = 0; y_index < this_rect.height;
+ y_index++) {
+ this_rect.data.push_back(
+ static_cast<uint8_t>(0)); // Blue
+ this_rect.data.push_back(
+ static_cast<uint8_t>(0)); // Green
+ this_rect.data.push_back(static_cast<uint8_t>(
+ x_index * 0xFF / msg->width)); // RED
+ this_rect.data.push_back(
+ static_cast<uint8_t>(0)); // UNUSED
}
}
- buffer_update_message.rectangles.push_back(std::move(this_rect));
+ buffer_update_message.rectangles.push_back(
+ std::move(this_rect));
auto serialized = serialize(buffer_update_message);
conn.send_binary(serialized);
@@ -397,23 +441,38 @@
.onopen([&](crow::websocket::connection& conn) {
})
- .onclose([&](crow::websocket::connection& conn, const std::string& reason) {
+ .onclose(
+ [&](crow::websocket::connection& conn, const std::string& reason) {
- })
- .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) {
+ })
+ .onmessage([&](crow::websocket::connection& conn, const std::string& data,
+ bool is_binary) {
boost::asio::io_service io_service;
- boost::asio::ip::udp::udp::socket socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0));
- boost::asio::ip::udp::resolver resolver(io_service);
- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), "10.243.48.31", "623");
- boost::asio::ip::udp::resolver::iterator iter = resolver.resolve(query);
- socket.send_to(boost::asio::buffer(data), *iter);
+ using boost::asio::ip::udp;
+ udp::resolver resolver(io_service);
+ udp::resolver::query query(udp::v4(), "10.243.48.31", "623");
+ udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ udp::socket socket(io_service);
+ socket.open(udp::v4());
+
+ socket.send_to(boost::asio::buffer(data), receiver_endpoint);
+
+ std::array<char, 255> recv_buf;
+
+ udp::endpoint sender_endpoint;
+ size_t len =
+ socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
+ // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use
+ // std::string::data())
+ std::string str(std::begin(recv_buf), std::end(recv_buf));
+ LOG(DEBUG) << "Got " << str << "back \n";
+ conn.send_binary(str);
+
});
- auto rules = app.get_rules();
- for (auto& rule : rules) {
- LOG(DEBUG) << "Static route: " << rule;
- }
-
- // app.port(18080).ssl(std::move(get_ssl_context(ssl_pem_file))).concurrency(4).run();
- app.port(18080).concurrency(4).run();
+ app.port(18080)
+ //.ssl(std::move(ensuressl::get_ssl_context(ssl_pem_file)))
+ .run();
+ // app.port(18080).run();
}