Large updates to webserver
Do not merge yet
Change-Id: I38c56844c1b0e3e8e5493c2705e62e6db7ee2102
diff --git a/include/aspeed/JTABLES.H b/include/aspeed/JTABLES.H
index bff39e3..8f2d9f3 100644
--- a/include/aspeed/JTABLES.H
+++ b/include/aspeed/JTABLES.H
@@ -18,15 +18,15 @@
// Standard Huffman tables (cf. JPEG standard section K.3) */
-static const unsigned char std_dc_luminance_nrcodes[17] = {0, 0, 1, 5, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned char std_dc_luminance_nrcodes[17] = {
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
static const unsigned char std_dc_luminance_values[12] = {0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 10, 11};
+ 6, 7, 8, 9, 10, 11};
static const unsigned char std_dc_chrominance_nrcodes[17] = {
0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const unsigned char std_dc_chrominance_values[12] = {0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 10, 11};
+ 6, 7, 8, 9, 10, 11};
static const unsigned char std_ac_luminance_nrcodes[17] = {
0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
@@ -284,7 +284,7 @@
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185};
-typedef struct {
+struct Huffman_table {
unsigned char Length[17]; // k =1-16 ; L[k] indicates the number of Huffman
// codes of length k
unsigned short int minor_code[17]; // indicates the value of the smallest
@@ -296,4 +296,4 @@
// Low nibble = size (in bits) of the coefficient which will be taken from the
// data stream
unsigned char Len[65536];
-} Huffman_table;
+};
diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
index b5144ab..d2a482a 100644
--- a/include/ast_jpeg_decoder.hpp
+++ b/include/ast_jpeg_decoder.hpp
@@ -1,41 +1,23 @@
#pragma once
-#include <string.h>
+#include <ast_video_types.hpp>
#include <array>
#include <aspeed/JTABLES.H>
-#include <ast_video_types.hpp>
#include <cassert>
#include <cstdint>
+#include <cstring>
#include <iostream>
#include <vector>
-/*
-template <class T, class Compare>
-constexpr const T &clamp(const T &v, const T &lo, const T &hi, Compare comp) {
- return assert(!comp(hi, lo)), comp(v, lo) ? lo : comp(hi, v) ? hi : v;
-}
-
-template <class T>
-constexpr const T &clamp(const T &v, const T &lo, const T &hi) {
- return clamp(v, lo, hi, std::less<>());
-}
-*/
namespace AstVideo {
struct COLOR_CACHE {
- COLOR_CACHE() {
- for (int i = 0; i < 4; i++) {
- Index[i] = i;
- }
- Color[0] = 0x008080;
- Color[1] = 0xFF8080;
- Color[2] = 0x808080;
- Color[3] = 0xC08080;
- }
+ COLOR_CACHE()
+ : Color{0x008080, 0xFF8080, 0x808080, 0xC08080}, Index{0, 1, 2, 3} {}
unsigned long Color[4];
unsigned char Index[4];
- unsigned char BitMapBits;
+ unsigned char BitMapBits{};
};
struct RGB {
@@ -94,7 +76,7 @@
float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
uint8_t j, row, col;
- uint8_t tempQT[64];
+ std::array<uint8_t, 64> tempQT{};
// Load quantization coefficients from JPG file, scale them for DCT and
// reorder
@@ -125,17 +107,20 @@
std_luminance_qt = Tbl_100Y;
break;
}
- set_quant_table(std_luminance_qt, (uint8_t)SCALEFACTOR, tempQT);
+ set_quant_table(std_luminance_qt, static_cast<uint8_t>(SCALEFACTOR),
+ tempQT);
- for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]];
+ for (j = 0; j <= 63; j++) {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
j = 0;
- for (row = 0; row <= 7; row++)
+ for (row = 0; row <= 7; row++) {
for (col = 0; col <= 7; col++) {
- quant_table[j] =
- (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) *
- 65536);
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
j++;
}
+ }
byte_pos += 64;
}
@@ -143,7 +128,7 @@
float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
uint8_t j, row, col;
- uint8_t tempQT[64];
+ std::array<uint8_t, 64> tempQT{};
// Load quantization coefficients from JPG file, scale them for DCT and
// reorder from zig-zag order
@@ -202,7 +187,8 @@
break;
}
}
- set_quant_table(std_chrominance_qt, (uint8_t)SCALEFACTORUV, tempQT);
+ set_quant_table(std_chrominance_qt, static_cast<uint8_t>(SCALEFACTORUV),
+ tempQT);
for (j = 0; j <= 63; j++) {
quant_table[j] = tempQT[zigzag[j]];
@@ -210,9 +196,8 @@
j = 0;
for (row = 0; row <= 7; row++) {
for (col = 0; col <= 7; col++) {
- quant_table[j] =
- (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) *
- 65536);
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
j++;
}
}
@@ -223,7 +208,7 @@
float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
uint8_t j, row, col;
- uint8_t tempQT[64];
+ std::array<uint8_t, 64> tempQT{};
// Load quantization coefficients from JPG file, scale them for DCT and
// reorder
@@ -255,17 +240,20 @@
break;
}
// Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- set_quant_table(std_luminance_qt, (uint8_t)ADVANCESCALEFACTOR, tempQT);
+ set_quant_table(std_luminance_qt, static_cast<uint8_t>(ADVANCESCALEFACTOR),
+ tempQT);
- for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]];
+ for (j = 0; j <= 63; j++) {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
j = 0;
- for (row = 0; row <= 7; row++)
+ for (row = 0; row <= 7; row++) {
for (col = 0; col <= 7; col++) {
- quant_table[j] =
- (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) *
- 65536);
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
j++;
}
+ }
byte_pos += 64;
}
@@ -274,7 +262,7 @@
float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
uint8_t j, row, col;
- uint8_t tempQT[64];
+ std::array<uint8_t, 64> tempQT{};
// Load quantization coefficients from JPG file, scale them for DCT and
// reorder
@@ -335,17 +323,20 @@
}
}
// Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- set_quant_table(std_chrominance_qt, (uint8_t)ADVANCESCALEFACTORUV, tempQT);
+ set_quant_table(std_chrominance_qt,
+ static_cast<uint8_t>(ADVANCESCALEFACTORUV), tempQT);
- for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]];
+ for (j = 0; j <= 63; j++) {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
j = 0;
- for (row = 0; row <= 7; row++)
+ for (row = 0; row <= 7; row++) {
for (col = 0; col <= 7; col++) {
- quant_table[j] =
- (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) *
- 65536);
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
j++;
}
+ }
byte_pos += 64;
}
@@ -387,7 +378,8 @@
inptr[DCTSIZE * 4] | inptr[DCTSIZE * 5] | inptr[DCTSIZE * 6] |
inptr[DCTSIZE * 7]) == 0) {
/* AC terms all zero */
- dcval = (int)((inptr[DCTSIZE * 0] * quantptr[DCTSIZE * 0]) >> 16);
+ dcval = static_cast<int>((inptr[DCTSIZE * 0] * quantptr[DCTSIZE * 0]) >>
+ 16);
wsptr[DCTSIZE * 0] = dcval;
wsptr[DCTSIZE * 1] = dcval;
@@ -445,14 +437,14 @@
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
- wsptr[DCTSIZE * 0] = (int)(tmp0 + tmp7);
- wsptr[DCTSIZE * 7] = (int)(tmp0 - tmp7);
- wsptr[DCTSIZE * 1] = (int)(tmp1 + tmp6);
- wsptr[DCTSIZE * 6] = (int)(tmp1 - tmp6);
- wsptr[DCTSIZE * 2] = (int)(tmp2 + tmp5);
- wsptr[DCTSIZE * 5] = (int)(tmp2 - tmp5);
- wsptr[DCTSIZE * 4] = (int)(tmp3 + tmp4);
- wsptr[DCTSIZE * 3] = (int)(tmp3 - tmp4);
+ wsptr[DCTSIZE * 0] = (tmp0 + tmp7);
+ wsptr[DCTSIZE * 7] = (tmp0 - tmp7);
+ wsptr[DCTSIZE * 1] = (tmp1 + tmp6);
+ wsptr[DCTSIZE * 6] = (tmp1 - tmp6);
+ wsptr[DCTSIZE * 2] = (tmp2 + tmp5);
+ wsptr[DCTSIZE * 5] = (tmp2 - tmp5);
+ wsptr[DCTSIZE * 4] = (tmp3 + tmp4);
+ wsptr[DCTSIZE * 3] = (tmp3 - tmp4);
inptr++; /* advance pointers to next column */
quantptr++;
@@ -465,7 +457,7 @@
//#define RANGE_MASK 1023; //2 bits wider than legal samples
#define PASS1_BITS 0
-#define IDESCALE(x, n) ((int)((x) >> n))
+#define IDESCALE(x, n) ((int)((x) >> (n)))
wsptr = workspace;
for (ctr = 0; ctr < DCTSIZE; ctr++) {
@@ -480,10 +472,10 @@
*/
/* Even part */
- tmp10 = ((int)wsptr[0] + (int)wsptr[4]);
- tmp11 = ((int)wsptr[0] - (int)wsptr[4]);
+ tmp10 = (wsptr[0] + wsptr[4]);
+ tmp11 = (wsptr[0] - wsptr[4]);
- tmp13 = ((int)wsptr[2] + (int)wsptr[6]);
+ tmp13 = (wsptr[2] + wsptr[6]);
tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) - tmp13;
tmp0 = tmp10 + tmp13;
@@ -493,10 +485,10 @@
/* Odd part */
- z13 = (int)wsptr[5] + (int)wsptr[3];
- z10 = (int)wsptr[5] - (int)wsptr[3];
- z11 = (int)wsptr[1] + (int)wsptr[7];
- z12 = (int)wsptr[1] - (int)wsptr[7];
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
tmp7 = z11 + z13; /* phase 5 */
tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
@@ -538,7 +530,7 @@
int nBlocksInMcu = 6;
unsigned int pixel_x, pixel_y;
- pByte = (struct RGB *)pBgr;
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
if (yuvmode == YuvMode::YUV444) {
py = pYCbCr;
pcb = pYCbCr + 64;
@@ -566,7 +558,9 @@
pos += WIDTH;
}
} else {
- for (i = 0; i < nBlocksInMcu - 2; i++) py420[i] = pYCbCr + i * 64;
+ for (i = 0; i < nBlocksInMcu - 2; i++) {
+ py420[i] = pYCbCr + i * 64;
+ }
pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
pcr = pcb + 64;
@@ -606,7 +600,7 @@
int nBlocksInMcu = 6;
unsigned int pixel_x, pixel_y;
- pByte = (struct RGB *)pBgr;
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
if (yuvmode == YuvMode::YUV444) {
py = pYCbCr;
pcb = pYCbCr + 64;
@@ -633,7 +627,9 @@
pos += WIDTH;
}
} else {
- for (i = 0; i < nBlocksInMcu - 2; i++) py420[i] = pYCbCr + i * 64;
+ for (i = 0; i < nBlocksInMcu - 2; i++) {
+ py420[i] = pYCbCr + i * 64;
+ }
pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
pcr = pcb + 64;
@@ -697,7 +693,8 @@
// YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
// YUVBuffer for YUV record
- YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
+ YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
void Decompress_2PASS(int txb, int tyb, char *outBuf,
@@ -718,7 +715,8 @@
process_Huffman_data_unit(CrDC_nr, CrAC_nr, &DCCr, 128);
IDCT_transform(DCT_coeff + 128, ptr, QT_TableSelection + 1);
- YUVToBuffer(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
+ YUVToBuffer(txb, tyb, byTileYuv, YUVBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
// YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
}
@@ -738,7 +736,7 @@
}
} else {
for (i = 0; i < 64; i++) {
- Data = (int)lookKbits(VQ->BitMapBits);
+ Data = static_cast<int>(lookKbits(VQ->BitMapBits));
ptr[0] = (VQ->Color[VQ->Index[Data]] & 0xFF0000) >> 16;
ptr[64] = (VQ->Color[VQ->Index[Data]] & 0x00FF00) >> 8;
ptr[128] = VQ->Color[VQ->Index[Data]] & 0x0000FF;
@@ -747,22 +745,27 @@
}
}
// YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf);
+ YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
- void MoveBlockIndex(void) {
+ void MoveBlockIndex() {
if (yuvmode == YuvMode::YUV444) {
txb++;
- if (txb >= (int)(WIDTH / 8)) {
+ if (txb >= static_cast<int>(WIDTH / 8)) {
tyb++;
- if (tyb >= (int)(HEIGHT / 8)) tyb = 0;
+ if (tyb >= static_cast<int>(HEIGHT / 8)) {
+ tyb = 0;
+ }
txb = 0;
}
} else {
txb++;
- if (txb >= (int)(WIDTH / 16)) {
+ if (txb >= static_cast<int>(WIDTH / 16)) {
tyb++;
- if (tyb >= (int)(HEIGHT / 16)) tyb = 0;
+ if (tyb >= static_cast<int>(HEIGHT / 16)) {
+ tyb = 0;
+ }
txb = 0;
}
}
@@ -782,13 +785,13 @@
/* Cr=>G value is scaled-up -0.8125 * x */
/* Cb=>G value is scaled-up -0.390625 * x */
for (i = 0, x = -128; i < 256; i++, x++) {
- m_CrToR[i] = (int)(FIX(1.597656) * x + nHalf) >> 16;
- m_CbToB[i] = (int)(FIX(2.015625) * x + nHalf) >> 16;
- m_CrToG[i] = (int)(-FIX(0.8125) * x + nHalf) >> 16;
- m_CbToG[i] = (int)(-FIX(0.390625) * x + nHalf) >> 16;
+ m_CrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
+ m_CbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
+ m_CrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
+ m_CbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
}
for (i = 0, x = -16; i < 256; i++, x++) {
- m_Y[i] = (int)(FIX(1.164) * x + nHalf) >> 16;
+ m_Y[i] = (FIX(1.164) * x + nHalf) >> 16;
}
// For Color Text Enchance Y Re-map. Recommend to disable in default
/*
@@ -823,17 +826,20 @@
for (j = 1; j <= 16; j++) {
HT->Length[j] = nrcode[j];
}
- for (i = 0, k = 1; k <= 16; k++)
+ for (i = 0, k = 1; k <= 16; k++) {
for (j = 0; j < HT->Length[k]; j++) {
HT->V[WORD_hi_lo(k, j)] = value[i];
i++;
}
+ }
code = 0;
for (k = 1; k <= 16; k++) {
- HT->minor_code[k] = (unsigned short int)code;
- for (j = 1; j <= HT->Length[k]; j++) code++;
- HT->major_code[k] = (unsigned short int)(code - 1);
+ HT->minor_code[k] = static_cast<unsigned short int>(code);
+ for (j = 1; j <= HT->Length[k]; j++) {
+ code++;
+ }
+ HT->major_code[k] = static_cast<unsigned short int>(code - 1);
code *= 2;
if (HT->Length[k] == 0) {
HT->minor_code[k] = 0xFFFF;
@@ -846,10 +852,10 @@
for (code_index = 1; code_index < 65535; code_index++) {
if (code_index < Huff_code[i]) {
- HT->Len[code_index] = (unsigned char)Huff_code[i + 1];
+ HT->Len[code_index] = static_cast<unsigned char>(Huff_code[i + 1]);
} else {
i = i + 2;
- HT->Len[code_index] = (unsigned char)Huff_code[i + 1];
+ HT->Len[code_index] = static_cast<unsigned char>(Huff_code[i + 1]);
}
}
}
@@ -870,18 +876,24 @@
/* Allocate and fill in the sample_range_limit table */
{
int j;
- rlimit_table = (unsigned char *)malloc(5 * 256L + 128);
+ rlimit_table = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
/* First segment of "simple" table: limit[x] = 0 for x < 0 */
memset((void *)rlimit_table, 0, 256);
rlimit_table += 256; /* allow negative subscripts of simple table */
/* Main part of "simple" table: limit[x] = x */
- for (j = 0; j < 256; j++) rlimit_table[j] = j;
+ for (j = 0; j < 256; j++) {
+ rlimit_table[j] = j;
+ }
/* End of simple table, rest of first half of post-IDCT table */
- for (j = 256; j < 640; j++) rlimit_table[j] = 255;
+ for (j = 256; j < 640; j++) {
+ rlimit_table[j] = 255;
+ }
/* Second half of post-IDCT table */
memset((void *)(rlimit_table + 640), 0, 384);
- for (j = 0; j < 128; j++) rlimit_table[j + 1024] = j;
+ for (j = 0; j < 128; j++) {
+ rlimit_table[j + 1024] = j;
+ }
}
inline unsigned short int WORD_hi_lo(uint8_t byte_high, uint8_t byte_low) {
@@ -905,15 +917,16 @@
huff_values = HTDC[DC_nr].V;
// DC
- k = HTDC[DC_nr].Len[(unsigned short int)(codebuf >> 16)];
+ k = HTDC[DC_nr].Len[static_cast<unsigned short int>(codebuf >> 16)];
// river
// tmp_Hcode=lookKbits(k);
- tmp_Hcode = (unsigned short int)(codebuf >> (32 - k));
+ tmp_Hcode = static_cast<unsigned short int>(codebuf >> (32 - k));
skipKbits(k);
- size_val = huff_values[WORD_hi_lo(k, (uint8_t)(tmp_Hcode - min_code[k]))];
- if (size_val == 0)
+ size_val = huff_values[WORD_hi_lo(
+ k, static_cast<uint8_t>(tmp_Hcode - min_code[k]))];
+ if (size_val == 0) {
DCT_coeff[position + 0] = *previous_DC;
- else {
+ } else {
DCT_coeff[position + 0] = *previous_DC + getKbits(size_val);
*previous_DC = DCT_coeff[position + 0];
}
@@ -925,12 +938,12 @@
nr = 1; // AC coefficient
do {
- k = HTAC[AC_nr].Len[(unsigned short int)(codebuf >> 16)];
- tmp_Hcode = (unsigned short int)(codebuf >> (32 - k));
+ k = HTAC[AC_nr].Len[static_cast<unsigned short int>(codebuf >> 16)];
+ tmp_Hcode = static_cast<unsigned short int>(codebuf >> (32 - k));
skipKbits(k);
- byte_temp =
- huff_values[WORD_hi_lo(k, (uint8_t)(tmp_Hcode - min_code[k]))];
+ byte_temp = huff_values[WORD_hi_lo(
+ k, static_cast<uint8_t>(tmp_Hcode - min_code[k]))];
size_val = byte_temp & 0xF;
count_0 = byte_temp >> 4;
if (size_val == 0) {
@@ -948,7 +961,7 @@
unsigned short int lookKbits(uint8_t k) {
unsigned short int revcode;
- revcode = (unsigned short int)(codebuf >> (32 - k));
+ revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
return (revcode);
}
@@ -975,7 +988,7 @@
// river
// signed_wordvalue=lookKbits(k);
- signed_wordvalue = (unsigned short int)(codebuf >> (32 - k));
+ signed_wordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
if (((1L << (k - 1)) & signed_wordvalue) == 0) {
// neg_pow2 was previously defined as the below. It seemed silly to keep
// a table of values around for something
@@ -1002,17 +1015,21 @@
}
void set_quant_table(const uint8_t *basic_table, uint8_t scale_factor,
- uint8_t *newtable)
+ std::array<uint8_t, 64>& newtable)
// Set quantization table and zigzag reorder it
{
uint8_t i;
long temp;
for (i = 0; i < 64; i++) {
- temp = ((long)(basic_table[i] * 16) / scale_factor);
+ temp = (static_cast<long>(basic_table[i] * 16) / scale_factor);
/* limit the values to the valid range */
- if (temp <= 0L) temp = 1L;
- if (temp > 255L) temp = 255L; /* limit to baseline range if requested */
- newtable[zigzag[i]] = (uint8_t)temp;
+ if (temp <= 0L) {
+ temp = 1L;
+ }
+ if (temp > 255L) {
+ temp = 255L; /* limit to baseline range if requested */
+ }
+ newtable[zigzag[i]] = static_cast<uint8_t>(temp);
}
}
@@ -1053,17 +1070,17 @@
Mapping = 0; // 0 or 1
if (yuvmode == YuvMode::YUV420) {
- if (WIDTH % 16) {
+ if ((WIDTH % 16) != 0u) {
WIDTH = WIDTH + 16 - (WIDTH % 16);
}
- if (HEIGHT % 16) {
+ if ((HEIGHT % 16) != 0u) {
HEIGHT = HEIGHT + 16 - (HEIGHT % 16);
}
} else {
- if (WIDTH % 8) {
+ if ((WIDTH % 8) != 0u) {
WIDTH = WIDTH + 8 - (WIDTH % 8);
}
- if (HEIGHT % 8) {
+ if ((HEIGHT % 8) != 0u) {
HEIGHT = HEIGHT + 8 - (HEIGHT % 8);
}
}
@@ -1098,7 +1115,7 @@
case JpgBlock::JPEG_NO_SKIP_CODE:
updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_START_LENGTH, &newbits,
buffer);
- Decompress(txb, tyb, (char *)OutBuffer.data(), 0);
+ Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0);
break;
case JpgBlock::FRAME_END_CODE:
return 0;
@@ -1110,7 +1127,7 @@
updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_SKIP_LENGTH, &newbits,
buffer);
- Decompress(txb, tyb, (char *)OutBuffer.data(), 0);
+ Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0);
break;
case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_START_LENGTH, &newbits,
@@ -1129,7 +1146,8 @@
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
case JpgBlock::VQ_SKIP_1_COLOR_CODE:
txb = (codebuf & 0x0FF00000) >> 20;
@@ -1151,7 +1169,8 @@
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
@@ -1171,7 +1190,8 @@
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
case JpgBlock::VQ_SKIP_2_COLOR_CODE:
txb = (codebuf & 0x0FF00000) >> 20;
@@ -1193,7 +1213,8 @@
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
@@ -1201,19 +1222,19 @@
buffer);
Decode_Color.BitMapBits = 2;
- for (int i = 0; i < 4; i++) {
- Decode_Color.Index[i] = ((codebuf >> 29) & VQ_INDEX_MASK);
+ for (unsigned char &i : Decode_Color.Index) {
+ i = ((codebuf >> 29) & VQ_INDEX_MASK);
if (((codebuf >> 31) & VQ_HEADER_MASK) == VQ_NO_UPDATE_HEADER) {
updatereadbuf(&codebuf, &newbuf, VQ_NO_UPDATE_LENGTH, &newbits,
buffer);
} else {
- Decode_Color.Color[Decode_Color.Index[i]] =
- ((codebuf >> 5) & VQ_COLOR_MASK);
+ Decode_Color.Color[i] = ((codebuf >> 5) & VQ_COLOR_MASK);
updatereadbuf(&codebuf, &newbuf, VQ_UPDATE_LENGTH, &newbits,
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
@@ -1225,19 +1246,19 @@
buffer);
Decode_Color.BitMapBits = 2;
- for (int i = 0; i < 4; i++) {
- Decode_Color.Index[i] = ((codebuf >> 29) & VQ_INDEX_MASK);
+ for (unsigned char &i : Decode_Color.Index) {
+ i = ((codebuf >> 29) & VQ_INDEX_MASK);
if (((codebuf >> 31) & VQ_HEADER_MASK) == VQ_NO_UPDATE_HEADER) {
updatereadbuf(&codebuf, &newbuf, VQ_NO_UPDATE_LENGTH, &newbits,
buffer);
} else {
- Decode_Color.Color[Decode_Color.Index[i]] =
- ((codebuf >> 5) & VQ_COLOR_MASK);
+ Decode_Color.Color[i] = ((codebuf >> 5) & VQ_COLOR_MASK);
updatereadbuf(&codebuf, &newbuf, VQ_UPDATE_LENGTH, &newbits,
buffer);
}
}
- VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color);
+ VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0,
+ &Decode_Color);
break;
case JpgBlock::JPEG_SKIP_PASS2_CODE:
@@ -1246,7 +1267,8 @@
updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_SKIP_LENGTH, &newbits,
buffer);
- Decompress_2PASS(txb, tyb, (char *)OutBuffer.data(), 2);
+ Decompress_2PASS(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()),
+ 2);
break;
default:
@@ -1277,41 +1299,41 @@
#endif
private:
- YuvMode yuvmode;
+ YuvMode yuvmode{};
// WIDTH and HEIGHT are the modes your display used
- unsigned long WIDTH;
- unsigned long HEIGHT;
- unsigned long USER_WIDTH;
- unsigned long USER_HEIGHT;
- unsigned char Y_selector;
+ unsigned long WIDTH{};
+ unsigned long HEIGHT{};
+ unsigned long USER_WIDTH{};
+ unsigned long USER_HEIGHT{};
+ unsigned char Y_selector{};
int SCALEFACTOR;
int SCALEFACTORUV;
int ADVANCESCALEFACTOR;
int ADVANCESCALEFACTORUV;
- int Mapping;
- unsigned char UV_selector;
- unsigned char advance_selector;
- int byte_pos; // current byte position
+ int Mapping{};
+ unsigned char UV_selector{};
+ unsigned char advance_selector{};
+ int byte_pos{}; // current byte position
// quantization tables, no more than 4 quantization tables
- std::array<std::array<long, 64>, 4> QT;
+ std::array<std::array<long, 64>, 4> QT{};
// DC huffman tables , no more than 4 (0..3)
- std::array<Huffman_table, 4> HTDC;
+ std::array<Huffman_table, 4> HTDC{};
// AC huffman tables (0..3)
- std::array<Huffman_table, 4> HTAC;
- std::array<int, 256> m_CrToR;
- std::array<int, 256> m_CbToB;
- std::array<int, 256> m_CrToG;
- std::array<int, 256> m_CbToG;
- std::array<int, 256> m_Y;
- unsigned long buffer_index;
- uint32_t codebuf, newbuf, readbuf;
- const unsigned char *std_luminance_qt;
- const uint8_t *std_chrominance_qt;
+ std::array<Huffman_table, 4> HTAC{};
+ std::array<int, 256> m_CrToR{};
+ std::array<int, 256> m_CbToB{};
+ std::array<int, 256> m_CrToG{};
+ std::array<int, 256> m_CbToG{};
+ std::array<int, 256> m_Y{};
+ unsigned long buffer_index{};
+ uint32_t codebuf{}, newbuf{}, readbuf{};
+ const unsigned char *std_luminance_qt{};
+ const uint8_t *std_chrominance_qt{};
- signed short int DCY, DCCb, DCCr; // Coeficientii DC pentru Y,Cb,Cr
- signed short int DCT_coeff[384];
+ signed short int DCY{}, DCCb{}, DCCr{}; // Coeficientii DC pentru Y,Cb,Cr
+ signed short int DCT_coeff[384]{};
// std::vector<signed short int> DCT_coeff; // Current DCT_coefficients
// quantization table number for Y, Cb, Cr
uint8_t YQ_nr = 0, CbQ_nr = 1, CrQ_nr = 1;
@@ -1321,13 +1343,13 @@
uint8_t YAC_nr = 0, CbAC_nr = 1, CrAC_nr = 1;
int txb = 0;
int tyb = 0;
- int newbits;
- uint8_t *rlimit_table;
+ int newbits{};
+ uint8_t *rlimit_table{};
std::vector<RGB> YUVBuffer;
// TODO(ed) this shouldn't exist. It is cruft that needs cleaning up
- uint32_t *Buffer;
+ uint32_t *Buffer{};
public:
std::vector<RGB> OutBuffer;
};
-}
\ No newline at end of file
+} // namespace AstVideo
\ No newline at end of file
diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp
index 6575d7e..759aaeb 100644
--- a/include/ast_video_puller.hpp
+++ b/include/ast_video_puller.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <assert.h>
+#include <cassert>
#include <ast_video_types.hpp>
#include <iostream>
#include <mutex>
@@ -12,29 +12,29 @@
//
// Cursor struct is used in User Mode
//
-typedef struct _cursor_attribution_tag {
+struct AST_CUR_ATTRIBUTION_TAG {
unsigned int posX;
unsigned int posY;
unsigned int cur_width;
unsigned int cur_height;
unsigned int cur_type; // 0:mono 1:color 2:disappear cursor
unsigned int cur_change_flag;
-} AST_CUR_ATTRIBUTION_TAG;
+};
//
// For storing Cursor Information
//
-typedef struct _cursor_tag {
+struct AST_CURSOR_TAG {
AST_CUR_ATTRIBUTION_TAG attr;
// unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2];
unsigned char *icon; //[64*64*2];
-} AST_CURSOR_TAG;
+};
//
// For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0
// ~ 11, low to high
//
-typedef struct _video_features {
+struct FEATURES_TAG {
short jpg_fmt; // 422:JPG420, 444:JPG444
short lumin_tbl;
short chrom_tbl;
@@ -42,12 +42,12 @@
int w;
int h;
unsigned char *buf;
-} FEATURES_TAG;
+};
//
// For configure video engine control registers
//
-typedef struct _image_info {
+struct IMAGE_INFO {
short do_image_refresh; // Action 0:motion 1:fullframe 2:quick cursor
char qc_valid; // quick cursor enable/disable
unsigned int len;
@@ -57,7 +57,7 @@
FEATURES_TAG features;
AST_CURSOR_TAG cursor_info;
} parameter;
-} IMAGE_INFO;
+};
class SimpleVideoPuller {
public:
@@ -66,7 +66,7 @@
void initialize() {
std::cout << "Opening /dev/video\n";
video_fd = open("/dev/video", O_RDWR);
- if (!video_fd) {
+ if (video_fd == 0) {
std::cout << "Failed to open /dev/video\n";
throw std::runtime_error("Failed to open /dev/video");
}
@@ -117,16 +117,16 @@
}
private:
- int video_fd;
+ int video_fd{};
IMAGE_INFO image_info;
};
#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
class AsyncVideoPuller {
public:
- typedef std::function<void(RawVideoBuffer &)> video_callback;
+ using video_callback = std::function<void (RawVideoBuffer &)>;
- AsyncVideoPuller(boost::asio::io_service &io_service)
+ explicit AsyncVideoPuller(boost::asio::io_service &io_service)
: image_info(), dev_video(io_service, open("/dev/video", O_RDWR)) {
videobuf = std::make_shared<RawVideoBuffer>();
@@ -148,7 +148,7 @@
boost::asio::async_read(
dev_video, mutable_buffer, [this](const boost::system::error_code &ec,
std::size_t bytes_transferred) {
- if (ec) {
+ if (ec != nullptr) {
std::cerr << "Read failed with status " << ec << "\n";
} else {
this->read_done();
@@ -182,4 +182,4 @@
std::vector<video_callback> callbacks;
};
#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
-}
+} // namespace AstVideo
diff --git a/include/ast_video_types.hpp b/include/ast_video_types.hpp
index 206a7ef..f5cfffd 100644
--- a/include/ast_video_types.hpp
+++ b/include/ast_video_types.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <cstdint>
#include <vector>
namespace AstVideo {
enum class YuvMode { YUV444 = 0, YUV420 = 1 };
@@ -7,12 +8,12 @@
class RawVideoBuffer {
public:
RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){};
- unsigned long height;
- unsigned long width;
- int y_selector;
- int uv_selector;
+ unsigned long height{};
+ unsigned long width{};
+ int y_selector{};
+ int uv_selector{};
YuvMode mode;
// TODO(ed) determine a more appropriate buffer size
std::vector<uint32_t> buffer;
};
-}
\ No newline at end of file
+} // namespace AstVideo
\ No newline at end of file
diff --git a/include/base64.hpp b/include/base64.hpp
index a40ab47..092189d 100644
--- a/include/base64.hpp
+++ b/include/base64.hpp
@@ -4,4 +4,4 @@
bool base64_encode(const std::string &input, std::string &output);
bool base64_decode(const std::string &input, std::string &output);
-}
\ No newline at end of file
+} // namespace base64
\ No newline at end of file
diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp
new file mode 100644
index 0000000..0306183
--- /dev/null
+++ b/include/dbus_monitor.hpp
@@ -0,0 +1,82 @@
+#pragma once
+#include <dbus/filter.hpp>
+#include <dbus/match.hpp>
+#include <dbus_singleton.hpp>
+#include <crow/app.h>
+#include <boost/container/flat_map.hpp>
+
+namespace crow {
+namespace dbus_monitor {
+
+struct DbusWebsocketSession {
+ std::vector<std::unique_ptr<dbus::match>> matches;
+ std::vector<dbus::filter> filters;
+};
+
+static boost::container::flat_map<crow::websocket::connection*,
+ DbusWebsocketSession>
+ sessions;
+
+void on_property_update(dbus::filter& filter, boost::system::error_code ec,
+ dbus::message s) {
+ if (!ec) {
+ std::string object_name;
+ std::vector<std::pair<std::string, dbus::dbus_variant>> values;
+ s.unpack(object_name, values);
+ nlohmann::json j;
+ for (auto& value : values) {
+ boost::apply_visitor([&](auto val) { j[s.get_path()] = val; },
+ value.second);
+ }
+ auto data_to_send = j.dump();
+
+ for (auto& session : sessions) {
+ session.first->send_text(data_to_send);
+ }
+ }
+ filter.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
+ on_property_update(filter, ec, s);
+ });
+};
+
+template <typename... Middlewares>
+void request_routes(Crow<Middlewares...>& app) {
+ CROW_ROUTE(app, "/dbus_monitor")
+ .websocket()
+ .onopen([&](crow::websocket::connection& conn) {
+ std::string path_namespace(conn.req.url_params.get("path_namespace"));
+ if (path_namespace.empty()) {
+ conn.send_text(
+ nlohmann::json({"error", "Did not specify path_namespace"}));
+ conn.close("error");
+ }
+ sessions[&conn] = DbusWebsocketSession();
+ std::string match_string(
+ "type='signal',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "path_namespace='" +
+ path_namespace + "'");
+ sessions[&conn].matches.push_back(std::make_unique<dbus::match>(
+ crow::connections::system_bus, std::move(match_string)));
+
+ sessions[&conn].filters.emplace_back(
+ crow::connections::system_bus, [path_namespace](dbus::message m) {
+ return m.get_member() == "PropertiesChanged" &&
+ boost::starts_with(m.get_path(), path_namespace);
+ });
+ auto& this_filter = sessions[&conn].filters.back();
+ this_filter.async_dispatch(
+ [&](boost::system::error_code ec, dbus::message s) {
+ on_property_update(this_filter, ec, s);
+ });
+
+ })
+ .onclose([&](crow::websocket::connection& conn,
+ const std::string& reason) { sessions.erase(&conn); })
+ .onmessage([&](crow::websocket::connection& conn, const std::string& data,
+ bool is_binary) {
+ CROW_LOG_ERROR << "Got unexpected message from client on sensorws";
+ });
+}
+} // namespace redfish
+} // namespace crow
diff --git a/include/dbus_singleton.hpp b/include/dbus_singleton.hpp
new file mode 100644
index 0000000..e2fd2d6
--- /dev/null
+++ b/include/dbus_singleton.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include <dbus/connection.hpp>
+
+namespace crow {
+namespace connections {
+
+static std::shared_ptr<dbus::connection> system_bus;
+
+} // namespace dbus
+} // namespace crow
\ No newline at end of file
diff --git a/include/gzip_helper.hpp b/include/gzip_helper.hpp
new file mode 100644
index 0000000..9b7d253
--- /dev/null
+++ b/include/gzip_helper.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <zlib.h>
+#include <cstring>
+#include <string>
+
+inline bool gzip_inflate(const std::string& compressedBytes,
+ std::string& uncompressedBytes) {
+ if (compressedBytes.empty()) {
+ uncompressedBytes = compressedBytes;
+ return true;
+ }
+
+ uncompressedBytes.clear();
+
+ unsigned half_length = compressedBytes.size() / 2;
+
+ z_stream strm{};
+
+ // The following line is nolint because we're declaring away constness.
+ // It's not clear why the input buffers on zlib aren't const, so this is a
+ // bit of a cheat for the moment
+ strm.next_in = (Bytef*)compressedBytes.data(); // NOLINT
+ strm.avail_in = compressedBytes.size();
+ strm.total_out = 0;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+
+ bool done = false;
+
+ if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
+ return false;
+ }
+
+ while (!done) {
+ // If our output buffer is too small
+ if (strm.total_out >= uncompressedBytes.size()) {
+ uncompressedBytes.resize(uncompressedBytes.size() + half_length);
+ }
+
+ strm.next_out =
+ (Bytef*)(uncompressedBytes.data() + strm.total_out); // NOLINT
+ strm.avail_out =
+ ((uLong)uncompressedBytes.size() - strm.total_out); // NOLINT
+
+ // Inflate another chunk.
+ int err = inflate(&strm, Z_SYNC_FLUSH);
+ if (err == Z_STREAM_END) {
+ done = true;
+ } else if (err != Z_OK) {
+ break;
+ }
+ }
+
+ return inflateEnd(&strm) == Z_OK;
+}
\ No newline at end of file
diff --git a/include/intel_oem.hpp b/include/intel_oem.hpp
new file mode 100644
index 0000000..e821807
--- /dev/null
+++ b/include/intel_oem.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <dbus_singleton.hpp>
+#include <fstream>
+#include <crow/app.h>
+
+namespace crow {
+namespace intel_oem {
+
+template <typename... Middlewares>
+void request_routes(Crow<Middlewares...>& app) {
+ CROW_ROUTE(app, "/intel/firmwareupload")
+ .methods("POST"_method)([](const crow::request& req) {
+ std::string filepath("/tmp/fw_update_image");
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ out << req.body;
+ out.close();
+
+ auto m = dbus::message::new_call(
+ {"xyz.openbmc_project.fwupdate1.server",
+ "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1"},
+ "start");
+
+ m.pack(std::string("file://") + filepath);
+ crow::connections::system_bus->send(m);
+ nlohmann::json j;
+ j["status"] = "Upload Successful";
+ return j;
+ });
+}
+} // namespace redfish
+} // namespace crow
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
new file mode 100644
index 0000000..9348808
--- /dev/null
+++ b/include/openbmc_dbus_rest.hpp
@@ -0,0 +1,320 @@
+#include <crow/app.h>
+
+#include <tinyxml2.h>
+#include <dbus/connection.hpp>
+#include <dbus/endpoint.hpp>
+#include <dbus/filter.hpp>
+#include <dbus/match.hpp>
+#include <dbus/message.hpp>
+#include <dbus_singleton.hpp>
+
+namespace crow {
+namespace openbmc_mapper {
+std::atomic<std::size_t> outstanding_async_calls(0);
+nlohmann::json object_paths;
+
+void introspect_objects(crow::response &res, std::string process_name,
+ std::string path) {
+ dbus::endpoint introspect_endpoint(
+ process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect");
+ outstanding_async_calls++;
+ crow::connections::system_bus->async_method_call(
+ [&, process_name{std::move(process_name)}, object_path{std::move(path)} ](
+ const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ outstanding_async_calls--;
+ if (ec) {
+ std::cerr << "Introspect call failed with error: " << ec.message()
+ << " on process: " << process_name
+ << " path: " << object_path << "\n";
+
+ } else {
+ object_paths.push_back({{"path", object_path}});
+
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr) {
+ std::cerr << "XML document failed to parse " << process_name << " "
+ << path << "\n";
+
+ } else {
+ tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
+ while (node != nullptr) {
+ std::string child_path = node->Attribute("name");
+ std::string newpath;
+ if (object_path != "/") {
+ newpath += object_path;
+ }
+ newpath += "/" + child_path;
+ // intropect the subobjects as well
+ introspect_objects(res, process_name, newpath);
+
+ node = node->NextSiblingElement("node");
+ }
+ }
+ }
+ // if we're the last outstanding caller, finish the request
+ if (outstanding_async_calls == 0) {
+ nlohmann::json j{{"status", "ok"},
+ {"bus_name", process_name},
+ {"objects", object_paths}};
+
+ res.write(j.dump());
+ object_paths.clear();
+ res.end();
+ }
+ },
+ introspect_endpoint);
+}
+
+template <typename... Middlewares>
+void request_routes(Crow<Middlewares...> &app) {
+ CROW_ROUTE(app, "/bus/").methods("GET"_method)([](const crow::request &req) {
+ return nlohmann::json{{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
+
+ });
+
+ CROW_ROUTE(app, "/bus/system/")
+ .methods("GET"_method)([](const crow::request &req, crow::response &res) {
+ crow::connections::system_bus->async_method_call(
+ [&](const boost::system::error_code ec,
+ std::vector<std::string> &names) {
+ std::sort(names.begin(), names.end());
+ if (ec) {
+ res.code = 500;
+ } else {
+ nlohmann::json j{{"status", "ok"}};
+ auto &objects_sub = j["objects"];
+ for (auto &name : names) {
+ objects_sub.push_back({{"name", name}});
+ }
+
+ res.write(j.dump());
+ }
+
+ res.end();
+
+ },
+ {"org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames"});
+
+ });
+
+ CROW_ROUTE(app, "/bus/system/<str>/")
+ .methods("GET"_method)([](const crow::request &req, crow::response &res,
+ const std::string &connection) {
+ // Can only do one call at a time (for now)
+ if (outstanding_async_calls == 0) {
+ // TODO(ed) sanitize paths
+ introspect_objects(res, connection, "/");
+ } else {
+ nlohmann::json j{{"status", "failed"}};
+ res.code = 500;
+ res.write(j.dump());
+ res.end();
+ }
+ });
+
+ CROW_ROUTE(app, "/bus/system/<str>/<path>")
+ .methods("GET"_method)([](const crow::request &req, crow::response &res,
+ const std::string &process_name,
+ const std::string &requested_path) {
+
+ std::vector<std::string> strs;
+ boost::split(strs, requested_path, boost::is_any_of("/"));
+ std::string object_path;
+ std::string interface_name;
+ std::string method_name;
+ auto it = strs.begin();
+ if (it == strs.end()) {
+ object_path = "/";
+ }
+ while (it != strs.end()) {
+ // Check if segment contains ".". If it does, it must be an
+ // interface
+ if ((*it).find(".") != std::string::npos) {
+ break;
+ // THis check is neccesary as the trailing slash gets parsed as part
+ // of our <path> specifier above, which causes the normal trailing
+ // backslash redirector to fail.
+ } else if (!it->empty()) {
+ object_path += "/" + *it;
+ }
+ it++;
+ }
+ if (it != strs.end()) {
+ interface_name = *it;
+ it++;
+
+ // after interface, we might have a method name
+ if (it != strs.end()) {
+ method_name = *it;
+ it++;
+ }
+ }
+ if (it != strs.end()) {
+ // if there is more levels past the method name, something went
+ // wrong, throw an error
+ res.code = 404;
+ res.end();
+ return;
+ }
+ dbus::endpoint introspect_endpoint(
+ process_name, object_path, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
+ if (interface_name.empty()) {
+ crow::connections::system_bus->async_method_call(
+ [
+ &, process_name{std::move(process_name)},
+ object_path{std::move(object_path)}
+ ](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec) {
+ std::cerr
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << process_name
+ << " path: " << object_path << "\n";
+
+ } else {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr) {
+ std::cerr << "XML document failed to parse " << process_name
+ << " " << object_path << "\n";
+ res.write(nlohmann::json{{"status", "XML parse error"}});
+ res.code = 500;
+ } else {
+ nlohmann::json interfaces_array = nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr) {
+ std::string iface_name = interface->Attribute("name");
+ interfaces_array.push_back({{"name", iface_name}});
+
+ interface = interface->NextSiblingElement("interface");
+ }
+ nlohmann::json j{{"status", "ok"},
+ {"bus_name", process_name},
+ {"interfaces", interfaces_array},
+ {"object_path", object_path}};
+ res.write(j.dump());
+ }
+ }
+ res.end();
+ },
+ introspect_endpoint);
+ } else {
+ crow::connections::system_bus->async_method_call(
+ [
+ &, process_name{std::move(process_name)},
+ interface_name{std::move(interface_name)},
+ object_path{std::move(object_path)}
+ ](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec) {
+ std::cerr
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << process_name
+ << " path: " << object_path << "\n";
+
+ } else {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr) {
+ std::cerr << "XML document failed to parse " << process_name
+ << " " << object_path << "\n";
+ res.code = 500;
+
+ } else {
+ tinyxml2::XMLElement *node =
+ pRoot->FirstChildElement("node");
+
+ // if we know we're the only call, build the json directly
+ nlohmann::json methods_array = nlohmann::json::array();
+ nlohmann::json signals_array = nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr) {
+ std::string iface_name = interface->Attribute("name");
+
+ if (iface_name == interface_name) {
+ tinyxml2::XMLElement *methods =
+ interface->FirstChildElement("method");
+ while (methods != nullptr) {
+ nlohmann::json args_array = nlohmann::json::array();
+ tinyxml2::XMLElement *arg =
+ methods->FirstChildElement("arg");
+ while (arg != nullptr) {
+ args_array.push_back(
+ {{"name", arg->Attribute("name")},
+ {"type", arg->Attribute("type")},
+ {"direction", arg->Attribute("direction")}});
+ arg = arg->NextSiblingElement("arg");
+ }
+ methods_array.push_back(
+ {{"name", methods->Attribute("name")},
+ {"uri", "/bus/system/" + process_name +
+ object_path + "/" + interface_name +
+ "/" + methods->Attribute("name")},
+ {"args", args_array}});
+ methods = methods->NextSiblingElement("method");
+ }
+ tinyxml2::XMLElement *signals =
+ interface->FirstChildElement("signal");
+ while (signals != nullptr) {
+ nlohmann::json args_array = nlohmann::json::array();
+
+ tinyxml2::XMLElement *arg =
+ signals->FirstChildElement("arg");
+ while (arg != nullptr) {
+ std::string name = arg->Attribute("name");
+ std::string type = arg->Attribute("type");
+ args_array.push_back({
+ {"name", name}, {"type", type},
+ });
+ arg = arg->NextSiblingElement("arg");
+ }
+ signals_array.push_back(
+ {{"name", signals->Attribute("name")},
+ {"args", args_array}});
+ signals = signals->NextSiblingElement("signal");
+ }
+
+ nlohmann::json j{
+ {"status", "ok"},
+ {"bus_name", process_name},
+ {"interface", interface_name},
+ {"methods", methods_array},
+ {"object_path", object_path},
+ {"properties", nlohmann::json::object()},
+ {"signals", signals_array}};
+
+ res.write(j.dump());
+ break;
+ }
+
+ interface = interface->NextSiblingElement("interface");
+ }
+ if (interface == nullptr) {
+ // if we got to the end of the list and never found a
+ // match, throw 404
+ res.code = 404;
+ }
+ }
+ }
+ res.end();
+ },
+ introspect_endpoint);
+ }
+
+ });
+}
+} // namespace openbmc_mapper
+} // namespace crow
diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
index 153dbc7..0825dd6 100644
--- a/include/pam_authenticate.hpp
+++ b/include/pam_authenticate.hpp
@@ -1,20 +1,28 @@
+#pragma once
+
#include <security/pam_appl.h>
+#include <cstring>
// function used to get user input
inline int pam_function_conversation(int num_msg,
const struct pam_message** msg,
struct pam_response** resp,
void* appdata_ptr) {
- char* pass = (char*)malloc(strlen((char*)appdata_ptr) + 1);
- strcpy(pass, (char*)appdata_ptr);
+ if (appdata_ptr == nullptr) {
+ return PAM_AUTH_ERR;
+ }
+ auto* pass = reinterpret_cast<char*>(
+ malloc(std::strlen(reinterpret_cast<char*>(appdata_ptr)) + 1));
+ std::strcpy(pass, reinterpret_cast<char*>(appdata_ptr));
- int i;
+ *resp = reinterpret_cast<pam_response*>(
+ calloc(num_msg, sizeof(struct pam_response)));
- *resp = (pam_response*)calloc(num_msg, sizeof(struct pam_response));
-
- for (i = 0; i < num_msg; ++i) {
+ for (int i = 0; i < num_msg; ++i) {
/* Ignore all PAM messages except prompting for hidden input */
- if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) continue;
+ if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) {
+ continue;
+ }
/* Assume PAM is only prompting for the password as hidden input */
resp[i]->resp = pass;
@@ -23,43 +31,39 @@
return PAM_SUCCESS;
}
-class PamAuthenticator {
- public:
- inline bool authenticate(const std::string& username,
- const std::string& password) {
- const struct pam_conv local_conversation = {pam_function_conversation,
- (char*)password.c_str()};
- pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start
+inline bool pam_authenticate_user(const std::string& username,
+ const std::string& password) {
+ const struct pam_conv local_conversation = {
+ pam_function_conversation, const_cast<char*>(password.c_str())};
+ pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start
- int retval;
- retval = pam_start("su", username.c_str(), &local_conversation,
- &local_auth_handle);
-
- if (retval != PAM_SUCCESS) {
- //printf("pam_start returned: %d\n ", retval);
- return false;
- }
-
- retval = pam_authenticate(local_auth_handle,
- PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
-
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_AUTH_ERR) {
- //printf("Authentication failure.\n");
- } else {
- //printf("pam_authenticate returned %d\n", retval);
- }
- return false;
- }
-
- //printf("Authenticated.\n");
- retval = pam_end(local_auth_handle, retval);
-
- if (retval != PAM_SUCCESS) {
- //printf("pam_end returned\n");
- return false;
- }
-
- return true;
+ if (pam_start("su", username.c_str(), &local_conversation,
+ &local_auth_handle) != PAM_SUCCESS) {
+ return false;
}
-};
\ No newline at end of file
+ int retval = pam_authenticate(local_auth_handle,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
+
+ if (retval != PAM_SUCCESS) {
+ if (retval == PAM_AUTH_ERR) {
+ // printf("Authentication failure.\n");
+ } else {
+ // printf("pam_authenticate returned %d\n", retval);
+ }
+ pam_end(local_auth_handle, PAM_SUCCESS);
+ return false;
+ }
+
+ /* check that the account is healthy */
+ if (pam_acct_mgmt(local_auth_handle, PAM_DISALLOW_NULL_AUTHTOK) !=
+ PAM_SUCCESS) {
+ pam_end(local_auth_handle, PAM_SUCCESS);
+ return false;
+ }
+
+ if (pam_end(local_auth_handle, PAM_SUCCESS) != PAM_SUCCESS) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index c302a68..73ed84e 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -1,9 +1,24 @@
+#pragma once
+
#include <crow/app.h>
+
+#include <dbus/connection.hpp>
+#include <dbus/endpoint.hpp>
+#include <dbus/filter.hpp>
+#include <dbus/match.hpp>
+#include <dbus/message.hpp>
+#include <fstream>
+
namespace crow {
namespace redfish {
template <typename... Middlewares>
void request_routes(Crow<Middlewares...>& app) {
+
+ // noop for now
+ return;
+
+
CROW_ROUTE(app, "/redfish/").methods("GET"_method)([]() {
return nlohmann::json{{"v1", "/redfish/v1/"}};
});
@@ -28,6 +43,28 @@
};
});
+ CROW_ROUTE(app, "/redfish/v1/Chassis").methods("GET"_method)([]() {
+ std::vector<std::string> entities;
+ std::ifstream f("~/system.json");
+ nlohmann::json input;
+ input << f;
+ for (auto it = input.begin(); it != input.end(); it++) {
+ auto value = it.value();
+ if (value["type"] == "Chassis") {
+ std::string str = value["name"];
+ entities.emplace_back(str);
+ }
+ }
+ auto ret = nlohmann::json{
+ {"@odata.context",
+ "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"},
+ {"@odata.id", "/redfish/v1/Chassis"},
+ {"@odata.type", "#ChassisCollection.ChassisCollection"},
+ {"Name", "Chassis Collection"},
+ {"Members@odata.count", entities.size()}};
+ return ret;
+ });
+
CROW_ROUTE(app, "/redfish/v1/AccountService").methods("GET"_method)([]() {
return nlohmann::json{
{"@odata.context",
@@ -38,6 +75,7 @@
{"Name", "Account Service"},
{"Description", "BMC User Accounts"},
{"Status",
+ // TODO(ed) health rollup
{{"State", "Enabled"}, {"Health", "OK"}, {"HealthRollup", "OK"}}},
{"ServiceEnabled", true},
{"MinPasswordLength", 1},
@@ -47,22 +85,41 @@
};
});
- CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
- .methods("GET"_method)([]() {
- return nlohmann::json{
- {"@odata.context",
- "/redfish/v1/"
- "$metadata#ManagerAccountCollection.ManagerAccountCollection"},
- {"@odata.id", "/redfish/v1/AccountService/Accounts"},
- {"@odata.type",
- "#ManagerAccountCollection.ManagerAccountCollection"},
- {"Name", "Accounts Collection"},
- {"Description", "BMC User Accounts"},
- {"Members@odata.count", 3},
- {"Members",
- {{{"@odata.id", "/redfish/v1/AccountService/Accounts/1"}},
- {{"@odata.id", "/redfish/v1/AccountService/Accounts/2"}},
- {{"@odata.id", "/redfish/v1/AccountService/Accounts/3"}}}}};
+ CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts")
+ .methods("GET"_method)([](const crow::request& req, crow::response& res) {
+ boost::asio::io_service io;
+ auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session);
+ dbus::endpoint user_list("org.openbmc.UserManager",
+ "/org/openbmc/UserManager/Users",
+ "org.openbmc.Enrol", "UserList");
+ bus->async_method_call(
+ [&](const boost::system::error_code ec,
+ const std::vector<std::string>& users) {
+ if (ec) {
+ res.code = 500;
+ } else {
+ nlohmann::json return_json{
+ {"@odata.context",
+ "/redfish/v1/"
+ "$metadata#ManagerAccountCollection."
+ "ManagerAccountCollection"},
+ {"@odata.id", "/redfish/v1/AccountService/Accounts"},
+ {"@odata.type",
+ "#ManagerAccountCollection.ManagerAccountCollection"},
+ {"Name", "Accounts Collection"},
+ {"Description", "BMC User Accounts"},
+ {"Members@odata.count", users.size()}};
+ nlohmann::json member_array;
+ int user_index = 0;
+ for (auto& user : users) {
+ member_array.push_back(
+ {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
+ std::to_string(++user_index)}});
+ }
+ return_json["Members"] = member_array;
+ }
+ res.end();
+ }, user_list);
});
CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/<int>/")
@@ -84,5 +141,5 @@
{{"@odata.id", "/redfish/v1/AccountService/Roles/NoAccess"}}}}}};
});
}
-}
-}
\ No newline at end of file
+} // namespace redfish
+} // namespace crow
diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp
index 19644f4..e12395a 100644
--- a/include/security_headers_middleware.hpp
+++ b/include/security_headers_middleware.hpp
@@ -4,34 +4,28 @@
#include <crow/http_response.h>
namespace crow {
-static const std::string strict_transport_security_key =
- "Strict-Transport-Security";
-static const std::string strict_transport_security_value =
+static const char* strict_transport_security_key = "Strict-Transport-Security";
+static const char* strict_transport_security_value =
"max-age=31536000; includeSubdomains; preload";
-static const std::string ua_compatability_key = "X-UA-Compatible";
-static const std::string ua_compatability_value = "IE=11";
+static const char* ua_compatability_key = "X-UA-Compatible";
+static const char* ua_compatability_value = "IE=11";
-static const std::string xframe_key = "X-Frame-Options";
-static const std::string xframe_value = "DENY";
+static const char* xframe_key = "X-Frame-Options";
+static const char* xframe_value = "DENY";
-static const std::string xss_key = "X-XSS-Protection";
-static const std::string xss_value = "1; mode=block";
+static const char* xss_key = "X-XSS-Protection";
+static const char* xss_value = "1; mode=block";
-static const std::string content_security_key = "X-Content-Security-Policy";
-static const std::string content_security_value = "default-src 'self'";
-
+static const char* content_security_key = "X-Content-Security-Policy";
+static const char* content_security_value = "default-src 'self'";
struct SecurityHeadersMiddleware {
struct context {};
- void before_handle(crow::request& req,
- response& res,
- context& ctx) {}
+ void before_handle(crow::request& req, response& res, context& ctx) {}
- void after_handle(request& /*req*/,
- response& res,
- context& ctx) {
+ void after_handle(request& req, response& res, context& ctx) {
/*
TODO(ed) these should really check content types. for example,
X-UA-Compatible header doesn't make sense when retrieving a JSON or
@@ -43,6 +37,8 @@
res.add_header(xframe_key, xframe_value);
res.add_header(xss_key, xss_value);
res.add_header(content_security_key, content_security_value);
+ res.add_header("Access-Control-Allow-Origin", "http://localhost:8085");
+ res.add_header("Access-Control-Allow-Credentials", "true");
}
};
-}
\ No newline at end of file
+} // namespace crow
diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
index 4948025..2a1a852 100644
--- a/include/ssl_key_handler.hpp
+++ b/include/ssl_key_handler.hpp
@@ -15,11 +15,11 @@
#include <boost/asio.hpp>
namespace ensuressl {
-static void init_openssl(void);
-static void cleanup_openssl(void);
-static EVP_PKEY *create_rsa_key(void);
-static EVP_PKEY *create_ec_key(void);
-static void handle_openssl_error(void);
+static void init_openssl();
+static void cleanup_openssl();
+static EVP_PKEY *create_rsa_key();
+static EVP_PKEY *create_ec_key();
+static void handle_openssl_error();
inline bool verify_openssl_key_cert(const std::string &filepath) {
bool private_key_valid = false;
@@ -31,9 +31,9 @@
if (file != NULL) {
EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
int rc;
- if (pkey) {
+ if (pkey != nullptr) {
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa) {
+ if (rsa != nullptr) {
std::cout << "Found an RSA key\n";
if (RSA_check_key(rsa) == 1) {
// private_key_valid = true;
@@ -43,12 +43,13 @@
RSA_free(rsa);
} else {
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- if (ec) {
+ if (ec != nullptr) {
std::cout << "Found an EC key\n";
if (EC_KEY_check_key(ec) == 1) {
private_key_valid = true;
} else {
- std::cerr << "Key not valid error number " << ERR_get_error() << "\n";
+ std::cerr << "Key not valid error number " << ERR_get_error()
+ << "\n";
}
EC_KEY_free(ec);
}
@@ -56,7 +57,7 @@
if (private_key_valid) {
X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
- if (!x509) {
+ if (x509 == nullptr) {
std::cout << "error getting x509 cert " << ERR_get_error() << "\n";
} else {
rc = X509_verify(x509, pkey);
@@ -64,7 +65,7 @@
cert_valid = true;
} else {
std::cerr << "Error in verifying private key signature "
- << ERR_get_error() << "\n";
+ << ERR_get_error() << "\n";
}
}
}
@@ -86,12 +87,12 @@
std::cerr << "Generating EC key\n";
EVP_PKEY *pRsaPrivKey = create_ec_key();
- if (pRsaPrivKey) {
+ if (pRsaPrivKey != nullptr) {
std::cerr << "Generating x509 Certificate\n";
// Use this code to directly generate a certificate
X509 *x509;
x509 = X509_new();
- if (x509) {
+ if (x509 != nullptr) {
// Get a random number from the RNG for the certificate serial number
// If this is not random, regenerating certs throws broswer errors
std::random_device rd;
@@ -111,12 +112,15 @@
X509_NAME *name;
name = X509_get_subject_name(x509);
- X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US",
+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("US"),
-1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
- (unsigned char *)"Intel BMC", -1, -1, 0);
- X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
- (unsigned char *)"testhost", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(
+ name, "O", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1, 0);
+ X509_NAME_add_entry_by_txt(
+ name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0);
// set the CSR options
X509_set_issuer_name(x509, name);
@@ -125,7 +129,7 @@
pFile = fopen(filepath.c_str(), "wt");
- if (pFile) {
+ if (pFile != nullptr) {
PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, NULL);
PEM_write_X509(pFile, x509);
@@ -143,7 +147,7 @@
// cleanup_openssl();
}
-EVP_PKEY *create_rsa_key(void) {
+EVP_PKEY *create_rsa_key() {
RSA *pRSA = NULL;
#if OPENSSL_VERSION_NUMBER < 0x00908000L
pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
@@ -152,7 +156,8 @@
#endif
EVP_PKEY *pKey = EVP_PKEY_new();
- if (pRSA && pKey && EVP_PKEY_assign_RSA(pKey, pRSA)) {
+ if ((pRSA != nullptr) && (pKey != nullptr) &&
+ EVP_PKEY_assign_RSA(pKey, pRSA)) {
/* pKey owns pRSA from now */
if (RSA_check_key(pRSA) <= 0) {
fprintf(stderr, "RSA_check_key failed.\n");
@@ -162,11 +167,11 @@
}
} else {
handle_openssl_error();
- if (pRSA) {
+ if (pRSA != nullptr) {
RSA_free(pRSA);
pRSA = NULL;
}
- if (pKey) {
+ if (pKey != nullptr) {
EVP_PKEY_free(pKey);
pKey = NULL;
}
@@ -174,17 +179,17 @@
return pKey;
}
-EVP_PKEY *create_ec_key(void) {
+EVP_PKEY *create_ec_key() {
EVP_PKEY *pKey = NULL;
int eccgrp = 0;
eccgrp = OBJ_txt2nid("prime256v1");
EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp);
- if (myecc) {
+ if (myecc != nullptr) {
EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE);
EC_KEY_generate_key(myecc);
pKey = EVP_PKEY_new();
- if (pKey) {
+ if (pKey != nullptr) {
if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) {
/* pKey owns pRSA from now */
if (EC_KEY_check_key(myecc) <= 0) {
@@ -196,15 +201,15 @@
return pKey;
}
-void init_openssl(void) {
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- RAND_load_file("/dev/urandom", 1024);
+void init_openssl() {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ RAND_load_file("/dev/urandom", 1024);
#endif
}
-void cleanup_openssl(void) {
+void cleanup_openssl() {
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -213,7 +218,7 @@
EVP_cleanup();
}
-void handle_openssl_error(void) { ERR_print_errors_fp(stderr); }
+void handle_openssl_error() { ERR_print_errors_fp(stderr); }
inline void ensure_openssl_key_present_and_valid(const std::string &filepath) {
bool pem_file_valid = false;
@@ -225,7 +230,8 @@
}
}
-boost::asio::ssl::context get_ssl_context(std::string ssl_pem_file) {
+inline boost::asio::ssl::context get_ssl_context(
+ const std::string &ssl_pem_file) {
boost::asio::ssl::context m_ssl_context{boost::asio::ssl::context::sslv23};
m_ssl_context.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
@@ -249,7 +255,7 @@
}
// From mozilla "compatibility"
- std::string ciphers =
+ std::string mozilla_compatibility_ciphers =
"ECDHE-ECDSA-CHACHA20-POLY1305:"
"ECDHE-RSA-CHACHA20-POLY1305:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
@@ -283,7 +289,7 @@
"!DSS";
// From mozilla "modern"
- std::string modern_ciphers =
+ std::string mozilla_modern_ciphers =
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-CHACHA20-POLY1305:"
@@ -295,14 +301,14 @@
"ECDHE-ECDSA-AES128-SHA256:"
"ECDHE-RSA-AES128-SHA256";
- std::string lighttp_ciphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
+ std::string aes_only_ciphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
- if (SSL_CTX_set_cipher_list(m_ssl_context.native_handle(), lighttp_ciphers.c_str()) !=
- 1) {
+ if (SSL_CTX_set_cipher_list(m_ssl_context.native_handle(),
+ mozilla_compatibility_ciphers.c_str()) != 1) {
CROW_LOG_ERROR << "Error setting cipher list\n";
}
return m_ssl_context;
}
-}
+} // namespace ensuressl
#endif
\ No newline at end of file
diff --git a/include/test_utils.hpp b/include/test_utils.hpp
deleted file mode 100644
index eb990d5..0000000
--- a/include/test_utils.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include <string>
-
-bool gzipInflate(const std::string& compressedBytes,
- std::string& uncompressedBytes);
\ No newline at end of file
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 2d1edcd..eebd4f0 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -1,32 +1,32 @@
#pragma once
+#include <base64.hpp>
+#include <pam_authenticate.hpp>
+#include <webassets.hpp>
+#include <random>
+#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
#include <boost/container/flat_set.hpp>
-#include <base64.hpp>
-
-#include <pam_authenticate.hpp>
-
namespace crow {
+namespace TokenAuthorization {
struct User {};
using random_bytes_engine =
- std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
- unsigned char>;
+ std::independent_bits_engine<std::random_device, CHAR_BIT, unsigned char>;
-template <class AuthenticationFunction>
-struct TokenAuthorization {
- private:
- random_bytes_engine rbe;
-
+class Middleware {
public:
- struct context {
- // std::string auth_token;
+ Middleware() {
+ for (auto& route : crow::webassets::routes) {
+ allowed_routes.emplace(route);
+ }
+ allowed_routes.emplace("/login");
};
- TokenAuthorization(){};
+ struct context {};
void before_handle(crow::request& req, response& res, context& ctx) {
auto return_unauthorized = [&req, &res]() {
@@ -34,100 +34,64 @@
res.end();
};
- auto return_bad_request = [&req, &res]() {
- res.code = 400;
- res.end();
- };
-
- auto return_internal_error = [&req, &res]() {
- res.code = 500;
- res.end();
- };
-
- if (req.url == "/" || boost::starts_with(req.url, "/static/")) {
+ if (allowed_routes.find(req.url.c_str()) != allowed_routes.end()) {
// 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 for based page
- // that didn't load the full angular UI until after login
- return;
- }
-
- if (req.url == "/login") {
- if (req.method != HTTPMethod::POST) {
- return_unauthorized();
- return;
- } else {
- std::string username;
- std::string password;
- try {
- auto login_credentials = nlohmann::json::parse(req.body);
- username = login_credentials["username"];
- password = login_credentials["password"];
- } catch (...) {
- return_bad_request();
- return;
- }
-
- auto p = AuthenticationFunction();
- if (p.authenticate(username, password)) {
- nlohmann::json x;
-
- std::string token('a', 20);
- // TODO(ed) for some reason clang-tidy finds a divide by zero error in
- // cstdlibc here commented out for now. Needs investigation
- std::generate(std::begin(token), std::end(token),
- std::ref(rbe)); // NOLINT
- std::string encoded_token;
- base64::base64_encode(token, encoded_token);
- // ctx.auth_token = encoded_token;
- this->auth_token2.insert(encoded_token);
-
- nlohmann::json ret{{"token", encoded_token}};
-
- res.write(ret.dump());
- res.add_header("Content-Type", "application/json");
- res.end();
- } else {
+ // should be done in the url router handler, with tagged routes for the
+ // whitelist entries. Another option would be to whitelist a minimal form
+ // based page that didn't load the full angular UI until after login
+ } else {
+ // Normal, non login, non static file request
+ // Check for an authorization header, reject if not present
+ std::string auth_key;
+ if (req.headers.count("Authorization") == 1) {
+ std::string auth_header = req.get_header_value("Authorization");
+ // If the user is attempting any kind of auth other than token, reject
+ if (!boost::starts_with(auth_header, "Token ")) {
return_unauthorized();
return;
}
+ auth_key = auth_header.substr(6);
+ } else {
+ int count = req.headers.count("Cookie");
+ if (count == 1) {
+ auto& cookie_value = req.get_header_value("Cookie");
+ auto start_index = cookie_value.find("SESSION=");
+ if (start_index != std::string::npos) {
+ start_index += 8;
+ auto end_index = cookie_value.find(";", start_index);
+ if (end_index == std::string::npos) {
+ end_index = cookie_value.size() - 1;
+ }
+ auth_key =
+ cookie_value.substr(start_index, end_index - start_index + 1);
+ }
+ }
+ }
+ if (auth_key.empty()) {
+ res.code = 400;
+ res.end();
+ return;
+ }
+ std::cout << "auth_key=" << auth_key << "\n";
+
+ for (auto& token : this->auth_tokens) {
+ std::cout << "token=" << token << "\n";
}
- } else { // Normal, non login, non static file request
- // Check to make sure we're logged in
- if (this->auth_token2.empty()) {
- return_unauthorized();
- return;
- }
- // Check for an authorization header, reject if not present
- if (req.headers.count("Authorization") != 1) {
- return_unauthorized();
- return;
- }
-
- std::string auth_header = req.get_header_value("Authorization");
- // If the user is attempting any kind of auth other than token, reject
- if (!boost::starts_with(auth_header, "Token ")) {
- return_unauthorized();
- return;
- }
- std::string auth_key = auth_header.substr(6);
// TODO(ed), use span here instead of constructing a new string
- if (this->auth_token2.find(auth_key) == this->auth_token2.end()) {
+ if (this->auth_tokens.find(auth_key) == this->auth_tokens.end()) {
return_unauthorized();
return;
}
if (req.url == "/logout") {
- this->auth_token2.erase(auth_key);
+ this->auth_tokens.erase(auth_key);
res.code = 200;
res.end();
return;
}
-
// else let the request continue unharmed
}
}
@@ -136,9 +100,128 @@
// Do nothing
}
- private:
- boost::container::flat_set<std::string> auth_token2;
+ boost::container::flat_set<std::string> auth_tokens;
+ boost::container::flat_set<std::string> allowed_routes;
+ random_bytes_engine rbe;
};
-using TokenAuthorizationMiddleware = TokenAuthorization<PamAuthenticator>;
-}
\ No newline at end of file
+// TODO(ed) see if there is a better way to allow middlewares to request routes.
+// Possibly an init function on first construction?
+template <typename... Middlewares>
+void request_routes(Crow<Middlewares...>& app) {
+ static_assert(black_magic::contains<TokenAuthorization::Middleware,
+ Middlewares...>::value,
+ "TokenAuthorization middleware must be enabled in app to use "
+ "auth routes");
+ CROW_ROUTE(app, "/login")
+ .methods(
+ "POST"_method)([&](const crow::request& req, crow::response& res) {
+ std::string content_type;
+ auto content_type_it = req.headers.find("content-type");
+ if (content_type_it != req.headers.end()) {
+ content_type = content_type_it->second;
+ boost::algorithm::to_lower(content_type);
+ }
+ std::string username;
+ std::string password;
+ bool looks_like_ibm = false;
+ // Check if auth was provided by a payload
+ if (content_type == "application/json") {
+ try {
+ auto login_credentials = nlohmann::json::parse(req.body);
+ // check for username/password in the root object
+ // THis method is how intel APIs authenticate
+ auto user_it = login_credentials.find("username");
+ auto pass_it = login_credentials.find("password");
+ if (user_it != login_credentials.end() &&
+ pass_it != login_credentials.end()) {
+ username = user_it->get<const std::string>();
+ password = pass_it->get<const std::string>();
+ } else {
+ // Openbmc appears to push a data object that contains the same
+ // keys (username and password), attempt to use that
+ auto data_it = login_credentials.find("data");
+ if (data_it != login_credentials.end()) {
+ // Some apis produce an array of value ["username", "password"]
+ if (data_it->is_array()) {
+ if (data_it->size() == 2) {
+ username = (*data_it)[0].get<const std::string>();
+ password = (*data_it)[1].get<const std::string>();
+ looks_like_ibm = true;
+ }
+ } else if (data_it->is_object()) {
+ auto user_it = data_it->find("username");
+ auto pass_it = data_it->find("password");
+ if (user_it != data_it->end() && pass_it != data_it->end()) {
+ username = user_it->get<const std::string>();
+ password = pass_it->get<const std::string>();
+ }
+ }
+ }
+ }
+ } catch (...) {
+ // TODO(ed) figure out how to not throw on a bad json parse
+ res.code = 400;
+ res.end();
+ return;
+ }
+ } else {
+ // check if auth was provided as a query string
+ auto user_it = req.headers.find("username");
+ auto pass_it = req.headers.find("password");
+ if (user_it != req.headers.end() && pass_it != req.headers.end()) {
+ username = user_it->second;
+ password = pass_it->second;
+ }
+ }
+
+ if (!username.empty() && !password.empty()) {
+ if (!pam_authenticate_user(username, password)) {
+ res.code = 401;
+ } else {
+ // THis should be a multiple of 3 to make sure that base64 doesn't
+ // end with an equals sign at the end. we could strip it off
+ // afterward
+ std::string token(30, 'a');
+ // TODO(ed) for some reason clang-tidy finds a divide by zero
+ // error in cstdlibc here commented out for now.
+ // Needs investigation
+ auto& m = app.template get_middleware<Middleware>();
+ std::generate(std::begin(token), std::end(token),
+ std::ref(m.rbe)); // NOLINT
+ std::string encoded_token;
+ if (!base64::base64_encode(token, encoded_token)) {
+ res.code = 500;
+ } else {
+
+ m.auth_tokens.insert(encoded_token);
+ if (looks_like_ibm) {
+ // IBM requires a very specific login structure, and doesn't
+ // actually look at the status code. TODO(ed).... Fix that
+ // upstream
+ nlohmann::json ret{
+ {"data", "User '" + username + "' logged in"},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+ res.add_header(
+ "Set-Cookie",
+ "SESSION=" + encoded_token + "; Secure; HttpOnly");
+ res.write(ret.dump());
+ } else {
+ // if content type is json, assume json token
+ nlohmann::json ret{{"token", encoded_token}};
+
+ res.write(ret.dump());
+ res.add_header("Content-Type", "application/json");
+ }
+ }
+ }
+
+ } else {
+ res.code = 400;
+ }
+ res.end();
+ });
+}
+} // namespaec TokenAuthorization
+} // namespace crow
\ No newline at end of file
diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp
index 3d33347..82cb488 100644
--- a/include/web_kvm.hpp
+++ b/include/web_kvm.hpp
@@ -119,20 +119,20 @@
};
struct framebuffer_rectangle {
- boost::endian::big_uint16_t x;
- boost::endian::big_uint16_t y;
- boost::endian::big_uint16_t width;
- boost::endian::big_uint16_t height;
- boost::endian::big_uint32_t encoding;
+ boost::endian::big_uint16_t x{};
+ boost::endian::big_uint16_t y{};
+ boost::endian::big_uint16_t width{};
+ boost::endian::big_uint16_t height{};
+ boost::endian::big_uint32_t encoding{};
std::vector<uint8_t> data;
};
struct framebuffer_update_msg {
- boost::endian::big_uint8_t message_type;
+ boost::endian::big_uint8_t message_type{};
std::vector<framebuffer_rectangle> rectangles;
};
-std::string serialize(const framebuffer_update_msg& msg) {
+inline std::string serialize(const framebuffer_update_msg& msg) {
// calculate the size of the needed vector for serialization
size_t vector_size = 4;
for (const auto& rect : msg.rectangles) {
@@ -174,12 +174,12 @@
class connection_metadata {
public:
- connection_metadata(void) : vnc_state(VncState::UNSTARTED){};
+ connection_metadata() {};
- VncState vnc_state;
+ VncState vnc_state{VncState::UNSTARTED};
};
-typedef std::vector<connection_metadata> meta_list;
+using meta_list = std::vector<connection_metadata>;
meta_list connection_states(10);
connection_metadata meta;
@@ -235,7 +235,7 @@
} break;
case VncState::AWAITING_CLIENT_INIT_msg: {
// Now send the server initialization
- server_initialization_msg server_init_msg;
+ server_initialization_msg server_init_msg{};
server_init_msg.framebuffer_width = 800;
server_init_msg.framebuffer_height = 600;
server_init_msg.pixel_format.bits_per_pixel = 32;
@@ -261,8 +261,8 @@
case VncState::MAIN_LOOP: {
if (data.size() >= sizeof(client_to_server_msg_type)) {
auto type = static_cast<client_to_server_msg_type>(data[0]);
- std::cout << "Received client message type " << (uint32_t)type
- << "\n";
+ std::cout << "Received client message type "
+ << static_cast<std::size_t>(type) << "\n";
switch (type) {
case client_to_server_msg_type::set_pixel_format: {
} break;
@@ -277,7 +277,9 @@
if (data.size() >= sizeof(frame_buffer_update_req) +
sizeof(client_to_server_msg_type)) {
auto msg = reinterpret_cast<const frame_buffer_update_req*>(
- data.data() + sizeof(client_to_server_msg_type));
+ data.data() + // NOLINT
+ sizeof(client_to_server_msg_type));
+ // TODO(ed) find a better way to do this deserialization
// Todo(ed) lifecycle of the video puller and decoder
// should be
@@ -302,10 +304,11 @@
this_rect.encoding =
static_cast<uint8_t>(encoding_type::raw);
std::cout << "Encoding is " << this_rect.encoding;
- this_rect.data.reserve(this_rect.width * this_rect.height *
- 4);
+ this_rect.data.reserve(
+ static_cast<std::size_t>(this_rect.width) *
+ static_cast<std::size_t>(this_rect.height) * 4);
std::cout << "Width " << out.width << " Height "
- << out.height;
+ << out.height;
for (int i = 0; i < out.width * out.height; i++) {
auto& pixel = d.OutBuffer[i];
@@ -349,5 +352,5 @@
});
}
-}
-}
\ No newline at end of file
+} // namespace kvm
+} // namespace crow
\ No newline at end of file
diff --git a/include/webassets.hpp b/include/webassets.hpp
new file mode 100644
index 0000000..988af76
--- /dev/null
+++ b/include/webassets.hpp
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <experimental/filesystem>
+#include <fstream>
+#include <string>
+#include <crow/app.h>
+#include <crow/http_request.h>
+#include <crow/http_response.h>
+#include <crow/routing.h>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/container/flat_set.hpp>
+
+namespace crow {
+namespace webassets {
+
+namespace filesystem = std::experimental::filesystem;
+static const char* gzip_string = "gzip";
+static const char* none_string = "none";
+static const char* if_none_match_string = "If-None-Match";
+static const char* content_encoding_string = "Content-Encoding";
+static const char* content_type_string = "Content-Type";
+static const char* etag_string = "ETag";
+
+static boost::container::flat_set<std::string> routes;
+
+template <typename... Middlewares>
+void request_routes(Crow<Middlewares...>& app) {
+ const static boost::container::flat_map<const char*, const char*> content_types{
+ {{".css", "text/css;charset=UTF-8"},
+ {".html", "text/html;charset=UTF-8"},
+ {".js", "text/html;charset=UTF-8"},
+ {".png", "image/png;charset=UTF-8"},
+ {".woff", "application/x-font-woff"},
+ {".woff2", "application/x-font-woff2"},
+ {".ttf", "application/x-font-ttf"},
+ {".svg", "image/svg+xml"},
+ {".eot", "application/vnd.ms-fontobject"},
+ // dev tools don't care about map type, setting to json causes
+ // browser to show as text
+ // https://stackoverflow.com/questions/19911929/what-mime-type-should-i-use-for-javascript-source-map-files
+ {".map", "application/json"}}};
+ auto rootpath = filesystem::path("/usr/share/www/");
+ auto dir_iter = filesystem::recursive_directory_iterator(rootpath);
+ for (auto& dir : dir_iter) {
+ auto absolute_path = dir.path();
+ auto relative_path = filesystem::path(
+ absolute_path.string().substr(rootpath.string().size() - 1));
+ // make sure we don't recurse into certain directories
+ // note: maybe check for is_directory() here as well...
+ if (filesystem::is_directory(dir)) {
+ // don't recurse into hidden directories or symlinks
+ if (boost::starts_with(dir.path().filename().string(), ".") ||
+ filesystem::is_symlink(dir)) {
+ dir_iter.disable_recursion_pending();
+ }
+ } else if (filesystem::is_regular_file(dir)) {
+ auto webpath = relative_path;
+ bool is_gzip = false;
+ if (relative_path.extension() == ".gz") {
+ webpath = webpath.replace_extension("");
+ is_gzip = true;
+ }
+
+ if (webpath.filename() == "index.html") {
+ webpath = webpath.parent_path();
+ }
+
+ routes.insert(webpath.string());
+
+ std::string absolute_path_str = absolute_path.string();
+ const char* content_type = nullptr;
+ auto content_type_it =
+ content_types.find(relative_path.extension().c_str());
+ if (content_type_it != content_types.end()) {
+ content_type = content_type_it->second;
+ }
+ app.route_dynamic(std::string(webpath.string()))(
+ [is_gzip, absolute_path_str, content_type](const crow::request& req,
+ crow::response& res) {
+ if (is_gzip) {
+ res.add_header(content_encoding_string, gzip_string);
+ } else {
+ res.add_header(content_encoding_string, none_string);
+ }
+ // std::string sha1("a576dc96a5c605b28afb032f3103630d61ac1068");
+ // res.add_header(etag_string, sha1);
+
+ // if (req.get_header_value(if_none_match_string) == sha1) {
+ // res.code = 304;
+ //} else {
+ // res.code = 200;
+ // TODO, if you have a browser from the dark ages that doesn't
+ // support
+ // gzip, unzip it before sending based on Accept-Encoding header
+ // res.add_header(content_encoding_string, gzip_string);
+ if (content_type != nullptr) {
+ res.add_header(content_type_string, content_type);
+ }
+ // res.set_header("Cache-Control", "public, max-age=86400");
+ std::ifstream inf(absolute_path_str);
+ if (!inf) {
+ CROW_LOG_DEBUG << "failed to read file";
+ res.code = 400;
+ res.end();
+ return;
+ }
+
+ std::string body{std::istreambuf_iterator<char>(inf),
+ std::istreambuf_iterator<char>()};
+
+ res.body = body;
+ res.end();
+ });
+ }
+ }
+}
+} // namespace webassets
+} // namespace crow
\ No newline at end of file