Move to clang-format-6.0
This commit moves the codebase to the lastest clang-format file from
upstream, as well as clang-format-6.0.
Change-Id: Ice8313468097c0c42317fbb9e10ddf036e8cff4c
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
index e6e0f08..e8bdddb 100644
--- a/include/ast_jpeg_decoder.hpp
+++ b/include/ast_jpeg_decoder.hpp
@@ -1,345 +1,390 @@
#pragma once
#include <aspeed/JTABLES.H>
-#include <ast_video_types.hpp>
+
#include <array>
+#include <ast_video_types.hpp>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <vector>
-namespace ast_video {
+namespace ast_video
+{
-struct ColorCache {
- ColorCache()
- : color{0x008080, 0xFF8080, 0x808080, 0xC08080}, index{0, 1, 2, 3} {}
+struct ColorCache
+{
+ ColorCache() :
+ color{0x008080, 0xFF8080, 0x808080, 0xC08080}, index{0, 1, 2, 3}
+ {
+ }
- unsigned long color[4];
- unsigned char index[4];
- unsigned char bitMapBits{};
+ unsigned long color[4];
+ unsigned char index[4];
+ unsigned char bitMapBits{};
};
-struct RGB {
- unsigned char b;
- unsigned char g;
- unsigned char r;
- unsigned char reserved;
+struct RGB
+{
+ unsigned char b;
+ unsigned char g;
+ unsigned char r;
+ unsigned char reserved;
};
-enum class JpgBlock {
- JPEG_NO_SKIP_CODE = 0x00,
- JPEG_SKIP_CODE = 0x08,
+enum class JpgBlock
+{
+ JPEG_NO_SKIP_CODE = 0x00,
+ JPEG_SKIP_CODE = 0x08,
- JPEG_PASS2_CODE = 0x02,
- JPEG_SKIP_PASS2_CODE = 0x0A,
+ JPEG_PASS2_CODE = 0x02,
+ JPEG_SKIP_PASS2_CODE = 0x0A,
- LOW_JPEG_NO_SKIP_CODE = 0x04,
- LOW_JPEG_SKIP_CODE = 0x0C,
+ LOW_JPEG_NO_SKIP_CODE = 0x04,
+ LOW_JPEG_SKIP_CODE = 0x0C,
- VQ_NO_SKIP_1_COLOR_CODE = 0x05,
- VQ_SKIP_1_COLOR_CODE = 0x0D,
+ VQ_NO_SKIP_1_COLOR_CODE = 0x05,
+ VQ_SKIP_1_COLOR_CODE = 0x0D,
- VQ_NO_SKIP_2_COLOR_CODE = 0x06,
- VQ_SKIP_2_COLOR_CODE = 0x0E,
+ VQ_NO_SKIP_2_COLOR_CODE = 0x06,
+ VQ_SKIP_2_COLOR_CODE = 0x0E,
- VQ_NO_SKIP_4_COLOR_CODE = 0x07,
- VQ_SKIP_4_COLOR_CODE = 0x0F,
+ VQ_NO_SKIP_4_COLOR_CODE = 0x07,
+ VQ_SKIP_4_COLOR_CODE = 0x0F,
- FRAME_END_CODE = 0x09,
+ FRAME_END_CODE = 0x09,
};
-class AstJpegDecoder {
- public:
- AstJpegDecoder() {
- // TODO(ed) figure out how to init this in the constructor
- yuvBuffer.resize(1920 * 1200);
- outBuffer.resize(1920 * 1200);
- for (auto &r : outBuffer) {
- r.r = 0x00;
- r.g = 0x00;
- r.b = 0x00;
- r.reserved = 0xAA;
+class AstJpegDecoder
+{
+ public:
+ AstJpegDecoder()
+ {
+ // TODO(ed) figure out how to init this in the constructor
+ yuvBuffer.resize(1920 * 1200);
+ outBuffer.resize(1920 * 1200);
+ for (auto &r : outBuffer)
+ {
+ r.r = 0x00;
+ r.g = 0x00;
+ r.b = 0x00;
+ r.reserved = 0xAA;
+ }
+
+ int qfactor = 16;
+
+ scalefactor = qfactor;
+ scalefactoruv = qfactor;
+ advancescalefactor = 16;
+ advancescalefactoruv = 16;
+ initJpgTable();
}
- int qfactor = 16;
+ void loadQuantTable(std::array<long, 64> &quant_table)
+ {
+ float scalefactorF[8] = {1.0f, 1.387039845f, 1.306562965f,
+ 1.175875602f, 1.0f, 0.785694958f,
+ 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
- scalefactor = qfactor;
- scalefactoruv = qfactor;
- advancescalefactor = 16;
- advancescalefactoruv = 16;
- initJpgTable();
- }
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ switch (ySelector)
+ {
+ case 0:
+ stdLuminanceQt = tbl000Y;
+ break;
+ case 1:
+ stdLuminanceQt = tbl014Y;
+ break;
+ case 2:
+ stdLuminanceQt = tbl029Y;
+ break;
+ case 3:
+ stdLuminanceQt = tbl043Y;
+ break;
+ case 4:
+ stdLuminanceQt = tbl057Y;
+ break;
+ case 5:
+ stdLuminanceQt = tbl071Y;
+ break;
+ case 6:
+ stdLuminanceQt = tbl086Y;
+ break;
+ case 7:
+ stdLuminanceQt = tbl100Y;
+ break;
+ }
+ setQuantTable(stdLuminanceQt, static_cast<uint8_t>(scalefactor),
+ tempQT);
- void loadQuantTable(std::array<long, 64> &quant_table) {
- float scalefactorF[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
-
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- switch (ySelector) {
- case 0:
- stdLuminanceQt = tbl000Y;
- break;
- case 1:
- stdLuminanceQt = tbl014Y;
- break;
- case 2:
- stdLuminanceQt = tbl029Y;
- break;
- case 3:
- stdLuminanceQt = tbl043Y;
- break;
- case 4:
- stdLuminanceQt = tbl057Y;
- break;
- case 5:
- stdLuminanceQt = tbl071Y;
- break;
- case 6:
- stdLuminanceQt = tbl086Y;
- break;
- case 7:
- stdLuminanceQt = tbl100Y;
- break;
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactorF[row] * scalefactorF[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- setQuantTable(stdLuminanceQt, static_cast<uint8_t>(scalefactor), tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactorF[row] * scalefactorF[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
+ void loadQuantTableCb(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
- void loadQuantTableCb(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder from zig-zag order
+ if (mapping == 0)
+ {
+ switch (uvSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Y;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Y;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Y;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Y;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Y;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Y;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Y;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Y;
+ break;
+ }
+ }
+ else
+ {
+ switch (uvSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Uv;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Uv;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Uv;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Uv;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Uv;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Uv;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Uv;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Uv;
+ break;
+ }
+ }
+ setQuantTable(stdChrominanceQt, static_cast<uint8_t>(scalefactoruv),
+ tempQT);
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder from zig-zag order
- if (mapping == 0) {
- switch (uvSelector) {
- case 0:
- stdChrominanceQt = tbl000Y;
- break;
- case 1:
- stdChrominanceQt = tbl014Y;
- break;
- case 2:
- stdChrominanceQt = tbl029Y;
- break;
- case 3:
- stdChrominanceQt = tbl043Y;
- break;
- case 4:
- stdChrominanceQt = tbl057Y;
- break;
- case 5:
- stdChrominanceQt = tbl071Y;
- break;
- case 6:
- stdChrominanceQt = tbl086Y;
- break;
- case 7:
- stdChrominanceQt = tbl100Y;
- break;
- }
- } else {
- switch (uvSelector) {
- case 0:
- stdChrominanceQt = tbl000Uv;
- break;
- case 1:
- stdChrominanceQt = tbl014Uv;
- break;
- case 2:
- stdChrominanceQt = tbl029Uv;
- break;
- case 3:
- stdChrominanceQt = tbl043Uv;
- break;
- case 4:
- stdChrominanceQt = tbl057Uv;
- break;
- case 5:
- stdChrominanceQt = tbl071Uv;
- break;
- case 6:
- stdChrominanceQt = tbl086Uv;
- break;
- case 7:
- stdChrominanceQt = tbl100Uv;
- break;
- }
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- setQuantTable(stdChrominanceQt, static_cast<uint8_t>(scalefactoruv),
- tempQT);
+ // Note: Added for Dual_JPEG
+ void loadAdvanceQuantTable(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
- // Note: Added for Dual_JPEG
- void loadAdvanceQuantTable(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ switch (advanceSelector)
+ {
+ case 0:
+ stdLuminanceQt = tbl000Y;
+ break;
+ case 1:
+ stdLuminanceQt = tbl014Y;
+ break;
+ case 2:
+ stdLuminanceQt = tbl029Y;
+ break;
+ case 3:
+ stdLuminanceQt = tbl043Y;
+ break;
+ case 4:
+ stdLuminanceQt = tbl057Y;
+ break;
+ case 5:
+ stdLuminanceQt = tbl071Y;
+ break;
+ case 6:
+ stdLuminanceQt = tbl086Y;
+ break;
+ case 7:
+ stdLuminanceQt = tbl100Y;
+ break;
+ }
+ // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
+ setQuantTable(stdLuminanceQt, static_cast<uint8_t>(advancescalefactor),
+ tempQT);
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- switch (advanceSelector) {
- case 0:
- stdLuminanceQt = tbl000Y;
- break;
- case 1:
- stdLuminanceQt = tbl014Y;
- break;
- case 2:
- stdLuminanceQt = tbl029Y;
- break;
- case 3:
- stdLuminanceQt = tbl043Y;
- break;
- case 4:
- stdLuminanceQt = tbl057Y;
- break;
- case 5:
- stdLuminanceQt = tbl071Y;
- break;
- case 6:
- stdLuminanceQt = tbl086Y;
- break;
- case 7:
- stdLuminanceQt = tbl100Y;
- break;
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- setQuantTable(stdLuminanceQt, static_cast<uint8_t>(advancescalefactor),
- tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
+ // Note: Added for Dual-JPEG
+ void loadAdvanceQuantTableCb(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
- // Note: Added for Dual-JPEG
- void loadAdvanceQuantTableCb(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ if (mapping == 1)
+ {
+ switch (advanceSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Y;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Y;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Y;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Y;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Y;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Y;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Y;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Y;
+ break;
+ }
+ }
+ else
+ {
+ switch (advanceSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Uv;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Uv;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Uv;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Uv;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Uv;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Uv;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Uv;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Uv;
+ break;
+ }
+ }
+ // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
+ setQuantTable(stdChrominanceQt,
+ static_cast<uint8_t>(advancescalefactoruv), tempQT);
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- if (mapping == 1) {
- switch (advanceSelector) {
- case 0:
- stdChrominanceQt = tbl000Y;
- break;
- case 1:
- stdChrominanceQt = tbl014Y;
- break;
- case 2:
- stdChrominanceQt = tbl029Y;
- break;
- case 3:
- stdChrominanceQt = tbl043Y;
- break;
- case 4:
- stdChrominanceQt = tbl057Y;
- break;
- case 5:
- stdChrominanceQt = tbl071Y;
- break;
- case 6:
- stdChrominanceQt = tbl086Y;
- break;
- case 7:
- stdChrominanceQt = tbl100Y;
- break;
- }
- } else {
- switch (advanceSelector) {
- case 0:
- stdChrominanceQt = tbl000Uv;
- break;
- case 1:
- stdChrominanceQt = tbl014Uv;
- break;
- case 2:
- stdChrominanceQt = tbl029Uv;
- break;
- case 3:
- stdChrominanceQt = tbl043Uv;
- break;
- case 4:
- stdChrominanceQt = tbl057Uv;
- break;
- case 5:
- stdChrominanceQt = tbl071Uv;
- break;
- case 6:
- stdChrominanceQt = tbl086Uv;
- break;
- case 7:
- stdChrominanceQt = tbl100Uv;
- break;
- }
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- setQuantTable(stdChrominanceQt, static_cast<uint8_t>(advancescalefactoruv),
- tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
-
- void idctTransform(short *coef, uint8_t *data, uint8_t nBlock) {
+ void idctTransform(short *coef, uint8_t *data, uint8_t nBlock)
+ {
#define FIX_1_082392200 ((int)277) /* FIX(1.082392200) */
#define FIX_1_414213562 ((int)362) /* FIX(1.414213562) */
#define FIX_1_847759065 ((int)473) /* FIX(1.847759065) */
@@ -347,108 +392,111 @@
#define MULTIPLY(var, cons) ((int)((var) * (cons)) >> 8)
- int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- int tmp10, tmp11, tmp12, tmp13;
- int z5, z10, z11, z12, z13;
- int workspace[64]; /* buffers data between passes */
+ int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ int tmp10, tmp11, tmp12, tmp13;
+ int z5, z10, z11, z12, z13;
+ int workspace[64]; /* buffers data between passes */
- short *inptr = coef;
- long *quantptr;
- int *wsptr = workspace;
- unsigned char *outptr;
- unsigned char *rLimit = rlimitTable + 128;
- int ctr, dcval, dctsize = 8;
+ short *inptr = coef;
+ long *quantptr;
+ int *wsptr = workspace;
+ unsigned char *outptr;
+ unsigned char *rLimit = rlimitTable + 128;
+ int ctr, dcval, dctsize = 8;
- quantptr = &qt[nBlock][0];
+ quantptr = &qt[nBlock][0];
- // Pass 1: process columns from input (inptr), store into work array(wsptr)
+ // Pass 1: process columns from input (inptr), store into work
+ // array(wsptr)
- for (ctr = 8; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
+ for (ctr = 8; ctr > 0; ctr--)
+ {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit
+ * this by short-circuiting the IDCT calculation for any column in
+ * which all the AC terms are zero. In that case each output is
+ * equal to the DC coefficient (with scale factor as needed). With
+ * typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
- if ((inptr[dctsize * 1] | inptr[dctsize * 2] | inptr[dctsize * 3] |
- inptr[dctsize * 4] | inptr[dctsize * 5] | inptr[dctsize * 6] |
- inptr[dctsize * 7]) == 0) {
- /* AC terms all zero */
- dcval = static_cast<int>((inptr[dctsize * 0] * quantptr[dctsize * 0]) >>
- 16);
+ if ((inptr[dctsize * 1] | inptr[dctsize * 2] | inptr[dctsize * 3] |
+ inptr[dctsize * 4] | inptr[dctsize * 5] | inptr[dctsize * 6] |
+ inptr[dctsize * 7]) == 0)
+ {
+ /* AC terms all zero */
+ dcval = static_cast<int>(
+ (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16);
- wsptr[dctsize * 0] = dcval;
- wsptr[dctsize * 1] = dcval;
- wsptr[dctsize * 2] = dcval;
- wsptr[dctsize * 3] = dcval;
- wsptr[dctsize * 4] = dcval;
- wsptr[dctsize * 5] = dcval;
- wsptr[dctsize * 6] = dcval;
- wsptr[dctsize * 7] = dcval;
+ wsptr[dctsize * 0] = dcval;
+ wsptr[dctsize * 1] = dcval;
+ wsptr[dctsize * 2] = dcval;
+ wsptr[dctsize * 3] = dcval;
+ wsptr[dctsize * 4] = dcval;
+ wsptr[dctsize * 5] = dcval;
+ wsptr[dctsize * 6] = dcval;
+ wsptr[dctsize * 7] = dcval;
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
- /* Even part */
+ /* Even part */
- tmp0 = (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16;
- tmp1 = (inptr[dctsize * 2] * quantptr[dctsize * 2]) >> 16;
- tmp2 = (inptr[dctsize * 4] * quantptr[dctsize * 4]) >> 16;
- tmp3 = (inptr[dctsize * 6] * quantptr[dctsize * 6]) >> 16;
+ tmp0 = (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16;
+ tmp1 = (inptr[dctsize * 2] * quantptr[dctsize * 2]) >> 16;
+ tmp2 = (inptr[dctsize * 4] * quantptr[dctsize * 4]) >> 16;
+ tmp3 = (inptr[dctsize * 6] * quantptr[dctsize * 6]) >> 16;
- tmp10 = tmp0 + tmp2; /* phase 3 */
- tmp11 = tmp0 - tmp2;
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
- tmp13 = tmp1 + tmp3; /* phases 5-3 */
- tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
- tmp0 = tmp10 + tmp13; /* phase 2 */
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
- /* Odd part */
+ /* Odd part */
- tmp4 = (inptr[dctsize * 1] * quantptr[dctsize * 1]) >> 16;
- tmp5 = (inptr[dctsize * 3] * quantptr[dctsize * 3]) >> 16;
- tmp6 = (inptr[dctsize * 5] * quantptr[dctsize * 5]) >> 16;
- tmp7 = (inptr[dctsize * 7] * quantptr[dctsize * 7]) >> 16;
+ tmp4 = (inptr[dctsize * 1] * quantptr[dctsize * 1]) >> 16;
+ tmp5 = (inptr[dctsize * 3] * quantptr[dctsize * 3]) >> 16;
+ tmp6 = (inptr[dctsize * 5] * quantptr[dctsize * 5]) >> 16;
+ tmp7 = (inptr[dctsize * 7] * quantptr[dctsize * 7]) >> 16;
- z13 = tmp6 + tmp5; /* phase 6 */
- z10 = tmp6 - tmp5;
- z11 = tmp4 + tmp7;
- z12 = tmp4 - tmp7;
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
- 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);
+ 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++;
- wsptr++;
- }
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
/* Pass 2: process rows from work array, store into output array. */
/* Note that we must descale the results by a factor of 8 == 2**3, */
@@ -458,897 +506,1042 @@
#define PASS1_BITS 0
#define IDESCALE(x, n) ((int)((x) >> (n)))
- wsptr = workspace;
- for (ctr = 0; ctr < dctsize; ctr++) {
- outptr = data + ctr * 8;
+ wsptr = workspace;
+ for (ctr = 0; ctr < dctsize; ctr++)
+ {
+ outptr = data + ctr * 8;
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the
- * time). On machines with very fast multiplication, it's possible that
- * the test takes more time than it's worth. In that case this section
- * may be commented out.
- */
- /* Even part */
+ /* Rows of zeroes can be exploited in the same way as we did with
+ * columns. However, the column calculation has created many nonzero
+ * AC terms, so the simplification applies less often (typically 5%
+ * to 10% of the time). On machines with very fast multiplication,
+ * it's possible that the test takes more time than it's worth. In
+ * that case this section may be commented out.
+ */
+ /* Even part */
- tmp10 = (wsptr[0] + wsptr[4]);
- tmp11 = (wsptr[0] - wsptr[4]);
+ tmp10 = (wsptr[0] + wsptr[4]);
+ tmp11 = (wsptr[0] - wsptr[4]);
- tmp13 = (wsptr[2] + wsptr[6]);
- tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) - tmp13;
+ tmp13 = (wsptr[2] + wsptr[6]);
+ tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) -
+ tmp13;
- tmp0 = tmp10 + tmp13;
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
- /* Odd part */
+ /* Odd part */
- z13 = wsptr[5] + wsptr[3];
- z10 = wsptr[5] - wsptr[3];
- z11 = wsptr[1] + wsptr[7];
- z12 = wsptr[1] - 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 */
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
- /* Final output stage: scale down by a factor of 8 and range-limit */
+ /* Final output stage: scale down by a factor of 8 and range-limit
+ */
- outptr[0] = rLimit[IDESCALE((tmp0 + tmp7), (PASS1_BITS + 3)) & 1023L];
- outptr[7] = rLimit[IDESCALE((tmp0 - tmp7), (PASS1_BITS + 3)) & 1023L];
- outptr[1] = rLimit[IDESCALE((tmp1 + tmp6), (PASS1_BITS + 3)) & 1023L];
- outptr[6] = rLimit[IDESCALE((tmp1 - tmp6), (PASS1_BITS + 3)) & 1023L];
- outptr[2] = rLimit[IDESCALE((tmp2 + tmp5), (PASS1_BITS + 3)) & 1023L];
- outptr[5] = rLimit[IDESCALE((tmp2 - tmp5), (PASS1_BITS + 3)) & 1023L];
- outptr[4] = rLimit[IDESCALE((tmp3 + tmp4), (PASS1_BITS + 3)) & 1023L];
- outptr[3] = rLimit[IDESCALE((tmp3 - tmp4), (PASS1_BITS + 3)) & 1023L];
+ outptr[0] =
+ rLimit[IDESCALE((tmp0 + tmp7), (PASS1_BITS + 3)) & 1023L];
+ outptr[7] =
+ rLimit[IDESCALE((tmp0 - tmp7), (PASS1_BITS + 3)) & 1023L];
+ outptr[1] =
+ rLimit[IDESCALE((tmp1 + tmp6), (PASS1_BITS + 3)) & 1023L];
+ outptr[6] =
+ rLimit[IDESCALE((tmp1 - tmp6), (PASS1_BITS + 3)) & 1023L];
+ outptr[2] =
+ rLimit[IDESCALE((tmp2 + tmp5), (PASS1_BITS + 3)) & 1023L];
+ outptr[5] =
+ rLimit[IDESCALE((tmp2 - tmp5), (PASS1_BITS + 3)) & 1023L];
+ outptr[4] =
+ rLimit[IDESCALE((tmp3 + tmp4), (PASS1_BITS + 3)) & 1023L];
+ outptr[3] =
+ rLimit[IDESCALE((tmp3 - tmp4), (PASS1_BITS + 3)) & 1023L];
- wsptr += dctsize; /* advance pointer to next row */
+ wsptr += dctsize; /* advance pointer to next row */
+ }
}
- }
- void yuvToRgb(
- int txb, int tyb,
- unsigned char
- *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- struct RGB *pYUV, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- unsigned char
- *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- ) {
- int i, j, pos, m, n;
- unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
- int y;
- struct RGB *pByte;
- int nBlocksInMcu = 6;
- unsigned int pixelX, pixelY;
+ void yuvToRgb(
+ int txb, int tyb,
+ unsigned char
+ *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ struct RGB *pYUV, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ unsigned char
+ *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ )
+ {
+ int i, j, pos, m, n;
+ unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
+ int y;
+ struct RGB *pByte;
+ int nBlocksInMcu = 6;
+ unsigned int pixelX, pixelY;
- pByte = reinterpret_cast<struct RGB *>(pBgr);
- if (yuvmode == YuvMode::YUV444) {
- py = pYCbCr;
- pcb = pYCbCr + 64;
- pcr = pcb + 64;
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
+ if (yuvmode == YuvMode::YUV444)
+ {
+ py = pYCbCr;
+ pcb = pYCbCr + 64;
+ pcr = pcb + 64;
- pixelX = txb * 8;
- pixelY = tyb * 8;
- pos = (pixelY * width) + pixelX;
+ pixelX = txb * 8;
+ pixelY = tyb * 8;
+ pos = (pixelY * width) + pixelX;
- for (j = 0; j < 8; j++) {
- for (i = 0; i < 8; i++) {
- m = ((j << 3) + i);
- y = py[m];
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- // For 2Pass. Save the YUV value
- pYUV[n].b = cb;
- pYUV[n].g = y;
- pYUV[n].r = cr;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ for (j = 0; j < 8; j++)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ m = ((j << 3) + i);
+ y = py[m];
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ // For 2Pass. Save the YUV value
+ pYUV[n].b = cb;
+ pYUV[n].g = y;
+ pYUV[n].r = cr;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
- } else {
- for (i = 0; i < nBlocksInMcu - 2; i++) {
- py420[i] = pYCbCr + i * 64;
- }
- pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
- pcr = pcb + 64;
+ else
+ {
+ for (i = 0; i < nBlocksInMcu - 2; i++)
+ {
+ py420[i] = pYCbCr + i * 64;
+ }
+ pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
+ pcr = pcb + 64;
- pixelX = txb * 16;
- pixelY = tyb * 16;
- pos = (pixelY * width) + pixelX;
+ pixelX = txb * 16;
+ pixelY = tyb * 16;
+ pos = (pixelY * width) + pixelX;
- for (j = 0; j < 16; j++) {
- for (i = 0; i < 16; i++) {
- // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
- y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
- m = ((j >> 1) << 3) + (i >> 1);
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ for (j = 0; j < 16; j++)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
+ y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
+ m = ((j >> 1) << 3) + (i >> 1);
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
}
- }
- void yuvToBuffer(
- int txb, int tyb,
- unsigned char
- *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- struct RGB
- *pYUV, // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- unsigned char
- *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- ) {
- int i, j, pos, m, n;
- unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
- int y;
- struct RGB *pByte;
- int nBlocksInMcu = 6;
- unsigned int pixelX, pixelY;
+ void yuvToBuffer(
+ int txb, int tyb,
+ unsigned char
+ *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ struct RGB
+ *pYUV, // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ unsigned char
+ *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ )
+ {
+ int i, j, pos, m, n;
+ unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
+ int y;
+ struct RGB *pByte;
+ int nBlocksInMcu = 6;
+ unsigned int pixelX, pixelY;
- pByte = reinterpret_cast<struct RGB *>(pBgr);
- if (yuvmode == YuvMode::YUV444) {
- py = pYCbCr;
- pcb = pYCbCr + 64;
- pcr = pcb + 64;
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
+ if (yuvmode == YuvMode::YUV444)
+ {
+ py = pYCbCr;
+ pcb = pYCbCr + 64;
+ pcr = pcb + 64;
- pixelX = txb * 8;
- pixelY = tyb * 8;
- pos = (pixelY * width) + pixelX;
+ pixelX = txb * 8;
+ pixelY = tyb * 8;
+ pos = (pixelY * width) + pixelX;
- for (j = 0; j < 8; j++) {
- for (i = 0; i < 8; i++) {
- m = ((j << 3) + i);
- n = pos + i;
- y = pYUV[n].g + (py[m] - 128);
- cb = pYUV[n].b + (pcb[m] - 128);
- cr = pYUV[n].r + (pcr[m] - 128);
- pYUV[n].b = cb;
- pYUV[n].g = y;
- pYUV[n].r = cr;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ for (j = 0; j < 8; j++)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ m = ((j << 3) + i);
+ n = pos + i;
+ y = pYUV[n].g + (py[m] - 128);
+ cb = pYUV[n].b + (pcb[m] - 128);
+ cr = pYUV[n].r + (pcr[m] - 128);
+ pYUV[n].b = cb;
+ pYUV[n].g = y;
+ pYUV[n].r = cr;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
- } else {
- for (i = 0; i < nBlocksInMcu - 2; i++) {
- py420[i] = pYCbCr + i * 64;
- }
- pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
- pcr = pcb + 64;
+ else
+ {
+ for (i = 0; i < nBlocksInMcu - 2; i++)
+ {
+ py420[i] = pYCbCr + i * 64;
+ }
+ pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
+ pcr = pcb + 64;
- pixelX = txb * 16;
- pixelY = tyb * 16;
- pos = (pixelY * width) + pixelX;
+ pixelX = txb * 16;
+ pixelY = tyb * 16;
+ pos = (pixelY * width) + pixelX;
- for (j = 0; j < 16; j++) {
- for (i = 0; i < 16; i++) {
- // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
- y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
- m = ((j >> 1) << 3) + (i >> 1);
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ for (j = 0; j < 16; j++)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
+ y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
+ m = ((j >> 1) << 3) + (i >> 1);
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
}
- }
- void decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection) {
- unsigned char *ptr;
- unsigned char byTileYuv[768] = {};
+ void decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection)
+ {
+ unsigned char *ptr;
+ unsigned char byTileYuv[768] = {};
- memset(dctCoeff, 0, 384 * 2);
- ptr = byTileYuv;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
- idctTransform(dctCoeff, ptr, QT_TableSelection);
- ptr += 64;
+ memset(dctCoeff, 0, 384 * 2);
+ ptr = byTileYuv;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
+ idctTransform(dctCoeff, ptr, QT_TableSelection);
+ ptr += 64;
- if (yuvmode == YuvMode::YUV420) {
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection);
- ptr += 64;
+ if (yuvmode == YuvMode::YUV420)
+ {
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection);
+ ptr += 64;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection);
- ptr += 64;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection);
+ ptr += 64;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 192);
- idctTransform(dctCoeff + 192, ptr, QT_TableSelection);
- ptr += 64;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 192);
+ idctTransform(dctCoeff + 192, ptr, QT_TableSelection);
+ ptr += 64;
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 256);
- idctTransform(dctCoeff + 256, ptr, QT_TableSelection + 1);
- ptr += 64;
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 256);
+ idctTransform(dctCoeff + 256, ptr, QT_TableSelection + 1);
+ ptr += 64;
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 320);
- idctTransform(dctCoeff + 320, ptr, QT_TableSelection + 1);
- } else {
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
- ptr += 64;
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 320);
+ idctTransform(dctCoeff + 320, ptr, QT_TableSelection + 1);
+ }
+ else
+ {
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
+ ptr += 64;
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
+ }
+
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
+ // yuvBuffer for YUV record
+ yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- // yuvBuffer for YUV record
- yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- }
+ void decompress2Pass(int txb, int tyb, char *outBuf,
+ uint8_t QT_TableSelection)
+ {
+ unsigned char *ptr;
+ unsigned char byTileYuv[768];
+ memset(dctCoeff, 0, 384 * 2);
- void decompress2Pass(int txb, int tyb, char *outBuf,
- uint8_t QT_TableSelection) {
- unsigned char *ptr;
- unsigned char byTileYuv[768];
- memset(dctCoeff, 0, 384 * 2);
+ ptr = byTileYuv;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
+ idctTransform(dctCoeff, ptr, QT_TableSelection);
+ ptr += 64;
- ptr = byTileYuv;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
- idctTransform(dctCoeff, ptr, QT_TableSelection);
- ptr += 64;
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
+ ptr += 64;
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
- ptr += 64;
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
-
- yuvToBuffer(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- }
-
- void vqDecompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
- struct ColorCache *VQ) {
- unsigned char *ptr, i;
- unsigned char byTileYuv[192];
- int data;
-
- ptr = byTileYuv;
- if (VQ->bitMapBits == 0) {
- for (i = 0; i < 64; i++) {
- ptr[0] = (VQ->color[VQ->index[0]] & 0xFF0000) >> 16;
- ptr[64] = (VQ->color[VQ->index[0]] & 0x00FF00) >> 8;
- ptr[128] = VQ->color[VQ->index[0]] & 0x0000FF;
- ptr += 1;
- }
- } else {
- for (i = 0; i < 64; i++) {
- 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;
- ptr += 1;
- skipKbits(VQ->bitMapBits);
- }
+ yuvToBuffer(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
}
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- }
- void moveBlockIndex() {
- if (yuvmode == YuvMode::YUV444) {
- txb++;
- if (txb >= static_cast<int>(width / 8)) {
- tyb++;
- if (tyb >= static_cast<int>(height / 8)) {
- tyb = 0;
+ void vqDecompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
+ struct ColorCache *VQ)
+ {
+ unsigned char *ptr, i;
+ unsigned char byTileYuv[192];
+ int data;
+
+ ptr = byTileYuv;
+ if (VQ->bitMapBits == 0)
+ {
+ for (i = 0; i < 64; i++)
+ {
+ ptr[0] = (VQ->color[VQ->index[0]] & 0xFF0000) >> 16;
+ ptr[64] = (VQ->color[VQ->index[0]] & 0x00FF00) >> 8;
+ ptr[128] = VQ->color[VQ->index[0]] & 0x0000FF;
+ ptr += 1;
+ }
}
- txb = 0;
- }
- } else {
- txb++;
- if (txb >= static_cast<int>(width / 16)) {
- tyb++;
- if (tyb >= static_cast<int>(height / 16)) {
- tyb = 0;
+ else
+ {
+ for (i = 0; i < 64; i++)
+ {
+ 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;
+ ptr += 1;
+ skipKbits(VQ->bitMapBits);
+ }
}
- txb = 0;
- }
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
+ yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
- }
- void initColorTable() {
- int i, x;
- int nScale = 1L << 16; // equal to power(2,16)
- int nHalf = nScale >> 1;
+ void moveBlockIndex()
+ {
+ if (yuvmode == YuvMode::YUV444)
+ {
+ txb++;
+ if (txb >= static_cast<int>(width / 8))
+ {
+ tyb++;
+ if (tyb >= static_cast<int>(height / 8))
+ {
+ tyb = 0;
+ }
+ txb = 0;
+ }
+ }
+ else
+ {
+ txb++;
+ if (txb >= static_cast<int>(width / 16))
+ {
+ tyb++;
+ if (tyb >= static_cast<int>(height / 16))
+ {
+ tyb = 0;
+ }
+ txb = 0;
+ }
+ }
+ }
+
+ void initColorTable()
+ {
+ int i, x;
+ int nScale = 1L << 16; // equal to power(2,16)
+ int nHalf = nScale >> 1;
#define FIX(x) ((int)((x)*nScale + 0.5))
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
- /* Cr=>r value is nearest int to 1.597656 * x */
- /* Cb=>b value is nearest int to 2.015625 * x */
- /* 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++) {
- mCrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
- mCbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
- mCrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
- mCbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
- }
- for (i = 0, x = -16; i < 256; i++, x++) {
- mY[i] = (FIX(1.164) * x + nHalf) >> 16;
- }
- // For color Text Enchance Y Re-map. Recommend to disable in default
- /*
- for (i = 0; i < (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate);
- i++) {
- temp = (double)i /
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate;
- temp1 = 1.0 / VideoEngineInfo->INFData.Gamma1Parameter;
- mY[i] =
- (BYTE)(VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate * pow (temp,
- temp1));
- if (mY[i] > 255) mY[i] = 255;
- }
- for (i = (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i < 256;
- i++) {
- mY[i] =
- (BYTE)((VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) + (256 -
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) * ( pow((double)((i -
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) / (256 -
- (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate))), (1.0 /
- VideoEngineInfo->INFData.Gamma2Parameter)) ));
- if (mY[i] > 255) mY[i] = 255;
- }
- */
- }
- void loadHuffmanTable(HuffmanTable *HT, const unsigned char *nrcode,
- const unsigned char *value,
- const unsigned short int *Huff_code) {
- unsigned char k, j, i;
- unsigned int code, codeIndex;
-
- for (j = 1; j <= 16; j++) {
- HT->length[j] = nrcode[j];
- }
- for (i = 0, k = 1; k <= 16; k++) {
- for (j = 0; j < HT->length[k]; j++) {
- HT->v[wordHiLo(k, j)] = value[i];
- i++;
- }
- }
-
- code = 0;
- for (k = 1; k <= 16; k++) {
- HT->minorCode[k] = static_cast<unsigned short int>(code);
- for (j = 1; j <= HT->length[k]; j++) {
- code++;
- }
- HT->majorCode[k] = static_cast<unsigned short int>(code - 1);
- code *= 2;
- if (HT->length[k] == 0) {
- HT->minorCode[k] = 0xFFFF;
- HT->majorCode[k] = 0;
- }
- }
-
- HT->len[0] = 2;
- i = 2;
-
- for (codeIndex = 1; codeIndex < 65535; codeIndex++) {
- if (codeIndex < Huff_code[i]) {
- HT->len[codeIndex] = static_cast<unsigned char>(Huff_code[i + 1]);
- } else {
- i = i + 2;
- HT->len[codeIndex] = static_cast<unsigned char>(Huff_code[i + 1]);
- }
- }
- }
- void initJpgTable() {
- initColorTable();
- prepareRangeLimitTable();
- loadHuffmanTable(&htdc[0], stdDcLuminanceNrcodes, stdDcLuminanceValues,
- dcLuminanceHuffmancode);
- loadHuffmanTable(&htac[0], stdAcLuminanceNrcodes, stdAcLuminanceValues,
- acLuminanceHuffmancode);
- loadHuffmanTable(&htdc[1], stdDcChrominanceNrcodes, stdDcChrominanceValues,
- dcChrominanceHuffmancode);
- loadHuffmanTable(&htac[1], stdAcChrominanceNrcodes, stdAcChrominanceValues,
- acChrominanceHuffmancode);
- }
-
- void prepareRangeLimitTable()
- /* Allocate and fill in the sample_range_limit table */
- {
- int j;
- rlimitTable = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
- /* First segment of "simple" table: limit[x] = 0 for x < 0 */
- memset((void *)rlimitTable, 0, 256);
- rlimitTable += 256; /* allow negative subscripts of simple table */
- /* Main part of "simple" table: limit[x] = x */
- for (j = 0; j < 256; j++) {
- rlimitTable[j] = j;
- }
- /* End of simple table, rest of first half of post-IDCT table */
- for (j = 256; j < 640; j++) {
- rlimitTable[j] = 255;
- }
-
- /* Second half of post-IDCT table */
- memset((void *)(rlimitTable + 640), 0, 384);
- for (j = 0; j < 128; j++) {
- rlimitTable[j + 1024] = j;
- }
- }
-
- inline unsigned short int wordHiLo(uint8_t byte_high, uint8_t byte_low) {
- return (byte_high << 8) + byte_low;
- }
-
- // river
- void processHuffmanDataUnit(uint8_t DC_nr, uint8_t AC_nr,
- signed short int *previous_DC,
- unsigned short int position) {
- uint8_t nr = 0;
- uint8_t k;
- unsigned short int tmpHcode;
- uint8_t sizeVal, count0;
- unsigned short int *minCode;
- uint8_t *huffValues;
- uint8_t byteTemp;
-
- minCode = htdc[DC_nr].minorCode;
- // maj_code=htdc[DC_nr].majorCode;
- huffValues = htdc[DC_nr].v;
-
- // DC
- k = htdc[DC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
- // river
- // tmp_Hcode=lookKbits(k);
- tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
- skipKbits(k);
- sizeVal =
- huffValues[wordHiLo(k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
- if (sizeVal == 0) {
- dctCoeff[position + 0] = *previous_DC;
- } else {
- dctCoeff[position + 0] = *previous_DC + getKbits(sizeVal);
- *previous_DC = dctCoeff[position + 0];
- }
-
- // Second, AC coefficient decoding
- minCode = htac[AC_nr].minorCode;
- // maj_code=htac[AC_nr].majorCode;
- huffValues = htac[AC_nr].v;
-
- nr = 1; // AC coefficient
- do {
- k = htac[AC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
- tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
- skipKbits(k);
-
- byteTemp =
- huffValues[wordHiLo(k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
- sizeVal = byteTemp & 0xF;
- count0 = byteTemp >> 4;
- if (sizeVal == 0) {
- if (count0 != 0xF) {
- break;
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>r value is nearest int to 1.597656 * x */
+ /* Cb=>b value is nearest int to 2.015625 * x */
+ /* 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++)
+ {
+ mCrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
+ mCbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
+ mCrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
+ mCbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
}
- nr += 16;
- } else {
- nr += count0; // skip count_0 zeroes
- dctCoeff[position + dezigzag[nr++]] = getKbits(sizeVal);
- }
- } while (nr < 64);
- }
-
- unsigned short int lookKbits(uint8_t k) {
- unsigned short int revcode;
-
- revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
-
- return (revcode);
- }
-
- void skipKbits(uint8_t k) {
- unsigned long readbuf;
-
- if ((newbits - k) <= 0) {
- readbuf = buffer[bufferIndex];
- bufferIndex++;
- codebuf =
- (codebuf << k) | ((newbuf | (readbuf >> (newbits))) >> (32 - k));
- newbuf = readbuf << (k - newbits);
- newbits = 32 + newbits - k;
- } else {
- codebuf = (codebuf << k) | (newbuf >> (32 - k));
- newbuf = newbuf << k;
- newbits -= k;
+ for (i = 0, x = -16; i < 256; i++, x++)
+ {
+ mY[i] = (FIX(1.164) * x + nHalf) >> 16;
+ }
+ // For color Text Enchance Y Re-map. Recommend to disable in default
+ /*
+ for (i = 0; i <
+ (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i++) { temp =
+ (double)i / VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate; temp1
+ = 1.0 / VideoEngineInfo->INFData.Gamma1Parameter; mY[i] =
+ (BYTE)(VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate * pow (temp,
+ temp1));
+ if (mY[i] > 255) mY[i] = 255;
+ }
+ for (i = (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i <
+ 256; i++) { mY[i] =
+ (BYTE)((VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) + (256 -
+ VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) * ( pow((double)((i
+ - VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) / (256 -
+ (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate))), (1.0 /
+ VideoEngineInfo->INFData.Gamma2Parameter)) ));
+ if (mY[i] > 255) mY[i] = 255;
+ }
+ */
}
- }
+ void loadHuffmanTable(HuffmanTable *HT, const unsigned char *nrcode,
+ const unsigned char *value,
+ const unsigned short int *Huff_code)
+ {
+ unsigned char k, j, i;
+ unsigned int code, codeIndex;
- signed short int getKbits(uint8_t k) {
- signed short int signedWordvalue;
+ for (j = 1; j <= 16; j++)
+ {
+ HT->length[j] = nrcode[j];
+ }
+ for (i = 0, k = 1; k <= 16; k++)
+ {
+ for (j = 0; j < HT->length[k]; j++)
+ {
+ HT->v[wordHiLo(k, j)] = value[i];
+ i++;
+ }
+ }
+
+ code = 0;
+ for (k = 1; k <= 16; k++)
+ {
+ HT->minorCode[k] = static_cast<unsigned short int>(code);
+ for (j = 1; j <= HT->length[k]; j++)
+ {
+ code++;
+ }
+ HT->majorCode[k] = static_cast<unsigned short int>(code - 1);
+ code *= 2;
+ if (HT->length[k] == 0)
+ {
+ HT->minorCode[k] = 0xFFFF;
+ HT->majorCode[k] = 0;
+ }
+ }
+
+ HT->len[0] = 2;
+ i = 2;
+
+ for (codeIndex = 1; codeIndex < 65535; codeIndex++)
+ {
+ if (codeIndex < Huff_code[i])
+ {
+ HT->len[codeIndex] =
+ static_cast<unsigned char>(Huff_code[i + 1]);
+ }
+ else
+ {
+ i = i + 2;
+ HT->len[codeIndex] =
+ static_cast<unsigned char>(Huff_code[i + 1]);
+ }
+ }
+ }
+ void initJpgTable()
+ {
+ initColorTable();
+ prepareRangeLimitTable();
+ loadHuffmanTable(&htdc[0], stdDcLuminanceNrcodes, stdDcLuminanceValues,
+ dcLuminanceHuffmancode);
+ loadHuffmanTable(&htac[0], stdAcLuminanceNrcodes, stdAcLuminanceValues,
+ acLuminanceHuffmancode);
+ loadHuffmanTable(&htdc[1], stdDcChrominanceNrcodes,
+ stdDcChrominanceValues, dcChrominanceHuffmancode);
+ loadHuffmanTable(&htac[1], stdAcChrominanceNrcodes,
+ stdAcChrominanceValues, acChrominanceHuffmancode);
+ }
+
+ void prepareRangeLimitTable()
+ /* Allocate and fill in the sample_range_limit table */
+ {
+ int j;
+ rlimitTable = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset((void *)rlimitTable, 0, 256);
+ rlimitTable += 256; /* allow negative subscripts of simple table */
+ /* Main part of "simple" table: limit[x] = x */
+ for (j = 0; j < 256; j++)
+ {
+ rlimitTable[j] = j;
+ }
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (j = 256; j < 640; j++)
+ {
+ rlimitTable[j] = 255;
+ }
+
+ /* Second half of post-IDCT table */
+ memset((void *)(rlimitTable + 640), 0, 384);
+ for (j = 0; j < 128; j++)
+ {
+ rlimitTable[j + 1024] = j;
+ }
+ }
+
+ inline unsigned short int wordHiLo(uint8_t byte_high, uint8_t byte_low)
+ {
+ return (byte_high << 8) + byte_low;
+ }
// river
- // signed_wordvalue=lookKbits(k);
- signedWordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
- if (((1L << (k - 1)) & signedWordvalue) == 0) {
- // neg_pow2 was previously defined as the below. It seemed silly to keep
- // a table of values around for something
- // THat's relatively easy to compute, so it was replaced with the
- // appropriate math
- // signed_wordvalue = signed_wordvalue - (0xFFFF >> (16 - k));
- std::array<signed short int, 17> negPow2 = {
- 0, -1, -3, -7, -15, -31, -63, -127,
- -255, -511, -1023, -2047, -4095, -8191, -16383, -32767};
+ void processHuffmanDataUnit(uint8_t DC_nr, uint8_t AC_nr,
+ signed short int *previous_DC,
+ unsigned short int position)
+ {
+ uint8_t nr = 0;
+ uint8_t k;
+ unsigned short int tmpHcode;
+ uint8_t sizeVal, count0;
+ unsigned short int *minCode;
+ uint8_t *huffValues;
+ uint8_t byteTemp;
- signedWordvalue = signedWordvalue + negPow2[k];
- }
- skipKbits(k);
- return signedWordvalue;
- }
- int initJpgDecoding() {
- bytePos = 0;
- loadQuantTable(qt[0]);
- loadQuantTableCb(qt[1]);
- // Note: Added for Dual-JPEG
- loadAdvanceQuantTable(qt[2]);
- loadAdvanceQuantTableCb(qt[3]);
- return 1;
- }
+ minCode = htdc[DC_nr].minorCode;
+ // maj_code=htdc[DC_nr].majorCode;
+ huffValues = htdc[DC_nr].v;
- void setQuantTable(const uint8_t *basic_table, uint8_t scale_factor,
- 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 = (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]] = static_cast<uint8_t>(temp);
- }
- }
-
- void updatereadbuf(uint32_t *codebuf, uint32_t *newbuf, int walks,
- int *newbits, std::vector<uint32_t> &buffer) {
- unsigned long readbuf;
-
- if ((*newbits - walks) <= 0) {
- readbuf = buffer[bufferIndex];
- bufferIndex++;
- *codebuf = (*codebuf << walks) |
- ((*newbuf | (readbuf >> (*newbits))) >> (32 - walks));
- *newbuf = readbuf << (walks - *newbits);
- *newbits = 32 + *newbits - walks;
- } else {
- *codebuf = (*codebuf << walks) | (*newbuf >> (32 - walks));
- *newbuf = *newbuf << walks;
- *newbits -= walks;
- }
- }
-
- uint32_t decode(std::vector<uint32_t> &bufferVector, unsigned long width,
- unsigned long height, YuvMode yuvmode_in, int ySelector,
- int uvSelector) {
- ColorCache decodeColor;
- if (width != userWidth || height != userHeight || yuvmode_in != yuvmode ||
- ySelector != ySelector || uvSelector != uvSelector) {
- yuvmode = yuvmode_in;
- ySelector = ySelector; // 0-7
- uvSelector = uvSelector; // 0-7
- userHeight = height;
- userWidth = width;
- width = width;
- height = height;
-
- // TODO(ed) Magic number section. Document appropriately
- advanceSelector = 0; // 0-7
- mapping = 0; // 0 or 1
-
- if (yuvmode == YuvMode::YUV420) {
- if ((width % 16) != 0u) {
- width = width + 16 - (width % 16);
+ // DC
+ k = htdc[DC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
+ // river
+ // tmp_Hcode=lookKbits(k);
+ tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
+ skipKbits(k);
+ sizeVal = huffValues[wordHiLo(
+ k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
+ if (sizeVal == 0)
+ {
+ dctCoeff[position + 0] = *previous_DC;
}
- if ((height % 16) != 0u) {
- height = height + 16 - (height % 16);
+ else
+ {
+ dctCoeff[position + 0] = *previous_DC + getKbits(sizeVal);
+ *previous_DC = dctCoeff[position + 0];
}
- } else {
- if ((width % 8) != 0u) {
- width = width + 8 - (width % 8);
- }
- if ((height % 8) != 0u) {
- height = height + 8 - (height % 8);
- }
- }
- initJpgDecoding();
+ // Second, AC coefficient decoding
+ minCode = htac[AC_nr].minorCode;
+ // maj_code=htac[AC_nr].majorCode;
+ huffValues = htac[AC_nr].v;
+
+ nr = 1; // AC coefficient
+ do
+ {
+ k = htac[AC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
+ tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
+ skipKbits(k);
+
+ byteTemp = huffValues[wordHiLo(
+ k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
+ sizeVal = byteTemp & 0xF;
+ count0 = byteTemp >> 4;
+ if (sizeVal == 0)
+ {
+ if (count0 != 0xF)
+ {
+ break;
+ }
+ nr += 16;
+ }
+ else
+ {
+ nr += count0; // skip count_0 zeroes
+ dctCoeff[position + dezigzag[nr++]] = getKbits(sizeVal);
+ }
+ } while (nr < 64);
}
- // TODO(ed) cleanup cruft
- buffer = bufferVector.data();
- codebuf = bufferVector[0];
- newbuf = bufferVector[1];
- bufferIndex = 2;
+ unsigned short int lookKbits(uint8_t k)
+ {
+ unsigned short int revcode;
- txb = tyb = 0;
- newbits = 32;
- dcy = dcCb = dcCr = 0;
+ revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
- static const uint32_t vqHeaderMask = 0x01;
- static const uint32_t vqNoUpdateHeader = 0x00;
- static const uint32_t vqUpdateHeader = 0x01;
- static const int vqNoUpdateLength = 0x03;
- static const int vqUpdateLength = 0x1B;
- static const uint32_t vqIndexMask = 0x03;
- static const uint32_t vqColorMask = 0xFFFFFF;
+ return (revcode);
+ }
- static const int blockAsT2100StartLength = 0x04;
- static const int blockAsT2100SkipLength = 20; // S:1 H:3 X:8 Y:8
+ void skipKbits(uint8_t k)
+ {
+ unsigned long readbuf;
- do {
- auto blockHeader = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
- switch (blockHeader) {
- case JpgBlock::JPEG_NO_SKIP_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0);
- break;
- case JpgBlock::FRAME_END_CODE:
- return 0;
- break;
- case JpgBlock::JPEG_SKIP_CODE:
+ if ((newbits - k) <= 0)
+ {
+ readbuf = buffer[bufferIndex];
+ bufferIndex++;
+ codebuf = (codebuf << k) |
+ ((newbuf | (readbuf >> (newbits))) >> (32 - k));
+ newbuf = readbuf << (k - newbits);
+ newbits = 32 + newbits - k;
+ }
+ else
+ {
+ codebuf = (codebuf << k) | (newbuf >> (32 - k));
+ newbuf = newbuf << k;
+ newbits -= k;
+ }
+ }
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
+ signed short int getKbits(uint8_t k)
+ {
+ signed short int signedWordvalue;
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0);
- break;
- case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 0;
+ // river
+ // signed_wordvalue=lookKbits(k);
+ signedWordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
+ if (((1L << (k - 1)) & signedWordvalue) == 0)
+ {
+ // neg_pow2 was previously defined as the below. It seemed silly to
+ // keep a table of values around for something THat's relatively
+ // easy to compute, so it was replaced with the appropriate math
+ // signed_wordvalue = signed_wordvalue - (0xFFFF >> (16 - k));
+ std::array<signed short int, 17> negPow2 = {
+ 0, -1, -3, -7, -15, -31, -63, -127,
+ -255, -511, -1023, -2047, -4095, -8191, -16383, -32767};
- for (int i = 0; i < 1; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ signedWordvalue = signedWordvalue + negPow2[k];
+ }
+ skipKbits(k);
+ return signedWordvalue;
+ }
+ int initJpgDecoding()
+ {
+ bytePos = 0;
+ loadQuantTable(qt[0]);
+ loadQuantTableCb(qt[1]);
+ // Note: Added for Dual-JPEG
+ loadAdvanceQuantTable(qt[2]);
+ loadAdvanceQuantTableCb(qt[3]);
+ return 1;
+ }
+
+ void setQuantTable(const uint8_t *basic_table, uint8_t scale_factor,
+ 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 = (static_cast<long>(basic_table[i] * 16) / scale_factor);
+ /* limit the values to the valid range */
+ if (temp <= 0L)
+ {
+ temp = 1L;
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
- case JpgBlock::VQ_SKIP_1_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 0;
-
- for (int i = 0; i < 1; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ if (temp > 255L)
+ {
+ temp = 255L; /* limit to baseline range if requested */
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
+ newtable[zigzag[i]] = static_cast<uint8_t>(temp);
+ }
+ }
- case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 1;
+ void updatereadbuf(uint32_t *codebuf, uint32_t *newbuf, int walks,
+ int *newbits, std::vector<uint32_t> &buffer)
+ {
+ unsigned long readbuf;
- for (int i = 0; i < 2; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ if ((*newbits - walks) <= 0)
+ {
+ readbuf = buffer[bufferIndex];
+ bufferIndex++;
+ *codebuf = (*codebuf << walks) |
+ ((*newbuf | (readbuf >> (*newbits))) >> (32 - walks));
+ *newbuf = readbuf << (walks - *newbits);
+ *newbits = 32 + *newbits - walks;
+ }
+ else
+ {
+ *codebuf = (*codebuf << walks) | (*newbuf >> (32 - walks));
+ *newbuf = *newbuf << walks;
+ *newbits -= walks;
+ }
+ }
+
+ uint32_t decode(std::vector<uint32_t> &bufferVector, unsigned long width,
+ unsigned long height, YuvMode yuvmode_in, int ySelector,
+ int uvSelector)
+ {
+ ColorCache decodeColor;
+ if (width != userWidth || height != userHeight ||
+ yuvmode_in != yuvmode || ySelector != ySelector ||
+ uvSelector != uvSelector)
+ {
+ yuvmode = yuvmode_in;
+ ySelector = ySelector; // 0-7
+ uvSelector = uvSelector; // 0-7
+ userHeight = height;
+ userWidth = width;
+ width = width;
+ height = height;
+
+ // TODO(ed) Magic number section. Document appropriately
+ advanceSelector = 0; // 0-7
+ mapping = 0; // 0 or 1
+
+ if (yuvmode == YuvMode::YUV420)
+ {
+ if ((width % 16) != 0u)
+ {
+ width = width + 16 - (width % 16);
+ }
+ if ((height % 16) != 0u)
+ {
+ height = height + 16 - (height % 16);
+ }
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
- case JpgBlock::VQ_SKIP_2_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 1;
-
- for (int i = 0; i < 2; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ else
+ {
+ if ((width % 8) != 0u)
+ {
+ width = width + 8 - (width % 8);
+ }
+ if ((height % 8) != 0u)
+ {
+ height = height + 8 - (height % 8);
+ }
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
- case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 2;
+ initJpgDecoding();
+ }
+ // TODO(ed) cleanup cruft
+ buffer = bufferVector.data();
- for (unsigned char &i : decodeColor.index) {
- i = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[i] = ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ codebuf = bufferVector[0];
+ newbuf = bufferVector[1];
+ bufferIndex = 2;
+
+ txb = tyb = 0;
+ newbits = 32;
+ dcy = dcCb = dcCr = 0;
+
+ static const uint32_t vqHeaderMask = 0x01;
+ static const uint32_t vqNoUpdateHeader = 0x00;
+ static const uint32_t vqUpdateHeader = 0x01;
+ static const int vqNoUpdateLength = 0x03;
+ static const int vqUpdateLength = 0x1B;
+ static const uint32_t vqIndexMask = 0x03;
+ static const uint32_t vqColorMask = 0xFFFFFF;
+
+ static const int blockAsT2100StartLength = 0x04;
+ static const int blockAsT2100SkipLength = 20; // S:1 H:3 X:8 Y:8
+
+ do
+ {
+ auto blockHeader = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
+ switch (blockHeader)
+ {
+ case JpgBlock::JPEG_NO_SKIP_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0);
+ break;
+ case JpgBlock::FRAME_END_CODE:
+ return 0;
+ break;
+ case JpgBlock::JPEG_SKIP_CODE:
+
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0);
+ break;
+ case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 0;
+
+ for (int i = 0; i < 1; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+ case JpgBlock::VQ_SKIP_1_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 0;
+
+ for (int i = 0; i < 1; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+
+ case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 1;
+
+ for (int i = 0; i < 2; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+ case JpgBlock::VQ_SKIP_2_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 1;
+
+ for (int i = 0; i < 2; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+ case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 2;
+
+ for (unsigned char &i : decodeColor.index)
+ {
+ i = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[i] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+
+ case JpgBlock::VQ_SKIP_4_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 2;
+
+ for (unsigned char &i : decodeColor.index)
+ {
+ i = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[i] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+ case JpgBlock::JPEG_SKIP_PASS2_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decompress2Pass(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()),
+ 2);
+
+ break;
+ default:
+ // TODO(ed) propogate errors upstream
+ return -1;
+ break;
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
+ moveBlockIndex();
- break;
+ } while (bufferIndex <= bufferVector.size());
- case JpgBlock::VQ_SKIP_4_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 2;
-
- for (unsigned char &i : decodeColor.index) {
- i = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[i] = ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
- }
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
-
- break;
- case JpgBlock::JPEG_SKIP_PASS2_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decompress2Pass(txb, tyb, reinterpret_cast<char *>(outBuffer.data()),
- 2);
-
- break;
- default:
- // TODO(ed) propogate errors upstream
- return -1;
- break;
- }
- moveBlockIndex();
-
- } while (bufferIndex <= bufferVector.size());
-
- return -1;
- }
+ return -1;
+ }
#ifdef cimg_version
- void dump_to_bitmap_file() {
- cimg_library::CImg<unsigned char> image(width, height, 1, 3);
- for (int y = 0; y < width; y++) {
- for (int x = 0; x < height; x++) {
- auto pixel = outBuffer[x + (y * width)];
- image(x, y, 0) = pixel.r;
- image(x, y, 1) = pixel.g;
- image(x, y, 2) = pixel.b;
- }
+ void dump_to_bitmap_file()
+ {
+ cimg_library::CImg<unsigned char> image(width, height, 1, 3);
+ for (int y = 0; y < width; y++)
+ {
+ for (int x = 0; x < height; x++)
+ {
+ auto pixel = outBuffer[x + (y * width)];
+ image(x, y, 0) = pixel.r;
+ image(x, y, 1) = pixel.g;
+ image(x, y, 2) = pixel.b;
+ }
+ }
+ image.save("/tmp/file2.bmp");
}
- image.save("/tmp/file2.bmp");
- }
#endif
- private:
- YuvMode yuvmode{};
- // width and height are the modes your display used
- unsigned long width{};
- unsigned long height{};
- unsigned long userWidth{};
- unsigned long userHeight{};
- unsigned char ySelector{};
- int scalefactor;
- int scalefactoruv;
- int advancescalefactor;
- int advancescalefactoruv;
- int mapping{};
- unsigned char uvSelector{};
- unsigned char advanceSelector{};
- int bytePos{}; // current byte position
+ private:
+ YuvMode yuvmode{};
+ // width and height are the modes your display used
+ unsigned long width{};
+ unsigned long height{};
+ unsigned long userWidth{};
+ unsigned long userHeight{};
+ unsigned char ySelector{};
+ int scalefactor;
+ int scalefactoruv;
+ int advancescalefactor;
+ int advancescalefactoruv;
+ int mapping{};
+ unsigned char uvSelector{};
+ unsigned char advanceSelector{};
+ int bytePos{}; // current byte position
- // quantization tables, no more than 4 quantization tables
- std::array<std::array<long, 64>, 4> qt{};
+ // quantization tables, no more than 4 quantization tables
+ std::array<std::array<long, 64>, 4> qt{};
- // DC huffman tables , no more than 4 (0..3)
- std::array<HuffmanTable, 4> htdc{};
- // AC huffman tables (0..3)
- std::array<HuffmanTable, 4> htac{};
- std::array<int, 256> mCrToR{};
- std::array<int, 256> mCbToB{};
- std::array<int, 256> mCrToG{};
- std::array<int, 256> mCbToG{};
- std::array<int, 256> mY{};
- unsigned long bufferIndex{};
- uint32_t codebuf{}, newbuf{}, readbuf{};
- const unsigned char *stdLuminanceQt{};
- const uint8_t *stdChrominanceQt{};
+ // DC huffman tables , no more than 4 (0..3)
+ std::array<HuffmanTable, 4> htdc{};
+ // AC huffman tables (0..3)
+ std::array<HuffmanTable, 4> htac{};
+ std::array<int, 256> mCrToR{};
+ std::array<int, 256> mCbToB{};
+ std::array<int, 256> mCrToG{};
+ std::array<int, 256> mCbToG{};
+ std::array<int, 256> mY{};
+ unsigned long bufferIndex{};
+ uint32_t codebuf{}, newbuf{}, readbuf{};
+ const unsigned char *stdLuminanceQt{};
+ const uint8_t *stdChrominanceQt{};
- signed short int dcy{}, dcCb{}, dcCr{}; // Coeficientii DC pentru Y,Cb,Cr
- signed short int dctCoeff[384]{};
- // std::vector<signed short int> dctCoeff; // Current DCT_coefficients
- // quantization table number for Y, Cb, Cr
- uint8_t yqNr = 0, cbQNr = 1, crQNr = 1;
- // DC Huffman table number for Y,Cb, Cr
- uint8_t ydcNr = 0, cbDcNr = 1, crDcNr = 1;
- // AC Huffman table number for Y,Cb, Cr
- uint8_t yacNr = 0, cbAcNr = 1, crAcNr = 1;
- int txb = 0;
- int tyb = 0;
- int newbits{};
- uint8_t *rlimitTable{};
- std::vector<RGB> yuvBuffer;
- // TODO(ed) this shouldn't exist. It is cruft that needs cleaning up
- uint32_t *buffer{};
+ signed short int dcy{}, dcCb{}, dcCr{}; // Coeficientii DC pentru Y,Cb,Cr
+ signed short int dctCoeff[384]{};
+ // std::vector<signed short int> dctCoeff; // Current DCT_coefficients
+ // quantization table number for Y, Cb, Cr
+ uint8_t yqNr = 0, cbQNr = 1, crQNr = 1;
+ // DC Huffman table number for Y,Cb, Cr
+ uint8_t ydcNr = 0, cbDcNr = 1, crDcNr = 1;
+ // AC Huffman table number for Y,Cb, Cr
+ uint8_t yacNr = 0, cbAcNr = 1, crAcNr = 1;
+ int txb = 0;
+ int tyb = 0;
+ int newbits{};
+ uint8_t *rlimitTable{};
+ std::vector<RGB> yuvBuffer;
+ // TODO(ed) this shouldn't exist. It is cruft that needs cleaning up
+ uint32_t *buffer{};
- public:
- std::vector<RGB> outBuffer;
+ public:
+ std::vector<RGB> outBuffer;
};
-} // namespace ast_video
\ No newline at end of file
+} // namespace ast_video
\ No newline at end of file
diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp
index c2ccea2..520fc68 100644
--- a/include/ast_video_puller.hpp
+++ b/include/ast_video_puller.hpp
@@ -1,186 +1,212 @@
#pragma once
#include <ast_video_types.hpp>
+#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <mutex>
#include <vector>
-#include <boost/asio.hpp>
-namespace ast_video {
+namespace ast_video
+{
//
// Cursor struct is used in User Mode
//
-struct AstCurAttributionTag {
- unsigned int posX;
- unsigned int posY;
- unsigned int curWidth;
- unsigned int curHeight;
- unsigned int curType; // 0:mono 1:color 2:disappear cursor
- unsigned int curChangeFlag;
+struct AstCurAttributionTag
+{
+ unsigned int posX;
+ unsigned int posY;
+ unsigned int curWidth;
+ unsigned int curHeight;
+ unsigned int curType; // 0:mono 1:color 2:disappear cursor
+ unsigned int curChangeFlag;
};
//
// For storing Cursor Information
//
-struct AstCursorTag {
- AstCurAttributionTag attr;
- // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2];
- unsigned char *icon; //[64*64*2];
+struct AstCursorTag
+{
+ AstCurAttributionTag attr;
+ // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2];
+ unsigned char *icon; //[64*64*2];
};
//
// For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0
// ~ 11, low to high
//
-struct FeaturesTag {
- short jpgFmt; // 422:JPG420, 444:JPG444
- short luminTbl;
- short chromTbl;
- short toleranceNoise;
- int w;
- int h;
- unsigned char *buf;
+struct FeaturesTag
+{
+ short jpgFmt; // 422:JPG420, 444:JPG444
+ short luminTbl;
+ short chromTbl;
+ short toleranceNoise;
+ int w;
+ int h;
+ unsigned char *buf;
};
//
// For configure video engine control registers
//
-struct ImageInfo {
- short doImageRefresh; // Action 0:motion 1:fullframe 2:quick cursor
- char qcValid; // quick cursor enable/disable
- unsigned int len;
- int crypttype;
- char cryptkey[16];
- union {
- FeaturesTag features;
- AstCursorTag cursorInfo;
- } parameter;
+struct ImageInfo
+{
+ short doImageRefresh; // Action 0:motion 1:fullframe 2:quick cursor
+ char qcValid; // quick cursor enable/disable
+ unsigned int len;
+ int crypttype;
+ char cryptkey[16];
+ union
+ {
+ FeaturesTag features;
+ AstCursorTag cursorInfo;
+ } parameter;
};
-class SimpleVideoPuller {
- public:
- SimpleVideoPuller() : imageInfo(){};
+class SimpleVideoPuller
+{
+ public:
+ SimpleVideoPuller() : imageInfo(){};
- void initialize() {
- std::cout << "Opening /dev/video\n";
- videoFd = open("/dev/video", O_RDWR);
- if (videoFd == 0) {
- std::cout << "Failed to open /dev/video\n";
- throw std::runtime_error("Failed to open /dev/video");
- }
- std::cout << "Opened successfully\n";
- }
-
- RawVideoBuffer readVideo() {
- assert(videoFd != 0);
- RawVideoBuffer raw;
-
- imageInfo.doImageRefresh = 1; // full frame refresh
- imageInfo.qcValid = 0; // quick cursor disabled
- imageInfo.parameter.features.buf =
- reinterpret_cast<unsigned char *>(raw.buffer.data());
- imageInfo.crypttype = -1;
- std::cout << "Writing\n";
-
- int status;
- /*
- status = write(videoFd, reinterpret_cast<char*>(&imageInfo),
- sizeof(imageInfo));
- if (status != sizeof(imageInfo)) {
- std::cout << "Write failed. Return: " << status << "\n";
- perror("perror output:");
+ void initialize()
+ {
+ std::cout << "Opening /dev/video\n";
+ videoFd = open("/dev/video", O_RDWR);
+ if (videoFd == 0)
+ {
+ std::cout << "Failed to open /dev/video\n";
+ throw std::runtime_error("Failed to open /dev/video");
+ }
+ std::cout << "Opened successfully\n";
}
- std::cout << "Write done\n";
- */
- std::cout << "Reading\n";
- status =
- read(videoFd, reinterpret_cast<char *>(&imageInfo), sizeof(imageInfo));
- std::cout << "Done reading\n";
+ RawVideoBuffer readVideo()
+ {
+ assert(videoFd != 0);
+ RawVideoBuffer raw;
- if (status != 0) {
- std::cerr << "Read failed with status " << status << "\n";
+ imageInfo.doImageRefresh = 1; // full frame refresh
+ imageInfo.qcValid = 0; // quick cursor disabled
+ imageInfo.parameter.features.buf =
+ reinterpret_cast<unsigned char *>(raw.buffer.data());
+ imageInfo.crypttype = -1;
+ std::cout << "Writing\n";
+
+ int status;
+ /*
+ status = write(videoFd, reinterpret_cast<char*>(&imageInfo),
+ sizeof(imageInfo));
+ if (status != sizeof(imageInfo)) {
+ std::cout << "Write failed. Return: " << status << "\n";
+ perror("perror output:");
+ }
+
+ std::cout << "Write done\n";
+ */
+ std::cout << "Reading\n";
+ status = read(videoFd, reinterpret_cast<char *>(&imageInfo),
+ sizeof(imageInfo));
+ std::cout << "Done reading\n";
+
+ if (status != 0)
+ {
+ std::cerr << "Read failed with status " << status << "\n";
+ }
+
+ raw.buffer.resize(imageInfo.len);
+
+ raw.height = imageInfo.parameter.features.h;
+ raw.width = imageInfo.parameter.features.w;
+ if (imageInfo.parameter.features.jpgFmt == 422)
+ {
+ raw.mode = YuvMode::YUV420;
+ }
+ else
+ {
+ raw.mode = YuvMode::YUV444;
+ }
+ return raw;
}
- raw.buffer.resize(imageInfo.len);
-
- raw.height = imageInfo.parameter.features.h;
- raw.width = imageInfo.parameter.features.w;
- if (imageInfo.parameter.features.jpgFmt == 422) {
- raw.mode = YuvMode::YUV420;
- } else {
- raw.mode = YuvMode::YUV444;
- }
- return raw;
- }
-
- private:
- int videoFd{};
- ImageInfo imageInfo;
+ private:
+ int videoFd{};
+ ImageInfo imageInfo;
};
#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
-class AsyncVideoPuller {
- public:
- using video_callback = std::function<void(RawVideoBuffer &)>;
+class AsyncVideoPuller
+{
+ public:
+ using video_callback = std::function<void(RawVideoBuffer &)>;
- explicit AsyncVideoPuller(boost::asio::io_service &ioService)
- : imageInfo(), devVideo(ioService, open("/dev/video", O_RDWR)) {
- videobuf = std::make_shared<RawVideoBuffer>();
+ explicit AsyncVideoPuller(boost::asio::io_service &ioService) :
+ imageInfo(), devVideo(ioService, open("/dev/video", O_RDWR))
+ {
+ videobuf = std::make_shared<RawVideoBuffer>();
- imageInfo.doImageRefresh = 1; // full frame refresh
- imageInfo.qcValid = 0; // quick cursor disabled
- imageInfo.parameter.features.buf =
- reinterpret_cast<unsigned char *>(videobuf->buffer.data());
- imageInfo.crypttype = -1;
- };
+ imageInfo.doImageRefresh = 1; // full frame refresh
+ imageInfo.qcValid = 0; // quick cursor disabled
+ imageInfo.parameter.features.buf =
+ reinterpret_cast<unsigned char *>(videobuf->buffer.data());
+ imageInfo.crypttype = -1;
+ };
- void registerCallback(video_callback &callback) {
- std::lock_guard<std::mutex> lock(callbackMutex);
- callbacks.push_back(callback);
- startRead();
- }
-
- void startRead() {
- auto mutableBuffer = boost::asio::buffer(&imageInfo, sizeof(imageInfo));
- boost::asio::async_read(devVideo, mutableBuffer,
- [this](const boost::system::error_code &ec,
- std::size_t bytes_transferred) {
- if (ec) {
- std::cerr << "Read failed with status " << ec
- << "\n";
- } else {
- this->readDone();
- }
- });
- }
-
- void readDone() {
- std::cout << "Done reading\n";
- videobuf->buffer.resize(imageInfo.len);
-
- videobuf->height = imageInfo.parameter.features.h;
- videobuf->width = imageInfo.parameter.features.w;
- if (imageInfo.parameter.features.jpgFmt == 422) {
- videobuf->mode = YuvMode::YUV420;
- } else {
- videobuf->mode = YuvMode::YUV444;
+ void registerCallback(video_callback &callback)
+ {
+ std::lock_guard<std::mutex> lock(callbackMutex);
+ callbacks.push_back(callback);
+ startRead();
}
- std::lock_guard<std::mutex> lock(callbackMutex);
- for (auto &callback : callbacks) {
- // TODO(ed) call callbacks async and double buffer frames
- callback(*videobuf);
- }
- }
- private:
- std::shared_ptr<RawVideoBuffer> videobuf;
- boost::asio::posix::stream_descriptor devVideo;
- ImageInfo imageInfo;
- std::mutex callbackMutex;
- std::vector<video_callback> callbacks;
+ void startRead()
+ {
+ auto mutableBuffer = boost::asio::buffer(&imageInfo, sizeof(imageInfo));
+ boost::asio::async_read(devVideo, mutableBuffer,
+ [this](const boost::system::error_code &ec,
+ std::size_t bytes_transferred) {
+ if (ec)
+ {
+ std::cerr << "Read failed with status "
+ << ec << "\n";
+ }
+ else
+ {
+ this->readDone();
+ }
+ });
+ }
+
+ void readDone()
+ {
+ std::cout << "Done reading\n";
+ videobuf->buffer.resize(imageInfo.len);
+
+ videobuf->height = imageInfo.parameter.features.h;
+ videobuf->width = imageInfo.parameter.features.w;
+ if (imageInfo.parameter.features.jpgFmt == 422)
+ {
+ videobuf->mode = YuvMode::YUV420;
+ }
+ else
+ {
+ videobuf->mode = YuvMode::YUV444;
+ }
+ std::lock_guard<std::mutex> lock(callbackMutex);
+ for (auto &callback : callbacks)
+ {
+ // TODO(ed) call callbacks async and double buffer frames
+ callback(*videobuf);
+ }
+ }
+
+ private:
+ std::shared_ptr<RawVideoBuffer> videobuf;
+ boost::asio::posix::stream_descriptor devVideo;
+ ImageInfo imageInfo;
+ std::mutex callbackMutex;
+ std::vector<video_callback> callbacks;
};
-#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
-} // namespace ast_video
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+} // namespace ast_video
diff --git a/include/ast_video_types.hpp b/include/ast_video_types.hpp
index f980146..aeef1d8 100644
--- a/include/ast_video_types.hpp
+++ b/include/ast_video_types.hpp
@@ -2,18 +2,24 @@
#include <cstdint>
#include <vector>
-namespace ast_video {
-enum class YuvMode { YUV444 = 0, YUV420 = 1 };
-
-class RawVideoBuffer {
- public:
- RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){};
- unsigned long height{};
- unsigned long width{};
- int ySelector{};
- int uvSelector{};
- YuvMode mode;
- // TODO(ed) determine a more appropriate buffer size
- std::vector<uint32_t> buffer;
+namespace ast_video
+{
+enum class YuvMode
+{
+ YUV444 = 0,
+ YUV420 = 1
};
-} // namespace ast_video
\ No newline at end of file
+
+class RawVideoBuffer
+{
+ public:
+ RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){};
+ unsigned long height{};
+ unsigned long width{};
+ int ySelector{};
+ int uvSelector{};
+ YuvMode mode;
+ // TODO(ed) determine a more appropriate buffer size
+ std::vector<uint32_t> buffer;
+};
+} // namespace ast_video
\ No newline at end of file
diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp
index e8b1a32..5dcd5ca 100644
--- a/include/dbus_monitor.hpp
+++ b/include/dbus_monitor.hpp
@@ -1,26 +1,33 @@
#pragma once
-#include <dbus_singleton.hpp>
-#include <sdbusplus/bus/match.hpp>
#include <crow/app.h>
#include <crow/websocket.h>
+
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
+#include <dbus_singleton.hpp>
+#include <sdbusplus/bus/match.hpp>
-namespace nlohmann {
+namespace nlohmann
+{
template <typename... Args>
-struct adl_serializer<sdbusplus::message::variant<Args...>> {
- static void to_json(json& j, const sdbusplus::message::variant<Args...>& v) {
- mapbox::util::apply_visitor([&](auto&& val) { j = val; }, v);
- }
+struct adl_serializer<sdbusplus::message::variant<Args...>>
+{
+ static void to_json(json& j, const sdbusplus::message::variant<Args...>& v)
+ {
+ mapbox::util::apply_visitor([&](auto&& val) { j = val; }, v);
+ }
};
-} // namespace nlohmann
+} // namespace nlohmann
-namespace crow {
-namespace dbus_monitor {
+namespace crow
+{
+namespace dbus_monitor
+{
-struct DbusWebsocketSession {
- std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
- boost::container::flat_set<std::string> interfaces;
+struct DbusWebsocketSession
+{
+ std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
+ boost::container::flat_set<std::string> interfaces;
};
static boost::container::flat_map<crow::websocket::Connection*,
@@ -28,165 +35,198 @@
sessions;
inline int onPropertyUpdate(sd_bus_message* m, void* userdata,
- sd_bus_error* ret_error) {
- if (ret_error == nullptr || sd_bus_error_is_set(ret_error)) {
- BMCWEB_LOG_ERROR << "Got sdbus error on match";
- return 0;
- }
- crow::websocket::Connection* connection =
- static_cast<crow::websocket::Connection*>(userdata);
- auto thisSession = sessions.find(connection);
- if (thisSession == sessions.end()) {
- BMCWEB_LOG_ERROR << "Couldn't find dbus connection " << connection;
- return 0;
- }
- sdbusplus::message::message message(m);
- using VariantType =
- sdbusplus::message::variant<std::string, bool, int64_t, uint64_t, double>;
- nlohmann::json j{{"event", message.get_member()},
- {"path", message.get_path()}};
- if (strcmp(message.get_member(), "PropertiesChanged") == 0) {
- std::string interface_name;
- boost::container::flat_map<std::string, VariantType> values;
- message.read(interface_name, values);
- j["properties"] = values;
- j["interface"] = std::move(interface_name);
-
- } else if (strcmp(message.get_member(), "InterfacesAdded") == 0) {
- std::string object_name;
- boost::container::flat_map<
- std::string, boost::container::flat_map<std::string, VariantType>>
- values;
- message.read(object_name, values);
- for (const std::pair<std::string,
- boost::container::flat_map<std::string, VariantType>>&
- paths : values) {
- auto it = thisSession->second.interfaces.find(paths.first);
- if (it != thisSession->second.interfaces.end()) {
- j["interfaces"][paths.first] = paths.second;
- }
+ sd_bus_error* ret_error)
+{
+ if (ret_error == nullptr || sd_bus_error_is_set(ret_error))
+ {
+ BMCWEB_LOG_ERROR << "Got sdbus error on match";
+ return 0;
}
- } else {
- BMCWEB_LOG_CRITICAL << "message " << message.get_member()
- << " was unexpected";
- return 0;
- }
+ crow::websocket::Connection* connection =
+ static_cast<crow::websocket::Connection*>(userdata);
+ auto thisSession = sessions.find(connection);
+ if (thisSession == sessions.end())
+ {
+ BMCWEB_LOG_ERROR << "Couldn't find dbus connection " << connection;
+ return 0;
+ }
+ sdbusplus::message::message message(m);
+ using VariantType = sdbusplus::message::variant<std::string, bool, int64_t,
+ uint64_t, double>;
+ nlohmann::json j{{"event", message.get_member()},
+ {"path", message.get_path()}};
+ if (strcmp(message.get_member(), "PropertiesChanged") == 0)
+ {
+ std::string interface_name;
+ boost::container::flat_map<std::string, VariantType> values;
+ message.read(interface_name, values);
+ j["properties"] = values;
+ j["interface"] = std::move(interface_name);
+ }
+ else if (strcmp(message.get_member(), "InterfacesAdded") == 0)
+ {
+ std::string object_name;
+ boost::container::flat_map<
+ std::string, boost::container::flat_map<std::string, VariantType>>
+ values;
+ message.read(object_name, values);
+ for (const std::pair<
+ std::string,
+ boost::container::flat_map<std::string, VariantType>>& paths :
+ values)
+ {
+ auto it = thisSession->second.interfaces.find(paths.first);
+ if (it != thisSession->second.interfaces.end())
+ {
+ j["interfaces"][paths.first] = paths.second;
+ }
+ }
+ }
+ else
+ {
+ BMCWEB_LOG_CRITICAL << "message " << message.get_member()
+ << " was unexpected";
+ return 0;
+ }
- connection->sendText(j.dump());
- return 0;
+ connection->sendText(j.dump());
+ return 0;
};
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/subscribe")
- .websocket()
- .onopen([&](crow::websocket::Connection& conn) {
- BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
- sessions[&conn] = DbusWebsocketSession();
- })
- .onclose([&](crow::websocket::Connection& conn,
- const std::string& reason) { sessions.erase(&conn); })
- .onmessage([&](crow::websocket::Connection& conn, const std::string& data,
- bool is_binary) {
- DbusWebsocketSession& thisSession = sessions[&conn];
- BMCWEB_LOG_DEBUG << "Connection " << &conn << " recevied " << data;
- nlohmann::json j = nlohmann::json::parse(data, nullptr, false);
- if (j.is_discarded()) {
- BMCWEB_LOG_ERROR << "Unable to parse json data for monitor";
- conn.close("Unable to parse json request");
- return;
- }
- nlohmann::json::iterator interfaces = j.find("interfaces");
- if (interfaces != j.end()) {
- thisSession.interfaces.reserve(interfaces->size());
- for (auto& interface : *interfaces) {
- const std::string* str = interface.get_ptr<const std::string*>();
- if (str != nullptr) {
- thisSession.interfaces.insert(*str);
- }
- }
- }
-
- nlohmann::json::iterator paths = j.find("paths");
- if (paths != j.end()) {
- int interfaceCount = thisSession.interfaces.size();
- if (interfaceCount == 0) {
- interfaceCount = 1;
- }
- // Reserve our matches upfront. For each path there is 1 for
- // interfacesAdded, and InterfaceCount number for PropertiesChanged
- thisSession.matches.reserve(thisSession.matches.size() +
- paths->size() * (1 + interfaceCount));
- }
- std::string object_manager_match_string;
- std::string properties_match_string;
- std::string object_manager_interfaces_match_string;
- // These regexes derived on the rules here:
- // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
- std::regex validPath("^/([A-Za-z0-9_]+/?)*$");
- std::regex validInterface(
- "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+$");
-
- for (const auto& thisPath : *paths) {
- const std::string* thisPathString =
- thisPath.get_ptr<const std::string*>();
- if (thisPathString == nullptr) {
- BMCWEB_LOG_ERROR << "subscribe path isn't a string?";
- conn.close();
- return;
- }
- if (!std::regex_match(*thisPathString, validPath)) {
- BMCWEB_LOG_ERROR << "Invalid path name " << *thisPathString;
- conn.close();
- return;
- }
- properties_match_string =
- ("type='signal',"
- "interface='org.freedesktop.DBus.Properties',"
- "path_namespace='" +
- *thisPathString +
- "',"
- "member='PropertiesChanged'");
- // If interfaces weren't specified, add a single match for all
- // interfaces
- if (thisSession.interfaces.size() == 0) {
- BMCWEB_LOG_DEBUG << "Creating match " << properties_match_string;
-
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, properties_match_string,
- onPropertyUpdate, &conn));
- } else {
- // If interfaces were specified, add a match for each interface
- for (const std::string& interface : thisSession.interfaces) {
- if (!std::regex_match(interface, validInterface)) {
- BMCWEB_LOG_ERROR << "Invalid interface name " << interface;
- conn.close();
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/subscribe")
+ .websocket()
+ .onopen([&](crow::websocket::Connection& conn) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+ sessions[&conn] = DbusWebsocketSession();
+ })
+ .onclose([&](crow::websocket::Connection& conn,
+ const std::string& reason) { sessions.erase(&conn); })
+ .onmessage([&](crow::websocket::Connection& conn,
+ const std::string& data, bool is_binary) {
+ DbusWebsocketSession& thisSession = sessions[&conn];
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " recevied " << data;
+ nlohmann::json j = nlohmann::json::parse(data, nullptr, false);
+ if (j.is_discarded())
+ {
+ BMCWEB_LOG_ERROR << "Unable to parse json data for monitor";
+ conn.close("Unable to parse json request");
return;
- }
- std::string ifaceMatchString =
- properties_match_string + ",arg0='" + interface + "'";
- BMCWEB_LOG_DEBUG << "Creating match " << ifaceMatchString;
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, ifaceMatchString,
- onPropertyUpdate, &conn));
}
- }
- object_manager_match_string =
- ("type='signal',"
- "interface='org.freedesktop.DBus.ObjectManager',"
- "path_namespace='" +
- *thisPathString +
- "',"
- "member='InterfacesAdded'");
- BMCWEB_LOG_DEBUG << "Creating match " << object_manager_match_string;
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, object_manager_match_string,
- onPropertyUpdate, &conn));
- }
- });
+ nlohmann::json::iterator interfaces = j.find("interfaces");
+ if (interfaces != j.end())
+ {
+ thisSession.interfaces.reserve(interfaces->size());
+ for (auto& interface : *interfaces)
+ {
+ const std::string* str =
+ interface.get_ptr<const std::string*>();
+ if (str != nullptr)
+ {
+ thisSession.interfaces.insert(*str);
+ }
+ }
+ }
+
+ nlohmann::json::iterator paths = j.find("paths");
+ if (paths != j.end())
+ {
+ int interfaceCount = thisSession.interfaces.size();
+ if (interfaceCount == 0)
+ {
+ interfaceCount = 1;
+ }
+ // Reserve our matches upfront. For each path there is 1 for
+ // interfacesAdded, and InterfaceCount number for
+ // PropertiesChanged
+ thisSession.matches.reserve(thisSession.matches.size() +
+ paths->size() *
+ (1 + interfaceCount));
+ }
+ std::string object_manager_match_string;
+ std::string properties_match_string;
+ std::string object_manager_interfaces_match_string;
+ // These regexes derived on the rules here:
+ // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
+ std::regex validPath("^/([A-Za-z0-9_]+/?)*$");
+ std::regex validInterface(
+ "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+$");
+
+ for (const auto& thisPath : *paths)
+ {
+ const std::string* thisPathString =
+ thisPath.get_ptr<const std::string*>();
+ if (thisPathString == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "subscribe path isn't a string?";
+ conn.close();
+ return;
+ }
+ if (!std::regex_match(*thisPathString, validPath))
+ {
+ BMCWEB_LOG_ERROR << "Invalid path name " << *thisPathString;
+ conn.close();
+ return;
+ }
+ properties_match_string =
+ ("type='signal',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "path_namespace='" +
+ *thisPathString +
+ "',"
+ "member='PropertiesChanged'");
+ // If interfaces weren't specified, add a single match for all
+ // interfaces
+ if (thisSession.interfaces.size() == 0)
+ {
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << properties_match_string;
+
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ properties_match_string, onPropertyUpdate, &conn));
+ }
+ else
+ {
+ // If interfaces were specified, add a match for each
+ // interface
+ for (const std::string& interface : thisSession.interfaces)
+ {
+ if (!std::regex_match(interface, validInterface))
+ {
+ BMCWEB_LOG_ERROR << "Invalid interface name "
+ << interface;
+ conn.close();
+ return;
+ }
+ std::string ifaceMatchString = properties_match_string +
+ ",arg0='" + interface +
+ "'";
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << ifaceMatchString;
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus, ifaceMatchString,
+ onPropertyUpdate, &conn));
+ }
+ }
+ object_manager_match_string =
+ ("type='signal',"
+ "interface='org.freedesktop.DBus.ObjectManager',"
+ "path_namespace='" +
+ *thisPathString +
+ "',"
+ "member='InterfacesAdded'");
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << object_manager_match_string;
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ object_manager_match_string, onPropertyUpdate, &conn));
+ }
+ });
}
-} // namespace dbus_monitor
-} // namespace crow
+} // namespace dbus_monitor
+} // namespace crow
diff --git a/include/dbus_singleton.hpp b/include/dbus_singleton.hpp
index a4a16bb..2438152 100644
--- a/include/dbus_singleton.hpp
+++ b/include/dbus_singleton.hpp
@@ -1,21 +1,28 @@
#pragma once
-#include <sdbusplus/asio/connection.hpp>
#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
-namespace mapbox {
+namespace mapbox
+{
template <typename T, typename... Types>
-const T* getPtr(const mapbox::util::variant<Types...>& v) {
- if (v.template is<std::remove_const_t<T>>()) {
- return &v.template get_unchecked<std::remove_const_t<T>>();
- } else {
- return nullptr;
- }
+const T* getPtr(const mapbox::util::variant<Types...>& v)
+{
+ if (v.template is<std::remove_const_t<T>>())
+ {
+ return &v.template get_unchecked<std::remove_const_t<T>>();
+ }
+ else
+ {
+ return nullptr;
+ }
}
-} // namespace mapbox
+} // namespace mapbox
-namespace crow {
-namespace connections {
+namespace crow
+{
+namespace connections
+{
static std::shared_ptr<sdbusplus::asio::connection> systemBus;
-} // namespace connections
-} // namespace crow
+} // namespace connections
+} // namespace crow
diff --git a/include/gzip_helper.hpp b/include/gzip_helper.hpp
index e14fc1b..be13809 100644
--- a/include/gzip_helper.hpp
+++ b/include/gzip_helper.hpp
@@ -1,56 +1,65 @@
#pragma once
#include <zlib.h>
+
#include <cstring>
#include <string>
inline bool gzipInflate(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);
+ std::string& uncompressedBytes)
+{
+ if (compressedBytes.empty())
+ {
+ uncompressedBytes = compressedBytes;
+ return true;
}
- strm.next_out =
- (Bytef*)(uncompressedBytes.data() + strm.total_out); // NOLINT
- strm.avail_out =
- ((uLong)uncompressedBytes.size() - strm.total_out); // NOLINT
+ uncompressedBytes.clear();
- // Inflate another chunk.
- int err = inflate(&strm, Z_SYNC_FLUSH);
- if (err == Z_STREAM_END) {
- done = true;
- } else if (err != Z_OK) {
- break;
+ 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;
}
- }
- return inflateEnd(&strm) == Z_OK;
+ 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/http_utility.hpp b/include/http_utility.hpp
index f2d3172..e13dfc0 100644
--- a/include/http_utility.hpp
+++ b/include/http_utility.hpp
@@ -1,21 +1,27 @@
#pragma once
#include <boost/algorithm/string.hpp>
-namespace http_helpers {
-inline bool requestPrefersHtml(const crow::Request& req) {
- boost::string_view header = req.getHeaderValue("accept");
- std::vector<std::string> encodings;
- // chrome currently sends 6 accepts headers, firefox sends 4.
- encodings.reserve(6);
- boost::split(encodings, header, boost::is_any_of(", "),
- boost::token_compress_on);
- for (const std::string& encoding : encodings) {
- if (encoding == "text/html") {
- return true;
- } else if (encoding == "application/json") {
- return false;
+namespace http_helpers
+{
+inline bool requestPrefersHtml(const crow::Request& req)
+{
+ boost::string_view header = req.getHeaderValue("accept");
+ std::vector<std::string> encodings;
+ // chrome currently sends 6 accepts headers, firefox sends 4.
+ encodings.reserve(6);
+ boost::split(encodings, header, boost::is_any_of(", "),
+ boost::token_compress_on);
+ for (const std::string& encoding : encodings)
+ {
+ if (encoding == "text/html")
+ {
+ return true;
+ }
+ else if (encoding == "application/json")
+ {
+ return false;
+ }
}
- }
- return false;
+ return false;
}
-} // namespace http_helpers
\ No newline at end of file
+} // namespace http_helpers
\ No newline at end of file
diff --git a/include/image_upload.hpp b/include/image_upload.hpp
index df5c1ae..2b84db8 100644
--- a/include/image_upload.hpp
+++ b/include/image_upload.hpp
@@ -1,103 +1,113 @@
#pragma once
-#include <dbus_singleton.hpp>
-#include <cstdio>
-#include <fstream>
-#include <memory>
#include <crow/app.h>
+
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <cstdio>
+#include <dbus_singleton.hpp>
+#include <fstream>
+#include <memory>
-namespace crow {
-namespace image_upload {
+namespace crow
+{
+namespace image_upload
+{
std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
inline void uploadImageHandler(const crow::Request& req, crow::Response& res,
- const std::string& filename) {
- // Only allow one FW update at a time
- if (fwUpdateMatcher != nullptr) {
- res.addHeader("Retry-After", "30");
- res.result(boost::beast::http::status::service_unavailable);
- res.end();
- return;
- }
- // Make this const static so it survives outside this method
- static boost::asio::deadline_timer timeout(*req.ioService,
- boost::posix_time::seconds(5));
-
- timeout.expires_from_now(boost::posix_time::seconds(5));
-
- timeout.async_wait([&res](const boost::system::error_code& ec) {
- fwUpdateMatcher = nullptr;
- if (ec == asio::error::operation_aborted) {
- // expected, we were canceled before the timer completed.
- return;
- }
- BMCWEB_LOG_ERROR << "Timed out waiting for log event";
-
- if (ec) {
- BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
- return;
- }
-
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- });
-
- std::function<void(sdbusplus::message::message&)> callback =
- [&res](sdbusplus::message::message& m) {
- BMCWEB_LOG_DEBUG << "Match fired";
- boost::system::error_code ec;
- timeout.cancel(ec);
- if (ec) {
- BMCWEB_LOG_ERROR << "error canceling timer " << ec;
- }
- std::string versionInfo;
- m.read(versionInfo); // Read in the object path that was just created
-
- std::size_t index = versionInfo.rfind('/');
- if (index != std::string::npos) {
- versionInfo.erase(0, index);
- }
- res.jsonValue = {{"data", std::move(versionInfo)},
- {"message", "200 OK"},
- {"status", "ok"}};
- BMCWEB_LOG_DEBUG << "ending response";
+ const std::string& filename)
+{
+ // Only allow one FW update at a time
+ if (fwUpdateMatcher != nullptr)
+ {
+ res.addHeader("Retry-After", "30");
+ res.result(boost::beast::http::status::service_unavailable);
res.end();
+ return;
+ }
+ // Make this const static so it survives outside this method
+ static boost::asio::deadline_timer timeout(*req.ioService,
+ boost::posix_time::seconds(5));
+
+ timeout.expires_from_now(boost::posix_time::seconds(5));
+
+ timeout.async_wait([&res](const boost::system::error_code& ec) {
fwUpdateMatcher = nullptr;
- };
- fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus,
- "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
- "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
- callback);
+ if (ec == asio::error::operation_aborted)
+ {
+ // expected, we were canceled before the timer completed.
+ return;
+ }
+ BMCWEB_LOG_ERROR << "Timed out waiting for log event";
- std::string filepath(
- "/tmp/images/" +
- boost::uuids::to_string(boost::uuids::random_generator()()));
- BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
- std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
- std::ofstream::trunc);
- out << req.body;
- out.close();
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
+ return;
+ }
+
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ });
+
+ std::function<void(sdbusplus::message::message&)> callback =
+ [&res](sdbusplus::message::message& m) {
+ BMCWEB_LOG_DEBUG << "Match fired";
+ boost::system::error_code ec;
+ timeout.cancel(ec);
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "error canceling timer " << ec;
+ }
+ std::string versionInfo;
+ m.read(
+ versionInfo); // Read in the object path that was just created
+
+ std::size_t index = versionInfo.rfind('/');
+ if (index != std::string::npos)
+ {
+ versionInfo.erase(0, index);
+ }
+ res.jsonValue = {{"data", std::move(versionInfo)},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+ BMCWEB_LOG_DEBUG << "ending response";
+ res.end();
+ fwUpdateMatcher = nullptr;
+ };
+ fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+ "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
+ callback);
+
+ std::string filepath(
+ "/tmp/images/" +
+ boost::uuids::to_string(boost::uuids::random_generator()()));
+ BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ out << req.body;
+ out.close();
}
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/upload/image/<str>")
- .methods("POST"_method,
- "PUT"_method)([](const crow::Request& req, crow::Response& res,
- const std::string& filename) {
- uploadImageHandler(req, res, filename);
- });
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/upload/image/<str>")
+ .methods("POST"_method,
+ "PUT"_method)([](const crow::Request& req, crow::Response& res,
+ const std::string& filename) {
+ uploadImageHandler(req, res, filename);
+ });
- BMCWEB_ROUTE(app, "/upload/image")
- .methods("POST"_method,
- "PUT"_method)([](const crow::Request& req, crow::Response& res) {
- uploadImageHandler(req, res, "");
- });
+ BMCWEB_ROUTE(app, "/upload/image")
+ .methods("POST"_method, "PUT"_method)(
+ [](const crow::Request& req, crow::Response& res) {
+ uploadImageHandler(req, res, "");
+ });
}
-} // namespace image_upload
-} // namespace crow
+} // namespace image_upload
+} // namespace crow
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
index 3e6443d..4f6c233 100644
--- a/include/openbmc_dbus_rest.hpp
+++ b/include/openbmc_dbus_rest.hpp
@@ -1,64 +1,78 @@
#include <crow/app.h>
-
#include <tinyxml2.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/container/flat_set.hpp>
#include <dbus_singleton.hpp>
#include <experimental/filesystem>
#include <fstream>
-#include <boost/algorithm/string.hpp>
-#include <boost/container/flat_set.hpp>
-namespace crow {
-namespace openbmc_mapper {
+namespace crow
+{
+namespace openbmc_mapper
+{
void introspectObjects(crow::Response &res, std::string process_name,
std::string path,
- std::shared_ptr<nlohmann::json> transaction) {
- crow::connections::systemBus->async_method_call(
- [
- &res, transaction, processName{std::move(process_name)},
- objectPath{std::move(path)}
- ](const boost::system::error_code ec, const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Introspect call failed with error: "
- << ec.message() << " on process: " << processName
- << " path: " << objectPath << "\n";
-
- } else {
- transaction->push_back({{"path", objectPath}});
-
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
- << " " << objectPath << "\n";
-
- } else {
- tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
- while (node != nullptr) {
- std::string childPath = node->Attribute("name");
- std::string newpath;
- if (objectPath != "/") {
- newpath += objectPath;
- }
- newpath += "/" + childPath;
- // introspect the subobjects as well
- introspectObjects(res, processName, newpath, transaction);
-
- node = node->NextSiblingElement("node");
+ std::shared_ptr<nlohmann::json> transaction)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, transaction, processName{std::move(process_name)},
+ objectPath{std::move(path)}](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << processName << " path: " << objectPath
+ << "\n";
}
- }
- }
- // if we're the last outstanding caller, finish the request
- if (transaction.use_count() == 1) {
- res.jsonValue = {{"status", "ok"},
- {"bus_name", processName},
- {"objects", std::move(*transaction)}};
- res.end();
- }
- },
- process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect");
+ else
+ {
+ transaction->push_back({{"path", objectPath}});
+
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << processName << " " << objectPath
+ << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLElement *node =
+ pRoot->FirstChildElement("node");
+ while (node != nullptr)
+ {
+ std::string childPath = node->Attribute("name");
+ std::string newpath;
+ if (objectPath != "/")
+ {
+ newpath += objectPath;
+ }
+ newpath += "/" + childPath;
+ // introspect the subobjects as well
+ introspectObjects(res, processName, newpath,
+ transaction);
+
+ node = node->NextSiblingElement("node");
+ }
+ }
+ }
+ // if we're the last outstanding caller, finish the request
+ if (transaction.use_count() == 1)
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"bus_name", processName},
+ {"objects", std::move(*transaction)}};
+ res.end();
+ }
+ },
+ process_name, path, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
}
// A smattering of common types to unpack. TODO(ed) this should really iterate
@@ -74,46 +88,60 @@
std::string,
boost::container::flat_map<std::string, DbusRestVariantType>>>>;
-void getManagedObjectsForEnumerate(
- const std::string &object_name, const std::string &connection_name,
- crow::Response &res, std::shared_ptr<nlohmann::json> transaction) {
- crow::connections::systemBus->async_method_call(
- [&res, transaction](const boost::system::error_code ec,
- const ManagedObjectType &objects) {
- if (ec) {
- BMCWEB_LOG_ERROR << ec;
- } else {
- nlohmann::json &dataJson = *transaction;
-
- for (auto &objectPath : objects) {
- BMCWEB_LOG_DEBUG
- << "Reading object "
- << static_cast<const std::string &>(objectPath.first);
- nlohmann::json &objectJson =
- dataJson[static_cast<const std::string &>(objectPath.first)];
- if (objectJson.is_null()) {
- objectJson = nlohmann::json::object();
+void getManagedObjectsForEnumerate(const std::string &object_name,
+ const std::string &connection_name,
+ crow::Response &res,
+ std::shared_ptr<nlohmann::json> transaction)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, transaction](const boost::system::error_code ec,
+ const ManagedObjectType &objects) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << ec;
}
- for (const auto &interface : objectPath.second) {
- for (const auto &property : interface.second) {
- nlohmann::json &propertyJson = objectJson[property.first];
- mapbox::util::apply_visitor(
- [&propertyJson](auto &&val) { propertyJson = val; },
- property.second);
- }
- }
- }
- }
+ else
+ {
+ nlohmann::json &dataJson = *transaction;
- if (transaction.use_count() == 1) {
- res.jsonValue = {{"message", "200 OK"},
- {"status", "ok"},
- {"data", std::move(*transaction)}};
- res.end();
- }
- },
- connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
- "GetManagedObjects");
+ for (auto &objectPath : objects)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Reading object "
+ << static_cast<const std::string &>(objectPath.first);
+ nlohmann::json &objectJson =
+ dataJson[static_cast<const std::string &>(
+ objectPath.first)];
+ if (objectJson.is_null())
+ {
+ objectJson = nlohmann::json::object();
+ }
+ for (const auto &interface : objectPath.second)
+ {
+ for (const auto &property : interface.second)
+ {
+ nlohmann::json &propertyJson =
+ objectJson[property.first];
+ mapbox::util::apply_visitor(
+ [&propertyJson](auto &&val) {
+ propertyJson = val;
+ },
+ property.second);
+ }
+ }
+ }
+ }
+
+ if (transaction.use_count() == 1)
+ {
+ res.jsonValue = {{"message", "200 OK"},
+ {"status", "ok"},
+ {"data", std::move(*transaction)}};
+ res.end();
+ }
+ },
+ connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
+ "GetManagedObjects");
}
using GetSubTreeType = std::vector<
@@ -121,1025 +149,1320 @@
std::vector<std::pair<std::string, std::vector<std::string>>>>>;
// Structure for storing data on an in progress action
-struct InProgressActionData {
- InProgressActionData(crow::Response &res) : res(res){};
- ~InProgressActionData() {
- if (res.result() == boost::beast::http::status::internal_server_error) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = nlohmann::json::object();
+struct InProgressActionData
+{
+ InProgressActionData(crow::Response &res) : res(res){};
+ ~InProgressActionData()
+ {
+ if (res.result() == boost::beast::http::status::internal_server_error)
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = nlohmann::json::object();
+ }
+ res.end();
}
- res.end();
- }
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
- crow::Response &res;
- std::string path;
- std::string methodName;
- nlohmann::json arguments;
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
+ crow::Response &res;
+ std::string path;
+ std::string methodName;
+ nlohmann::json arguments;
};
-std::vector<std::string> dbusArgSplit(const std::string &string) {
- std::vector<std::string> ret;
- if (string.empty()) {
- return ret;
- }
- ret.push_back("");
- int containerDepth = 0;
-
- for (std::string::const_iterator character = string.begin();
- character != string.end(); character++) {
- ret.back() += *character;
- switch (*character) {
- case ('a'):
- break;
- case ('('):
- case ('{'):
- containerDepth++;
- break;
- case ('}'):
- case (')'):
- containerDepth--;
- if (containerDepth == 0) {
- if (character + 1 != string.end()) {
- ret.push_back("");
- }
- }
- break;
- default:
- if (containerDepth == 0) {
- if (character + 1 != string.end()) {
- ret.push_back("");
- }
- }
- break;
+std::vector<std::string> dbusArgSplit(const std::string &string)
+{
+ std::vector<std::string> ret;
+ if (string.empty())
+ {
+ return ret;
}
- }
+ ret.push_back("");
+ int containerDepth = 0;
+
+ for (std::string::const_iterator character = string.begin();
+ character != string.end(); character++)
+ {
+ ret.back() += *character;
+ switch (*character)
+ {
+ case ('a'):
+ break;
+ case ('('):
+ case ('{'):
+ containerDepth++;
+ break;
+ case ('}'):
+ case (')'):
+ containerDepth--;
+ if (containerDepth == 0)
+ {
+ if (character + 1 != string.end())
+ {
+ ret.push_back("");
+ }
+ }
+ break;
+ default:
+ if (containerDepth == 0)
+ {
+ if (character + 1 != string.end())
+ {
+ ret.push_back("");
+ }
+ }
+ break;
+ }
+ }
}
int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
- const nlohmann::json &input_json) {
- int r = 0;
- BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
- << " to type: " << arg_type;
- const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
+ const nlohmann::json &input_json)
+{
+ int r = 0;
+ BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
+ << " to type: " << arg_type;
+ const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
- // Assume a single object for now.
- const nlohmann::json *j = &input_json;
- nlohmann::json::const_iterator jIt = input_json.begin();
+ // Assume a single object for now.
+ const nlohmann::json *j = &input_json;
+ nlohmann::json::const_iterator jIt = input_json.begin();
- for (const std::string &arg_code : argTypes) {
- // If we are decoding multiple objects, grab the pointer to the iterator,
- // and increment it for the next loop
- if (argTypes.size() > 1) {
- if (jIt == input_json.end()) {
- return -2;
- }
- j = &*jIt;
- jIt++;
- }
- const int64_t *int_value = j->get_ptr<const int64_t *>();
- const uint64_t *uint_value = j->get_ptr<const uint64_t *>();
- const std::string *string_value = j->get_ptr<const std::string *>();
- const double *double_value = j->get_ptr<const double *>();
- const bool *b = j->get_ptr<const bool *>();
- int64_t v = 0;
- double d = 0.0;
+ for (const std::string &arg_code : argTypes)
+ {
+ // If we are decoding multiple objects, grab the pointer to the
+ // iterator, and increment it for the next loop
+ if (argTypes.size() > 1)
+ {
+ if (jIt == input_json.end())
+ {
+ return -2;
+ }
+ j = &*jIt;
+ jIt++;
+ }
+ const int64_t *int_value = j->get_ptr<const int64_t *>();
+ const uint64_t *uint_value = j->get_ptr<const uint64_t *>();
+ const std::string *string_value = j->get_ptr<const std::string *>();
+ const double *double_value = j->get_ptr<const double *>();
+ const bool *b = j->get_ptr<const bool *>();
+ int64_t v = 0;
+ double d = 0.0;
- // Do some basic type conversions that make sense. uint can be converted to
- // int. int and uint can be converted to double
- if (uint_value != nullptr && int_value == nullptr) {
- v = static_cast<int64_t>(*uint_value);
- int_value = &v;
- }
- if (uint_value != nullptr && double_value == nullptr) {
- d = static_cast<double>(*uint_value);
- double_value = &d;
- }
- if (int_value != nullptr && double_value == nullptr) {
- d = static_cast<double>(*int_value);
- double_value = &d;
- }
-
- if (arg_code == "s") {
- if (string_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0],
- (void *)string_value->c_str());
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "i") {
- if (int_value == nullptr) {
- return -1;
- }
- int32_t i = static_cast<int32_t>(*int_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &i);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "b") {
- // lots of ways bool could be represented here. Try them all
- int bool_int = false;
- if (int_value != nullptr) {
- bool_int = *int_value > 0 ? 1 : 0;
- } else if (b != nullptr) {
- bool_int = b ? 1 : 0;
- } else if (string_value != nullptr) {
- bool_int = boost::istarts_with(*string_value, "t") ? 1 : 0;
- } else {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], &bool_int);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "n") {
- if (int_value == nullptr) {
- return -1;
- }
- int16_t n = static_cast<int16_t>(*int_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &n);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "x") {
- if (int_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], int_value);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "y") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint8_t y = static_cast<uint8_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &y);
- } else if (arg_code == "q") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint16_t q = static_cast<uint16_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &q);
- } else if (arg_code == "u") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint32_t u = static_cast<uint32_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &u);
- } else if (arg_code == "t") {
- if (uint_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], uint_value);
- } else if (arg_code == "d") {
- sd_bus_message_append_basic(m, arg_code[0], double_value);
- } else if (boost::starts_with(arg_code, "a")) {
- std::string contained_type = arg_code.substr(1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
- contained_type.c_str());
- if (r < 0) {
- return r;
- }
-
- for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
- ++it) {
- r = convertJsonToDbus(m, contained_type, *it);
- if (r < 0) {
- return r;
+ // Do some basic type conversions that make sense. uint can be
+ // converted to int. int and uint can be converted to double
+ if (uint_value != nullptr && int_value == nullptr)
+ {
+ v = static_cast<int64_t>(*uint_value);
+ int_value = &v;
+ }
+ if (uint_value != nullptr && double_value == nullptr)
+ {
+ d = static_cast<double>(*uint_value);
+ double_value = &d;
+ }
+ if (int_value != nullptr && double_value == nullptr)
+ {
+ d = static_cast<double>(*int_value);
+ double_value = &d;
}
- it++;
- }
- sd_bus_message_close_container(m);
- } else if (boost::starts_with(arg_code, "v")) {
- std::string contained_type = arg_code.substr(1);
- BMCWEB_LOG_DEBUG << "variant type: " << arg_code
- << " appending variant of type: " << contained_type;
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
- contained_type.c_str());
- if (r < 0) {
- return r;
- }
-
- r = convertJsonToDbus(m, contained_type, input_json);
- if (r < 0) {
- return r;
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0) {
- return r;
- }
- } else if (boost::starts_with(arg_code, "(") &&
- boost::ends_with(arg_code, ")")) {
- std::string contained_type = arg_code.substr(1, arg_code.size() - 1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
- contained_type.c_str());
- nlohmann::json::const_iterator it = j->begin();
- for (const std::string &arg_code : dbusArgSplit(arg_type)) {
- if (it == j->end()) {
- return -1;
+ if (arg_code == "s")
+ {
+ if (string_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0],
+ (void *)string_value->c_str());
+ if (r < 0)
+ {
+ return r;
+ }
}
- r = convertJsonToDbus(m, arg_code, *it);
- if (r < 0) {
- return r;
+ else if (arg_code == "i")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ int32_t i = static_cast<int32_t>(*int_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &i);
+ if (r < 0)
+ {
+ return r;
+ }
}
- it++;
- }
- r = sd_bus_message_close_container(m);
- } else if (boost::starts_with(arg_code, "{") &&
- boost::ends_with(arg_code, "}")) {
- std::string contained_type = arg_code.substr(1, arg_code.size() - 1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
- contained_type.c_str());
- std::vector<std::string> codes = dbusArgSplit(contained_type);
- if (codes.size() != 2) {
- return -1;
- }
- const std::string &key_type = codes[0];
- const std::string &value_type = codes[1];
- for (auto it : j->items()) {
- r = convertJsonToDbus(m, key_type, it.key());
- if (r < 0) {
- return r;
+ else if (arg_code == "b")
+ {
+ // lots of ways bool could be represented here. Try them all
+ int bool_int = false;
+ if (int_value != nullptr)
+ {
+ bool_int = *int_value > 0 ? 1 : 0;
+ }
+ else if (b != nullptr)
+ {
+ bool_int = b ? 1 : 0;
+ }
+ else if (string_value != nullptr)
+ {
+ bool_int = boost::istarts_with(*string_value, "t") ? 1 : 0;
+ }
+ else
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], &bool_int);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "n")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ int16_t n = static_cast<int16_t>(*int_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &n);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "x")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], int_value);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "y")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint8_t y = static_cast<uint8_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &y);
+ }
+ else if (arg_code == "q")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint16_t q = static_cast<uint16_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &q);
+ }
+ else if (arg_code == "u")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint32_t u = static_cast<uint32_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &u);
+ }
+ else if (arg_code == "t")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], uint_value);
+ }
+ else if (arg_code == "d")
+ {
+ sd_bus_message_append_basic(m, arg_code[0], double_value);
+ }
+ else if (boost::starts_with(arg_code, "a"))
+ {
+ std::string contained_type = arg_code.substr(1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
+ contained_type.c_str());
+ if (r < 0)
+ {
+ return r;
+ }
+
+ for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
+ ++it)
+ {
+ r = convertJsonToDbus(m, contained_type, *it);
+ if (r < 0)
+ {
+ return r;
+ }
+
+ it++;
+ }
+ sd_bus_message_close_container(m);
+ }
+ else if (boost::starts_with(arg_code, "v"))
+ {
+ std::string contained_type = arg_code.substr(1);
+ BMCWEB_LOG_DEBUG
+ << "variant type: " << arg_code
+ << " appending variant of type: " << contained_type;
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
+ contained_type.c_str());
+ if (r < 0)
+ {
+ return r;
+ }
+
+ r = convertJsonToDbus(m, contained_type, input_json);
+ if (r < 0)
+ {
+ return r;
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (boost::starts_with(arg_code, "(") &&
+ boost::ends_with(arg_code, ")"))
+ {
+ std::string contained_type =
+ arg_code.substr(1, arg_code.size() - 1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
+ contained_type.c_str());
+ nlohmann::json::const_iterator it = j->begin();
+ for (const std::string &arg_code : dbusArgSplit(arg_type))
+ {
+ if (it == j->end())
+ {
+ return -1;
+ }
+ r = convertJsonToDbus(m, arg_code, *it);
+ if (r < 0)
+ {
+ return r;
+ }
+ it++;
+ }
+ r = sd_bus_message_close_container(m);
+ }
+ else if (boost::starts_with(arg_code, "{") &&
+ boost::ends_with(arg_code, "}"))
+ {
+ std::string contained_type =
+ arg_code.substr(1, arg_code.size() - 1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
+ contained_type.c_str());
+ std::vector<std::string> codes = dbusArgSplit(contained_type);
+ if (codes.size() != 2)
+ {
+ return -1;
+ }
+ const std::string &key_type = codes[0];
+ const std::string &value_type = codes[1];
+ for (auto it : j->items())
+ {
+ r = convertJsonToDbus(m, key_type, it.key());
+ if (r < 0)
+ {
+ return r;
+ }
+
+ r = convertJsonToDbus(m, value_type, it.value());
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ r = sd_bus_message_close_container(m);
+ }
+ else
+ {
+ return -2;
+ }
+ if (r < 0)
+ {
+ return r;
}
- r = convertJsonToDbus(m, value_type, it.value());
- if (r < 0) {
- return r;
+ if (argTypes.size() > 1)
+ {
+ jIt++;
}
- }
- r = sd_bus_message_close_container(m);
- } else {
- return -2;
}
- if (r < 0) {
- return r;
- }
-
- if (argTypes.size() > 1) {
- jIt++;
- }
- }
}
void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
- const std::string &connectionName) {
- BMCWEB_LOG_DEBUG << "findActionOnInterface for connection " << connectionName;
- crow::connections::systemBus->async_method_call(
- [
- transaction, connectionName{std::string(connectionName)}
- ](const boost::system::error_code ec, const std::string &introspect_xml) {
- BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
- if (ec) {
- BMCWEB_LOG_ERROR << "Introspect call failed with error: "
- << ec.message() << " on process: " << connectionName
- << "\n";
- } else {
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << connectionName << "\n";
-
- } else {
- tinyxml2::XMLElement *interface_node =
- pRoot->FirstChildElement("interface");
- while (interface_node != nullptr) {
- std::string this_interface_name =
- interface_node->Attribute("name");
- tinyxml2::XMLElement *method_node =
- interface_node->FirstChildElement("method");
- while (method_node != nullptr) {
- std::string this_methodName = method_node->Attribute("name");
- BMCWEB_LOG_DEBUG << "Found method: " << this_methodName;
- if (this_methodName == transaction->methodName) {
- sdbusplus::message::message m =
- crow::connections::systemBus->new_method_call(
- connectionName.c_str(), transaction->path.c_str(),
- this_interface_name.c_str(),
- transaction->methodName.c_str());
-
- tinyxml2::XMLElement *argument_node =
- method_node->FirstChildElement("arg");
-
- nlohmann::json::const_iterator arg_it =
- transaction->arguments.begin();
-
- while (argument_node != nullptr) {
- std::string arg_direction =
- argument_node->Attribute("direction");
- if (arg_direction == "in") {
- std::string arg_type = argument_node->Attribute("type");
- if (arg_it == transaction->arguments.end()) {
- transaction->setErrorStatus();
- return;
- }
- if (convertJsonToDbus(m.get(), arg_type, *arg_it) < 0) {
- transaction->setErrorStatus();
- return;
- }
-
- arg_it++;
- }
- argument_node = method_node->NextSiblingElement("arg");
- }
- crow::connections::systemBus->async_send(
- m, [transaction](boost::system::error_code ec,
- sdbusplus::message::message &m) {
- if (ec) {
- transaction->setErrorStatus();
- return;
- }
- transaction->res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", nullptr}};
- });
- break;
- }
- method_node = method_node->NextSiblingElement("method");
- }
- interface_node = interface_node->NextSiblingElement("interface");
+ const std::string &connectionName)
+{
+ BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
+ << connectionName;
+ crow::connections::systemBus->async_method_call(
+ [transaction, connectionName{std::string(connectionName)}](
+ const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << connectionName << "\n";
}
- }
- }
- },
- connectionName, transaction->path, "org.freedesktop.DBus.Introspectable",
- "Introspect");
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << connectionName << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLElement *interface_node =
+ pRoot->FirstChildElement("interface");
+ while (interface_node != nullptr)
+ {
+ std::string this_interface_name =
+ interface_node->Attribute("name");
+ tinyxml2::XMLElement *method_node =
+ interface_node->FirstChildElement("method");
+ while (method_node != nullptr)
+ {
+ std::string this_methodName =
+ method_node->Attribute("name");
+ BMCWEB_LOG_DEBUG << "Found method: "
+ << this_methodName;
+ if (this_methodName == transaction->methodName)
+ {
+ sdbusplus::message::message m =
+ crow::connections::systemBus
+ ->new_method_call(
+ connectionName.c_str(),
+ transaction->path.c_str(),
+ this_interface_name.c_str(),
+ transaction->methodName.c_str());
+
+ tinyxml2::XMLElement *argument_node =
+ method_node->FirstChildElement("arg");
+
+ nlohmann::json::const_iterator arg_it =
+ transaction->arguments.begin();
+
+ while (argument_node != nullptr)
+ {
+ std::string arg_direction =
+ argument_node->Attribute("direction");
+ if (arg_direction == "in")
+ {
+ std::string arg_type =
+ argument_node->Attribute("type");
+ if (arg_it ==
+ transaction->arguments.end())
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ if (convertJsonToDbus(m.get(), arg_type,
+ *arg_it) < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+
+ arg_it++;
+ }
+ argument_node =
+ method_node->NextSiblingElement("arg");
+ }
+ crow::connections::systemBus->async_send(
+ m, [transaction](
+ boost::system::error_code ec,
+ sdbusplus::message::message &m) {
+ if (ec)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ transaction->res.jsonValue = {
+ {"status", "ok"},
+ {"message", "200 OK"},
+ {"data", nullptr}};
+ });
+ break;
+ }
+ method_node =
+ method_node->NextSiblingElement("method");
+ }
+ interface_node =
+ interface_node->NextSiblingElement("interface");
+ }
+ }
+ }
+ },
+ connectionName, transaction->path,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
}
void handle_action(const crow::Request &req, crow::Response &res,
- const std::string &objectPath,
- const std::string &methodName) {
- nlohmann::json requestDbusData =
- nlohmann::json::parse(req.body, nullptr, false);
+ const std::string &objectPath, const std::string &methodName)
+{
+ nlohmann::json requestDbusData =
+ nlohmann::json::parse(req.body, nullptr, false);
- if (requestDbusData.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- if (!requestDbusData.is_array()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- auto transaction = std::make_shared<InProgressActionData>(res);
-
- transaction->path = objectPath;
- transaction->methodName = methodName;
- transaction->arguments = std::move(requestDbusData);
- crow::connections::systemBus->async_method_call(
- [transaction](
- const boost::system::error_code ec,
- const std::vector<std::pair<std::string, std::vector<std::string>>>
- &interface_names) {
- if (ec || interface_names.size() <= 0) {
- transaction->setErrorStatus();
- return;
- }
-
- BMCWEB_LOG_DEBUG << "GetObject returned objects "
- << interface_names.size();
-
- for (const std::pair<std::string, std::vector<std::string>> &object :
- interface_names) {
- findActionOnInterface(transaction, object.first);
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
- std::array<std::string, 0>());
-}
-
-void handle_list(crow::Response &res, const std::string &objectPath) {
- crow::connections::systemBus->async_method_call(
- [&res](const boost::system::error_code ec,
- std::vector<std::string> &objectPaths) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", std::move(objectPaths)}};
- }
+ if (requestDbusData.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
res.end();
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
- static_cast<int32_t>(99), std::array<std::string, 0>());
+ return;
+ }
+ if (!requestDbusData.is_array())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ auto transaction = std::make_shared<InProgressActionData>(res);
+
+ transaction->path = objectPath;
+ transaction->methodName = methodName;
+ transaction->arguments = std::move(requestDbusData);
+ crow::connections::systemBus->async_method_call(
+ [transaction](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<std::string, std::vector<std::string>>>
+ &interface_names) {
+ if (ec || interface_names.size() <= 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "GetObject returned objects "
+ << interface_names.size();
+
+ for (const std::pair<std::string, std::vector<std::string>>
+ &object : interface_names)
+ {
+ findActionOnInterface(transaction, object.first);
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
+ std::array<std::string, 0>());
}
-void handle_enumerate(crow::Response &res, const std::string &objectPath) {
- crow::connections::systemBus->async_method_call(
- [&res, objectPath{std::string(objectPath)} ](
- const boost::system::error_code ec,
- const GetSubTreeType &object_names) {
- if (ec) {
- res.jsonValue = {{"message", "200 OK"},
- {"status", "ok"},
- {"data", nlohmann::json::object()}};
+void handle_list(crow::Response &res, const std::string &objectPath)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res](const boost::system::error_code ec,
+ std::vector<std::string> &objectPaths) {
+ if (ec)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"message", "200 OK"},
+ {"data", std::move(objectPaths)}};
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
+ static_cast<int32_t>(99), std::array<std::string, 0>());
+}
- res.end();
- return;
- }
+void handle_enumerate(crow::Response &res, const std::string &objectPath)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, objectPath{std::string(objectPath)}](
+ const boost::system::error_code ec,
+ const GetSubTreeType &object_names) {
+ if (ec)
+ {
+ res.jsonValue = {{"message", "200 OK"},
+ {"status", "ok"},
+ {"data", nlohmann::json::object()}};
- boost::container::flat_set<std::string> connections;
+ res.end();
+ return;
+ }
- for (const auto &object : object_names) {
- for (const auto &Connection : object.second) {
- connections.insert(Connection.first);
- }
- }
+ boost::container::flat_set<std::string> connections;
- if (connections.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- auto transaction =
- std::make_shared<nlohmann::json>(nlohmann::json::object());
- for (const std::string &Connection : connections) {
- getManagedObjectsForEnumerate(objectPath, Connection, res,
- transaction);
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, (int32_t)0,
- std::array<std::string, 0>());
+ for (const auto &object : object_names)
+ {
+ for (const auto &Connection : object.second)
+ {
+ connections.insert(Connection.first);
+ }
+ }
+
+ if (connections.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ auto transaction =
+ std::make_shared<nlohmann::json>(nlohmann::json::object());
+ for (const std::string &Connection : connections)
+ {
+ getManagedObjectsForEnumerate(objectPath, Connection, res,
+ transaction);
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
+ (int32_t)0, std::array<std::string, 0>());
}
void handle_get(crow::Response &res, std::string &objectPath,
- std::string &destProperty) {
- BMCWEB_LOG_DEBUG << "handle_get: " << objectPath << " prop:" << destProperty;
- std::shared_ptr<std::string> property_name =
- std::make_shared<std::string>(std::move(destProperty));
+ std::string &destProperty)
+{
+ BMCWEB_LOG_DEBUG << "handle_get: " << objectPath
+ << " prop:" << destProperty;
+ std::shared_ptr<std::string> property_name =
+ std::make_shared<std::string>(std::move(destProperty));
- std::shared_ptr<std::string> path =
- std::make_shared<std::string>(std::move(objectPath));
+ std::shared_ptr<std::string> path =
+ std::make_shared<std::string>(std::move(objectPath));
- using GetObjectType =
- std::vector<std::pair<std::string, std::vector<std::string>>>;
- crow::connections::systemBus->async_method_call(
- [&res, path, property_name](const boost::system::error_code ec,
- const GetObjectType &object_names) {
- if (ec || object_names.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::shared_ptr<nlohmann::json> response =
- std::make_shared<nlohmann::json>(nlohmann::json::object());
- // The mapper should never give us an empty interface names list, but
- // check anyway
- for (const std::pair<std::string, std::vector<std::string>> connection :
- object_names) {
- const std::vector<std::string> &interfaceNames = connection.second;
+ using GetObjectType =
+ std::vector<std::pair<std::string, std::vector<std::string>>>;
+ crow::connections::systemBus->async_method_call(
+ [&res, path, property_name](const boost::system::error_code ec,
+ const GetObjectType &object_names) {
+ if (ec || object_names.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::shared_ptr<nlohmann::json> response =
+ std::make_shared<nlohmann::json>(nlohmann::json::object());
+ // The mapper should never give us an empty interface names list,
+ // but check anyway
+ for (const std::pair<std::string, std::vector<std::string>>
+ connection : object_names)
+ {
+ const std::vector<std::string> &interfaceNames =
+ connection.second;
- if (interfaceNames.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- for (const std::string &interface : interfaceNames) {
- crow::connections::systemBus->async_method_call(
- [&res, response, property_name](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, DbusRestVariantType>> &properties) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Bad dbus request error: " << ec;
- } else {
- for (const std::pair<std::string, DbusRestVariantType>
- &property : properties) {
- // if property name is empty, or matches our search query,
- // add it to the response json
-
- if (property_name->empty()) {
- mapbox::util::apply_visitor(
- [&response, &property](auto &&val) {
- (*response)[property.first] = val;
- },
- property.second);
- } else if (property.first == *property_name) {
- mapbox::util::apply_visitor(
- [&response](auto &&val) { (*response) = val; },
- property.second);
- }
- }
- }
- if (response.use_count() == 1) {
- res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", *response}};
-
+ if (interfaceNames.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
res.end();
- }
- },
- connection.first, *path, "org.freedesktop.DBus.Properties",
- "GetAll", interface);
- }
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
- std::array<std::string, 0>());
+ return;
+ }
+
+ for (const std::string &interface : interfaceNames)
+ {
+ crow::connections::systemBus->async_method_call(
+ [&res, response, property_name](
+ const boost::system::error_code ec,
+ const std::vector<
+ std::pair<std::string, DbusRestVariantType>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Bad dbus request error: "
+ << ec;
+ }
+ else
+ {
+ for (const std::pair<std::string,
+ DbusRestVariantType>
+ &property : properties)
+ {
+ // if property name is empty, or matches our
+ // search query, add it to the response json
+
+ if (property_name->empty())
+ {
+ mapbox::util::apply_visitor(
+ [&response, &property](auto &&val) {
+ (*response)[property.first] =
+ val;
+ },
+ property.second);
+ }
+ else if (property.first == *property_name)
+ {
+ mapbox::util::apply_visitor(
+ [&response](auto &&val) {
+ (*response) = val;
+ },
+ property.second);
+ }
+ }
+ }
+ if (response.use_count() == 1)
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"message", "200 OK"},
+ {"data", *response}};
+
+ res.end();
+ }
+ },
+ connection.first, *path,
+ "org.freedesktop.DBus.Properties", "GetAll", interface);
+ }
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
+ std::array<std::string, 0>());
}
-struct AsyncPutRequest {
- AsyncPutRequest(crow::Response &res) : res(res) {
- res.jsonValue = {
- {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
- }
- ~AsyncPutRequest() {
- if (res.result() == boost::beast::http::status::internal_server_error) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = nlohmann::json::object();
+struct AsyncPutRequest
+{
+ AsyncPutRequest(crow::Response &res) : res(res)
+ {
+ res.jsonValue = {
+ {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
+ }
+ ~AsyncPutRequest()
+ {
+ if (res.result() == boost::beast::http::status::internal_server_error)
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = nlohmann::json::object();
+ }
+
+ if (res.jsonValue.empty())
+ {
+ res.result(boost::beast::http::status::forbidden);
+ res.jsonValue = {
+ {"status", "error"},
+ {"message", "403 Forbidden"},
+ {"data",
+ {{"message", "The specified property cannot be created: " +
+ propertyName}}}};
+ }
+
+ res.end();
}
- if (res.jsonValue.empty()) {
- res.result(boost::beast::http::status::forbidden);
- res.jsonValue = {
- {"status", "error"},
- {"message", "403 Forbidden"},
- {"data",
- {{"message",
- "The specified property cannot be created: " + propertyName}}}};
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
}
- res.end();
- }
-
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
-
- crow::Response &res;
- std::string objectPath;
- std::string propertyName;
- nlohmann::json propertyValue;
+ crow::Response &res;
+ std::string objectPath;
+ std::string propertyName;
+ nlohmann::json propertyValue;
};
void handlePut(const crow::Request &req, crow::Response &res,
- const std::string &objectPath, const std::string &destProperty) {
- nlohmann::json requestDbusData =
- nlohmann::json::parse(req.body, nullptr, false);
+ const std::string &objectPath, const std::string &destProperty)
+{
+ nlohmann::json requestDbusData =
+ nlohmann::json::parse(req.body, nullptr, false);
- if (requestDbusData.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
-
- nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
- if (propertyIt == requestDbusData.end()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- const nlohmann::json &propertySetValue = *propertyIt;
- auto transaction = std::make_shared<AsyncPutRequest>(res);
- transaction->objectPath = objectPath;
- transaction->propertyName = destProperty;
- transaction->propertyValue = propertySetValue;
-
- using GetObjectType =
- std::vector<std::pair<std::string, std::vector<std::string>>>;
-
- crow::connections::systemBus->async_method_call(
- [transaction](const boost::system::error_code ec,
- const GetObjectType &object_names) {
- if (!ec && object_names.size() <= 0) {
- transaction->res.result(boost::beast::http::status::not_found);
- return;
- }
-
- for (const std::pair<std::string, std::vector<std::string>> connection :
- object_names) {
- const std::string &connectionName = connection.first;
-
- crow::connections::systemBus->async_method_call(
- [ connectionName{std::string(connectionName)}, transaction ](
- const boost::system::error_code ec,
- const std::string &introspectXml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << connectionName;
- transaction->setErrorStatus();
- return;
- }
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspectXml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse: "
- << introspectXml;
- transaction->setErrorStatus();
- return;
- }
- tinyxml2::XMLElement *ifaceNode =
- pRoot->FirstChildElement("interface");
- while (ifaceNode != nullptr) {
- const char *interfaceName = ifaceNode->Attribute("name");
- BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
- tinyxml2::XMLElement *propNode =
- ifaceNode->FirstChildElement("property");
- while (propNode != nullptr) {
- const char *propertyName = propNode->Attribute("name");
- BMCWEB_LOG_DEBUG << "Found property " << propertyName;
- if (propertyName == transaction->propertyName) {
- const char *argType = propNode->Attribute("type");
- if (argType != nullptr) {
- sdbusplus::message::message m =
- crow::connections::systemBus->new_method_call(
- connectionName.c_str(),
- transaction->objectPath.c_str(),
- "org.freedesktop.DBus.Properties", "Set");
- m.append(interfaceName, transaction->propertyName);
- int r = sd_bus_message_open_container(
- m.get(), SD_BUS_TYPE_VARIANT, argType);
- if (r < 0) {
- transaction->setErrorStatus();
- return;
- }
- r = convertJsonToDbus(m.get(), argType,
- transaction->propertyValue);
- if (r < 0) {
- transaction->setErrorStatus();
- return;
- }
- r = sd_bus_message_close_container(m.get());
- if (r < 0) {
- transaction->setErrorStatus();
- return;
- }
-
- crow::connections::systemBus->async_send(
- m, [transaction](boost::system::error_code ec,
- sdbusplus::message::message &m) {
- BMCWEB_LOG_DEBUG << "sent";
- if (ec) {
- transaction->res.jsonValue["status"] = "error";
- transaction->res.jsonValue["message"] =
- ec.message();
- }
- });
- }
- }
- propNode = propNode->NextSiblingElement("property");
- }
- ifaceNode = ifaceNode->NextSiblingElement("interface");
- }
- },
- connectionName, transaction->objectPath,
- "org.freedesktop.DBus.Introspectable", "Introspect");
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", transaction->objectPath,
- std::array<std::string, 0>());
-}
-
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...> &app) {
- BMCWEB_ROUTE(app, "/bus/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
- res.jsonValue = {{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
- });
-
- BMCWEB_ROUTE(app, "/bus/system/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
-
- auto myCallback = [&res](const boost::system::error_code ec,
- std::vector<std::string> &names) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- std::sort(names.begin(), names.end());
- nlohmann::json j{{"status", "ok"}};
- auto &objectsSub = j["objects"];
- for (auto &name : names) {
- objectsSub.push_back({{"name", name}});
- }
- res.jsonValue = std::move(j);
- }
- res.end();
- };
- crow::connections::systemBus->async_method_call(
- std::move(myCallback), "org.freedesktop.DBus", "/",
- "org.freedesktop.DBus", "ListNames");
- });
-
- BMCWEB_ROUTE(app, "/list/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
- handle_list(res, "/");
- });
-
- BMCWEB_ROUTE(app, "/xyz/<path>")
- .methods("GET"_method, "PUT"_method,
- "POST"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &path) {
- std::string objectPath = "/xyz/" + path;
-
- // Trim any trailing "/" at the end
- if (boost::ends_with(objectPath, "/")) {
- objectPath.pop_back();
- }
-
- // If accessing a single attribute, fill in and update objectPath,
- // otherwise leave destProperty blank
- std::string destProperty = "";
- const char *attrSeperator = "/attr/";
- size_t attrPosition = path.find(attrSeperator);
- if (attrPosition != path.npos) {
- objectPath = "/xyz/" + path.substr(0, attrPosition);
- destProperty =
- path.substr(attrPosition + strlen(attrSeperator), path.length());
- }
-
- if (req.method() == "POST"_method) {
- constexpr const char *action_seperator = "/action/";
- size_t action_position = path.find(action_seperator);
- if (action_position != path.npos) {
- objectPath = "/xyz/" + path.substr(0, action_position);
- std::string post_property = path.substr(
- (action_position + strlen(action_seperator)), path.length());
- handle_action(req, res, objectPath, post_property);
- return;
- }
- } else if (req.method() == "GET"_method) {
- if (boost::ends_with(objectPath, "/enumerate")) {
- objectPath.erase(objectPath.end() - 10, objectPath.end());
- handle_enumerate(res, objectPath);
- } else if (boost::ends_with(objectPath, "/list")) {
- objectPath.erase(objectPath.end() - 5, objectPath.end());
- handle_list(res, objectPath);
- } else {
- handle_get(res, objectPath, destProperty);
- }
- return;
- } else if (req.method() == "PUT"_method) {
- handlePut(req, res, objectPath, destProperty);
- return;
- }
-
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/bus/system/<str>/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &Connection) {
- std::shared_ptr<nlohmann::json> transaction;
- introspectObjects(res, Connection, "/", transaction);
- });
-
- BMCWEB_ROUTE(app, "/download/dump/<str>/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &dumpId) {
- std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
- if (!std::regex_match(dumpId, validFilename)) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::experimental::filesystem::path loc(
- "/var/lib/phosphor-debug-collector/dumps");
-
- loc += dumpId;
-
- if (!std::experimental::filesystem::exists(loc) ||
- !std::experimental::filesystem::is_directory(loc)) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::experimental::filesystem::directory_iterator files(loc);
- for (auto &file : files) {
- std::ifstream readFile(file.path());
- if (readFile.good()) {
- continue;
- }
- res.addHeader("Content-Type", "application/octet-stream");
- res.body() = {std::istreambuf_iterator<char>(readFile),
- std::istreambuf_iterator<char>()};
- res.end();
- }
- res.result(boost::beast::http::status::not_found);
+ if (requestDbusData.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
res.end();
return;
- });
+ }
- BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &processName,
- const std::string &requestedPath) {
- std::vector<std::string> strs;
- boost::split(strs, requestedPath, boost::is_any_of("/"));
- std::string objectPath;
- std::string interfaceName;
- std::string methodName;
- auto it = strs.begin();
- if (it == strs.end()) {
- objectPath = "/";
- }
- 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()) {
- objectPath += "/" + *it;
- }
- it++;
- }
- if (it != strs.end()) {
- interfaceName = *it;
- it++;
+ nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
+ if (propertyIt == requestDbusData.end())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ const nlohmann::json &propertySetValue = *propertyIt;
+ auto transaction = std::make_shared<AsyncPutRequest>(res);
+ transaction->objectPath = objectPath;
+ transaction->propertyName = destProperty;
+ transaction->propertyValue = propertySetValue;
- // after interface, we might have a method name
- if (it != strs.end()) {
- methodName = *it;
- it++;
- }
- }
- if (it != strs.end()) {
- // if there is more levels past the method name, something went
- // wrong, return not found
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- if (interfaceName.empty()) {
- crow::connections::systemBus->async_method_call(
- [&, processName, objectPath](const boost::system::error_code ec,
- const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
+ using GetObjectType =
+ std::vector<std::pair<std::string, std::vector<std::string>>>;
- } else {
- tinyxml2::XMLDocument doc;
+ crow::connections::systemBus->async_method_call(
+ [transaction](const boost::system::error_code ec,
+ const GetObjectType &object_names) {
+ if (!ec && object_names.size() <= 0)
+ {
+ transaction->res.result(boost::beast::http::status::not_found);
+ return;
+ }
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << processName << " " << objectPath
- << "\n";
- res.jsonValue = {{"status", "XML parse error"}};
- res.result(
- boost::beast::http::status::internal_server_error);
- } else {
- nlohmann::json interfacesArray = nlohmann::json::array();
- tinyxml2::XMLElement *interface =
- pRoot->FirstChildElement("interface");
+ for (const std::pair<std::string, std::vector<std::string>>
+ connection : object_names)
+ {
+ const std::string &connectionName = connection.first;
- while (interface != nullptr) {
- std::string ifaceName = interface->Attribute("name");
- interfacesArray.push_back({{"name", ifaceName}});
-
- interface = interface->NextSiblingElement("interface");
- }
- res.jsonValue = {{"status", "ok"},
- {"bus_name", processName},
- {"interfaces", interfacesArray},
- {"objectPath", objectPath}};
- }
- }
- res.end();
- },
- processName, objectPath, "org.freedesktop.DBus.Introspectable",
- "Introspect");
- } else {
- crow::connections::systemBus->async_method_call(
- [
- &, processName, objectPath,
- interface_name{std::move(interfaceName)}
- ](const boost::system::error_code ec,
- const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
-
- } else {
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << processName << " " << objectPath
- << "\n";
- res.result(
- boost::beast::http::status::internal_server_error);
-
- } else {
- tinyxml2::XMLElement *node =
- pRoot->FirstChildElement("node");
-
- // if we know we're the only call, build the json directly
- nlohmann::json methodsArray = nlohmann::json::array();
- nlohmann::json signalsArray = nlohmann::json::array();
- tinyxml2::XMLElement *interface =
- pRoot->FirstChildElement("interface");
-
- while (interface != nullptr) {
- std::string ifaceName = interface->Attribute("name");
-
- if (ifaceName == interfaceName) {
- tinyxml2::XMLElement *methods =
- interface->FirstChildElement("method");
- while (methods != nullptr) {
- nlohmann::json argsArray = nlohmann::json::array();
- tinyxml2::XMLElement *arg =
- methods->FirstChildElement("arg");
- while (arg != nullptr) {
- argsArray.push_back(
- {{"name", arg->Attribute("name")},
- {"type", arg->Attribute("type")},
- {"direction", arg->Attribute("direction")}});
- arg = arg->NextSiblingElement("arg");
- }
- methodsArray.push_back(
- {{"name", methods->Attribute("name")},
- {"uri", "/bus/system/" + processName +
- objectPath + "/" + interfaceName +
- "/" + methods->Attribute("name")},
- {"args", argsArray}});
- methods = methods->NextSiblingElement("method");
+ crow::connections::systemBus->async_method_call(
+ [connectionName{std::string(connectionName)},
+ transaction](const boost::system::error_code ec,
+ const std::string &introspectXml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << connectionName;
+ transaction->setErrorStatus();
+ return;
}
- tinyxml2::XMLElement *signals =
- interface->FirstChildElement("signal");
- while (signals != nullptr) {
- nlohmann::json argsArray = nlohmann::json::array();
+ tinyxml2::XMLDocument doc;
- tinyxml2::XMLElement *arg =
- signals->FirstChildElement("arg");
- while (arg != nullptr) {
- std::string name = arg->Attribute("name");
- std::string type = arg->Attribute("type");
- argsArray.push_back({
- {"name", name},
- {"type", type},
- });
- arg = arg->NextSiblingElement("arg");
- }
- signalsArray.push_back(
- {{"name", signals->Attribute("name")},
- {"args", argsArray}});
- signals = signals->NextSiblingElement("signal");
+ doc.Parse(introspectXml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse: "
+ << introspectXml;
+ transaction->setErrorStatus();
+ return;
}
+ tinyxml2::XMLElement *ifaceNode =
+ pRoot->FirstChildElement("interface");
+ while (ifaceNode != nullptr)
+ {
+ const char *interfaceName =
+ ifaceNode->Attribute("name");
+ BMCWEB_LOG_DEBUG << "found interface "
+ << interfaceName;
+ tinyxml2::XMLElement *propNode =
+ ifaceNode->FirstChildElement("property");
+ while (propNode != nullptr)
+ {
+ const char *propertyName =
+ propNode->Attribute("name");
+ BMCWEB_LOG_DEBUG << "Found property "
+ << propertyName;
+ if (propertyName == transaction->propertyName)
+ {
+ const char *argType =
+ propNode->Attribute("type");
+ if (argType != nullptr)
+ {
+ sdbusplus::message::message m =
+ crow::connections::systemBus
+ ->new_method_call(
+ connectionName.c_str(),
+ transaction->objectPath
+ .c_str(),
+ "org.freedesktop.DBus."
+ "Properties",
+ "Set");
+ m.append(interfaceName,
+ transaction->propertyName);
+ int r = sd_bus_message_open_container(
+ m.get(), SD_BUS_TYPE_VARIANT,
+ argType);
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ r = convertJsonToDbus(
+ m.get(), argType,
+ transaction->propertyValue);
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ r = sd_bus_message_close_container(
+ m.get());
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
- res.jsonValue = {
- {"status", "ok"},
- {"bus_name", processName},
- {"interface", interfaceName},
- {"methods", methodsArray},
- {"objectPath", objectPath},
- {"properties", nlohmann::json::object()},
- {"signals", signalsArray}};
-
- 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.result(boost::beast::http::status::not_found);
- }
- }
- }
- res.end();
- },
- processName, objectPath, "org.freedesktop.DBus.Introspectable",
- "Introspect");
- }
- });
+ crow::connections::systemBus
+ ->async_send(
+ m,
+ [transaction](
+ boost::system::error_code
+ ec,
+ sdbusplus::message::message
+ &m) {
+ BMCWEB_LOG_DEBUG << "sent";
+ if (ec)
+ {
+ transaction->res
+ .jsonValue
+ ["status"] =
+ "error";
+ transaction->res
+ .jsonValue
+ ["message"] =
+ ec.message();
+ }
+ });
+ }
+ }
+ propNode =
+ propNode->NextSiblingElement("property");
+ }
+ ifaceNode =
+ ifaceNode->NextSiblingElement("interface");
+ }
+ },
+ connectionName, transaction->objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject",
+ transaction->objectPath, std::array<std::string, 0>());
}
-} // namespace openbmc_mapper
-} // namespace crow
+
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
+{
+ BMCWEB_ROUTE(app, "/bus/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ res.jsonValue = {{"busses", {{{"name", "system"}}}},
+ {"status", "ok"}};
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ auto myCallback = [&res](const boost::system::error_code ec,
+ std::vector<std::string> &names) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ std::sort(names.begin(), names.end());
+ nlohmann::json j{{"status", "ok"}};
+ auto &objectsSub = j["objects"];
+ for (auto &name : names)
+ {
+ objectsSub.push_back({{"name", name}});
+ }
+ res.jsonValue = std::move(j);
+ }
+ res.end();
+ };
+ crow::connections::systemBus->async_method_call(
+ std::move(myCallback), "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "ListNames");
+ });
+
+ BMCWEB_ROUTE(app, "/list/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ handle_list(res, "/");
+ });
+
+ BMCWEB_ROUTE(app, "/xyz/<path>")
+ .methods("GET"_method, "PUT"_method,
+ "POST"_method)([](const crow::Request &req,
+ crow::Response &res,
+ const std::string &path) {
+ std::string objectPath = "/xyz/" + path;
+
+ // Trim any trailing "/" at the end
+ if (boost::ends_with(objectPath, "/"))
+ {
+ objectPath.pop_back();
+ }
+
+ // If accessing a single attribute, fill in and update objectPath,
+ // otherwise leave destProperty blank
+ std::string destProperty = "";
+ const char *attrSeperator = "/attr/";
+ size_t attrPosition = path.find(attrSeperator);
+ if (attrPosition != path.npos)
+ {
+ objectPath = "/xyz/" + path.substr(0, attrPosition);
+ destProperty = path.substr(attrPosition + strlen(attrSeperator),
+ path.length());
+ }
+
+ if (req.method() == "POST"_method)
+ {
+ constexpr const char *action_seperator = "/action/";
+ size_t action_position = path.find(action_seperator);
+ if (action_position != path.npos)
+ {
+ objectPath = "/xyz/" + path.substr(0, action_position);
+ std::string post_property = path.substr(
+ (action_position + strlen(action_seperator)),
+ path.length());
+ handle_action(req, res, objectPath, post_property);
+ return;
+ }
+ }
+ else if (req.method() == "GET"_method)
+ {
+ if (boost::ends_with(objectPath, "/enumerate"))
+ {
+ objectPath.erase(objectPath.end() - 10, objectPath.end());
+ handle_enumerate(res, objectPath);
+ }
+ else if (boost::ends_with(objectPath, "/list"))
+ {
+ objectPath.erase(objectPath.end() - 5, objectPath.end());
+ handle_list(res, objectPath);
+ }
+ else
+ {
+ handle_get(res, objectPath, destProperty);
+ }
+ return;
+ }
+ else if (req.method() == "PUT"_method)
+ {
+ handlePut(req, res, objectPath, destProperty);
+ return;
+ }
+
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/<str>/")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &Connection) {
+ std::shared_ptr<nlohmann::json> transaction;
+ introspectObjects(res, Connection, "/", transaction);
+ });
+
+ BMCWEB_ROUTE(app, "/download/dump/<str>/")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &dumpId) {
+ std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
+ if (!std::regex_match(dumpId, validFilename))
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::experimental::filesystem::path loc(
+ "/var/lib/phosphor-debug-collector/dumps");
+
+ loc += dumpId;
+
+ if (!std::experimental::filesystem::exists(loc) ||
+ !std::experimental::filesystem::is_directory(loc))
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::experimental::filesystem::directory_iterator files(loc);
+ for (auto &file : files)
+ {
+ std::ifstream readFile(file.path());
+ if (readFile.good())
+ {
+ continue;
+ }
+ res.addHeader("Content-Type", "application/octet-stream");
+ res.body() = {std::istreambuf_iterator<char>(readFile),
+ std::istreambuf_iterator<char>()};
+ res.end();
+ }
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &processName,
+ const std::string &requestedPath) {
+ std::vector<std::string> strs;
+ boost::split(strs, requestedPath, boost::is_any_of("/"));
+ std::string objectPath;
+ std::string interfaceName;
+ std::string methodName;
+ auto it = strs.begin();
+ if (it == strs.end())
+ {
+ objectPath = "/";
+ }
+ 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())
+ {
+ objectPath += "/" + *it;
+ }
+ it++;
+ }
+ if (it != strs.end())
+ {
+ interfaceName = *it;
+ it++;
+
+ // after interface, we might have a method name
+ if (it != strs.end())
+ {
+ methodName = *it;
+ it++;
+ }
+ }
+ if (it != strs.end())
+ {
+ // if there is more levels past the method name, something went
+ // wrong, return not found
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ if (interfaceName.empty())
+ {
+ crow::connections::systemBus->async_method_call(
+ [&, processName,
+ objectPath](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "XML document failed to parse "
+ << processName << " " << objectPath << "\n";
+ res.jsonValue = {{"status", "XML parse error"}};
+ res.result(boost::beast::http::status::
+ internal_server_error);
+ }
+ else
+ {
+ nlohmann::json interfacesArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr)
+ {
+ std::string ifaceName =
+ interface->Attribute("name");
+ interfacesArray.push_back(
+ {{"name", ifaceName}});
+
+ interface = interface->NextSiblingElement(
+ "interface");
+ }
+ res.jsonValue = {
+ {"status", "ok"},
+ {"bus_name", processName},
+ {"interfaces", interfacesArray},
+ {"objectPath", objectPath}};
+ }
+ }
+ res.end();
+ },
+ processName, objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ else
+ {
+ crow::connections::systemBus->async_method_call(
+ [&, processName, objectPath,
+ interface_name{std::move(interfaceName)}](
+ const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "XML document failed to parse "
+ << processName << " " << objectPath << "\n";
+ res.result(boost::beast::http::status::
+ internal_server_error);
+ }
+ else
+ {
+ tinyxml2::XMLElement *node =
+ pRoot->FirstChildElement("node");
+
+ // if we know we're the only call, build the
+ // json directly
+ nlohmann::json methodsArray =
+ nlohmann::json::array();
+ nlohmann::json signalsArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr)
+ {
+ std::string ifaceName =
+ interface->Attribute("name");
+
+ if (ifaceName == interfaceName)
+ {
+ tinyxml2::XMLElement *methods =
+ interface->FirstChildElement(
+ "method");
+ while (methods != nullptr)
+ {
+ nlohmann::json argsArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *arg =
+ methods->FirstChildElement(
+ "arg");
+ while (arg != nullptr)
+ {
+ argsArray.push_back(
+ {{"name",
+ arg->Attribute("name")},
+ {"type",
+ arg->Attribute("type")},
+ {"direction",
+ arg->Attribute(
+ "direction")}});
+ arg = arg->NextSiblingElement(
+ "arg");
+ }
+ methodsArray.push_back(
+ {{"name",
+ methods->Attribute("name")},
+ {"uri",
+ "/bus/system/" + processName +
+ objectPath + "/" +
+ interfaceName + "/" +
+ methods->Attribute(
+ "name")},
+ {"args", argsArray}});
+ methods =
+ methods->NextSiblingElement(
+ "method");
+ }
+ tinyxml2::XMLElement *signals =
+ interface->FirstChildElement(
+ "signal");
+ while (signals != nullptr)
+ {
+ nlohmann::json argsArray =
+ nlohmann::json::array();
+
+ tinyxml2::XMLElement *arg =
+ signals->FirstChildElement(
+ "arg");
+ while (arg != nullptr)
+ {
+ std::string name =
+ arg->Attribute("name");
+ std::string type =
+ arg->Attribute("type");
+ argsArray.push_back({
+ {"name", name},
+ {"type", type},
+ });
+ arg = arg->NextSiblingElement(
+ "arg");
+ }
+ signalsArray.push_back(
+ {{"name",
+ signals->Attribute("name")},
+ {"args", argsArray}});
+ signals =
+ signals->NextSiblingElement(
+ "signal");
+ }
+
+ res.jsonValue = {
+ {"status", "ok"},
+ {"bus_name", processName},
+ {"interface", interfaceName},
+ {"methods", methodsArray},
+ {"objectPath", objectPath},
+ {"properties",
+ nlohmann::json::object()},
+ {"signals", signalsArray}};
+
+ 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.result(
+ boost::beast::http::status::not_found);
+ }
+ }
+ }
+ res.end();
+ },
+ processName, objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ });
+}
+} // namespace openbmc_mapper
+} // namespace crow
diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
index 65e4740..f51f9aa 100644
--- a/include/pam_authenticate.hpp
+++ b/include/pam_authenticate.hpp
@@ -1,72 +1,84 @@
#pragma once
#include <security/pam_appl.h>
+
+#include <boost/utility/string_view.hpp>
#include <cstring>
#include <memory>
-#include <boost/utility/string_view.hpp>
// function used to get user input
inline int pamFunctionConversation(int numMsg, const struct pam_message** msg,
- struct pam_response** resp,
- void* appdataPtr) {
- if (appdataPtr == nullptr) {
- return PAM_AUTH_ERR;
- }
- auto* pass = reinterpret_cast<char*>(
- malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1));
- std::strcpy(pass, reinterpret_cast<char*>(appdataPtr));
+ struct pam_response** resp, void* appdataPtr)
+{
+ if (appdataPtr == nullptr)
+ {
+ return PAM_AUTH_ERR;
+ }
+ auto* pass = reinterpret_cast<char*>(
+ malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1));
+ std::strcpy(pass, reinterpret_cast<char*>(appdataPtr));
- *resp = reinterpret_cast<pam_response*>(
- calloc(numMsg, sizeof(struct pam_response)));
+ *resp = reinterpret_cast<pam_response*>(
+ calloc(numMsg, sizeof(struct pam_response)));
- for (int i = 0; i < numMsg; ++i) {
- /* Ignore all PAM messages except prompting for hidden input */
- if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) {
- continue;
+ for (int i = 0; i < numMsg; ++i)
+ {
+ /* Ignore all PAM messages except prompting for hidden input */
+ 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;
}
- /* Assume PAM is only prompting for the password as hidden input */
- resp[i]->resp = pass;
- }
-
- return PAM_SUCCESS;
+ return PAM_SUCCESS;
}
inline bool pamAuthenticateUser(const boost::string_view username,
- const boost::string_view password) {
- std::string userStr(username);
- std::string passStr(password);
- const struct pam_conv localConversation = {
- pamFunctionConversation, const_cast<char*>(passStr.c_str())};
- pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
+ const boost::string_view password)
+{
+ std::string userStr(username);
+ std::string passStr(password);
+ const struct pam_conv localConversation = {
+ pamFunctionConversation, const_cast<char*>(passStr.c_str())};
+ pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
- if (pam_start("webserver", userStr.c_str(), &localConversation,
- &localAuthHandle) != PAM_SUCCESS) {
- return false;
- }
- int retval =
- pam_authenticate(localAuthHandle, 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);
+ if (pam_start("webserver", userStr.c_str(), &localConversation,
+ &localAuthHandle) != PAM_SUCCESS)
+ {
+ return false;
}
- pam_end(localAuthHandle, PAM_SUCCESS);
- return false;
- }
+ int retval = pam_authenticate(localAuthHandle,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
- /* check that the account is healthy */
- if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
- PAM_SUCCESS) {
- pam_end(localAuthHandle, PAM_SUCCESS);
- return false;
- }
+ if (retval != PAM_SUCCESS)
+ {
+ if (retval == PAM_AUTH_ERR)
+ {
+ // printf("Authentication failure.\n");
+ }
+ else
+ {
+ // printf("pam_authenticate returned %d\n", retval);
+ }
+ pam_end(localAuthHandle, PAM_SUCCESS);
+ return false;
+ }
- if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) {
- return false;
- }
+ /* check that the account is healthy */
+ if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
+ PAM_SUCCESS)
+ {
+ pam_end(localAuthHandle, PAM_SUCCESS);
+ return false;
+ }
- return true;
+ if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
+ {
+ return false;
+ }
+
+ return true;
}
diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp
index 706f6f4..b384f02 100644
--- a/include/persistent_data_middleware.hpp
+++ b/include/persistent_data_middleware.hpp
@@ -1,121 +1,165 @@
#pragma once
-#include <nlohmann/json.hpp>
-#include <pam_authenticate.hpp>
-#include <sessions.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_map.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <nlohmann/json.hpp>
+#include <pam_authenticate.hpp>
+#include <random>
+#include <sessions.hpp>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace persistent_data {
+namespace persistent_data
+{
-class Middleware {
- // todo(ed) should read this from a fixed location somewhere, not CWD
- static constexpr const char* filename = "bmcweb_persistent_data.json";
- int jsonRevision = 1;
+class Middleware
+{
+ // todo(ed) should read this from a fixed location somewhere, not CWD
+ static constexpr const char* filename = "bmcweb_persistent_data.json";
+ int jsonRevision = 1;
- public:
- struct Context {};
+ public:
+ struct Context
+ {
+ };
- Middleware() { readData(); }
-
- ~Middleware() {
- if (persistent_data::SessionStore::getInstance().needsWrite()) {
- writeData();
+ Middleware()
+ {
+ readData();
}
- }
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {}
-
- void afterHandle(Request& req, Response& res, Context& ctx) {}
-
- // TODO(ed) this should really use protobuf, or some other serialization
- // library, but adding another dependency is somewhat outside the scope of
- // this application for the moment
- void readData() {
- std::ifstream persistentFile(filename);
- int fileRevision = 0;
- if (persistentFile.is_open()) {
- // call with exceptions disabled
- auto data = nlohmann::json::parse(persistentFile, nullptr, false);
- if (data.is_discarded()) {
- BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
- } else {
- for (const auto& item : data.items()) {
- if (item.key() == "revision") {
- fileRevision = 0;
-
- const uint64_t* uintPtr = item.value().get_ptr<const uint64_t*>();
- if (uintPtr == nullptr) {
- BMCWEB_LOG_ERROR << "Failed to read revision flag";
- } else {
- fileRevision = *uintPtr;
- }
- } else if (item.key() == "system_uuid") {
- const std::string* jSystemUuid =
- item.value().get_ptr<const std::string*>();
- if (jSystemUuid != nullptr) {
- systemUuid = *jSystemUuid;
- }
- } else if (item.key() == "sessions") {
- for (const auto& elem : item.value()) {
- std::shared_ptr<UserSession> newSession =
- UserSession::fromJson(elem);
-
- if (newSession == nullptr) {
- BMCWEB_LOG_ERROR
- << "Problem reading session from persistent store";
- continue;
- }
-
- BMCWEB_LOG_DEBUG << "Restored session: " << newSession->csrfToken
- << " " << newSession->uniqueId << " "
- << newSession->sessionToken;
- SessionStore::getInstance().authTokens.emplace(
- newSession->sessionToken, newSession);
- }
- } else {
- // Do nothing in the case of extra fields. We may have cases where
- // fields are added in the future, and we want to at least attempt
- // to gracefully support downgrades in that case, even if we don't
- // officially support it
- }
+ ~Middleware()
+ {
+ if (persistent_data::SessionStore::getInstance().needsWrite())
+ {
+ writeData();
}
- }
}
- bool needWrite = false;
- if (systemUuid.empty()) {
- systemUuid = boost::uuids::to_string(boost::uuids::random_generator()());
- needWrite = true;
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
}
- if (fileRevision < jsonRevision) {
- needWrite = true;
- }
- // write revision changes or system uuid changes immediately
- if (needWrite) {
- writeData();
- }
- }
- void writeData() {
- std::ofstream persistentFile(filename);
- nlohmann::json data{{"sessions", SessionStore::getInstance().authTokens},
- {"system_uuid", systemUuid},
- {"revision", jsonRevision}};
- persistentFile << data;
- }
+ void afterHandle(Request& req, Response& res, Context& ctx)
+ {
+ }
- std::string systemUuid{""};
+ // TODO(ed) this should really use protobuf, or some other serialization
+ // library, but adding another dependency is somewhat outside the scope of
+ // this application for the moment
+ void readData()
+ {
+ std::ifstream persistentFile(filename);
+ int fileRevision = 0;
+ if (persistentFile.is_open())
+ {
+ // call with exceptions disabled
+ auto data = nlohmann::json::parse(persistentFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ BMCWEB_LOG_ERROR
+ << "Error parsing persistent data in json file.";
+ }
+ else
+ {
+ for (const auto& item : data.items())
+ {
+ if (item.key() == "revision")
+ {
+ fileRevision = 0;
+
+ const uint64_t* uintPtr =
+ item.value().get_ptr<const uint64_t*>();
+ if (uintPtr == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read revision flag";
+ }
+ else
+ {
+ fileRevision = *uintPtr;
+ }
+ }
+ else if (item.key() == "system_uuid")
+ {
+ const std::string* jSystemUuid =
+ item.value().get_ptr<const std::string*>();
+ if (jSystemUuid != nullptr)
+ {
+ systemUuid = *jSystemUuid;
+ }
+ }
+ else if (item.key() == "sessions")
+ {
+ for (const auto& elem : item.value())
+ {
+ std::shared_ptr<UserSession> newSession =
+ UserSession::fromJson(elem);
+
+ if (newSession == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Problem reading session "
+ "from persistent store";
+ continue;
+ }
+
+ BMCWEB_LOG_DEBUG
+ << "Restored session: " << newSession->csrfToken
+ << " " << newSession->uniqueId << " "
+ << newSession->sessionToken;
+ SessionStore::getInstance().authTokens.emplace(
+ newSession->sessionToken, newSession);
+ }
+ }
+ else
+ {
+ // Do nothing in the case of extra fields. We may have
+ // cases where fields are added in the future, and we
+ // want to at least attempt to gracefully support
+ // downgrades in that case, even if we don't officially
+ // support it
+ }
+ }
+ }
+ }
+ bool needWrite = false;
+
+ if (systemUuid.empty())
+ {
+ systemUuid =
+ boost::uuids::to_string(boost::uuids::random_generator()());
+ needWrite = true;
+ }
+ if (fileRevision < jsonRevision)
+ {
+ needWrite = true;
+ }
+ // write revision changes or system uuid changes immediately
+ if (needWrite)
+ {
+ writeData();
+ }
+ }
+
+ void writeData()
+ {
+ std::ofstream persistentFile(filename);
+ nlohmann::json data{
+ {"sessions", SessionStore::getInstance().authTokens},
+ {"system_uuid", systemUuid},
+ {"revision", jsonRevision}};
+ persistentFile << data;
+ }
+
+ std::string systemUuid{""};
};
-} // namespace persistent_data
-} // namespace crow
+} // namespace persistent_data
+} // namespace crow
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index b81aa54..13e1838 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -1,15 +1,18 @@
#pragma once
+#include <crow/app.h>
+
+#include <boost/algorithm/string.hpp>
#include <dbus_singleton.hpp>
-#include <persistent_data_middleware.hpp>
-#include <token_authorization_middleware.hpp>
#include <fstream>
+#include <persistent_data_middleware.hpp>
#include <streambuf>
#include <string>
-#include <crow/app.h>
-#include <boost/algorithm/string.hpp>
-namespace crow {
-namespace redfish {
+#include <token_authorization_middleware.hpp>
+namespace crow
+{
+namespace redfish
+{
using ManagedObjectType = std::vector<std::pair<
sdbusplus::message::object_path,
@@ -17,108 +20,130 @@
std::string, boost::container::flat_map<
std::string, sdbusplus::message::variant<bool>>>>>;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/redfish/")
- .methods("GET"_method)([](const crow::Request& req, crow::Response& res) {
- res.jsonValue = {{"v1", "/redfish/v1/"}};
- res.end();
- });
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/")
+ .methods("GET"_method)(
+ [](const crow::Request& req, crow::Response& res) {
+ res.jsonValue = {{"v1", "/redfish/v1/"}};
+ res.end();
+ });
- BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
- .methods(
- "GET"_method)([&](const crow::Request& req, crow::Response& res) {
- crow::connections::systemBus->async_method_call(
- [&](const boost::system::error_code ec,
- const ManagedObjectType& users) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- res.jsonValue = {
- {"@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 memberArray = nlohmann::json::array();
- int userIndex = 0;
- for (auto& user : users) {
- const std::string& path =
- static_cast<const std::string&>(user.first);
- std::size_t lastIndex = path.rfind("/");
- if (lastIndex == std::string::npos) {
- lastIndex = 0;
- } else {
- lastIndex += 1;
- }
- memberArray.push_back(
- {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
- path.substr(lastIndex)}});
- }
- res.jsonValue["Members"] = memberArray;
- }
- res.end();
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+ BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
+ .methods(
+ "GET"_method)([&](const crow::Request& req, crow::Response& res) {
+ crow::connections::systemBus->async_method_call(
+ [&](const boost::system::error_code ec,
+ const ManagedObjectType& users) {
+ if (ec)
+ {
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ res.jsonValue = {
+ {"@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 memberArray = nlohmann::json::array();
+ int userIndex = 0;
+ for (auto& user : users)
+ {
+ const std::string& path =
+ static_cast<const std::string&>(user.first);
+ std::size_t lastIndex = path.rfind("/");
+ if (lastIndex == std::string::npos)
+ {
+ lastIndex = 0;
+ }
+ else
+ {
+ lastIndex += 1;
+ }
+ memberArray.push_back(
+ {{"@odata.id",
+ "/redfish/v1/AccountService/Accounts/" +
+ path.substr(lastIndex)}});
+ }
+ res.jsonValue["Members"] = memberArray;
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ });
- BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
- .methods("GET"_method)([](const crow::Request& req, crow::Response& res,
- const std::string& account_name) {
-
- crow::connections::systemBus->async_method_call(
- [&, accountName{std::move(account_name)} ](
- const boost::system::error_code ec,
- const ManagedObjectType& users) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- for (auto& user : users) {
- const std::string& path =
- static_cast<const std::string&>(user.first);
- std::size_t lastIndex = path.rfind("/");
- if (lastIndex == std::string::npos) {
- lastIndex = 0;
- } else {
- lastIndex += 1;
- }
- if (path.substr(lastIndex) == accountName) {
- res.jsonValue = {
- {"@odata.context",
- "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
- {"@odata.id", "/redfish/v1/AccountService/Accounts/1"},
- {"@odata.type",
- "#ManagerAccount.v1_0_3.ManagerAccount"},
- {"Id", "1"},
- {"Name", "User Account"},
- {"Description", "User Account"},
- {"Enabled", false},
- {"Password", nullptr},
- {"UserName", accountName},
- {"RoleId", "Administrator"},
- {"Links",
- {{"Role",
- {{"@odata.id",
- "/redfish/v1/AccountService/Roles/"
- "Administrator"}}}}}};
- break;
- }
- }
- if (res.jsonValue.is_null()) {
- res.result(boost::beast::http::status::not_found);
- }
- }
- res.end();
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+ BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
+ .methods("GET"_method)([](const crow::Request& req, crow::Response& res,
+ const std::string& account_name) {
+ crow::connections::systemBus->async_method_call(
+ [&, accountName{std::move(account_name)}](
+ const boost::system::error_code ec,
+ const ManagedObjectType& users) {
+ if (ec)
+ {
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ for (auto& user : users)
+ {
+ const std::string& path =
+ static_cast<const std::string&>(user.first);
+ std::size_t lastIndex = path.rfind("/");
+ if (lastIndex == std::string::npos)
+ {
+ lastIndex = 0;
+ }
+ else
+ {
+ lastIndex += 1;
+ }
+ if (path.substr(lastIndex) == accountName)
+ {
+ res.jsonValue = {
+ {"@odata.context",
+ "/redfish/v1/"
+ "$metadata#ManagerAccount.ManagerAccount"},
+ {"@odata.id",
+ "/redfish/v1/AccountService/Accounts/1"},
+ {"@odata.type",
+ "#ManagerAccount.v1_0_3.ManagerAccount"},
+ {"Id", "1"},
+ {"Name", "User Account"},
+ {"Description", "User Account"},
+ {"Enabled", false},
+ {"Password", nullptr},
+ {"UserName", accountName},
+ {"RoleId", "Administrator"},
+ {"Links",
+ {{"Role",
+ {{"@odata.id",
+ "/redfish/v1/AccountService/Roles/"
+ "Administrator"}}}}}};
+ break;
+ }
+ }
+ if (res.jsonValue.is_null())
+ {
+ res.result(boost::beast::http::status::not_found);
+ }
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ });
}
-} // namespace redfish
-} // namespace crow
+} // namespace redfish
+} // namespace crow
diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp
index 750f87b..561fd81 100644
--- a/include/security_headers_middleware.hpp
+++ b/include/security_headers_middleware.hpp
@@ -3,7 +3,8 @@
#include <crow/http_request.h>
#include <crow/http_response.h>
-namespace crow {
+namespace crow
+{
static const char* strictTransportSecurityKey = "Strict-Transport-Security";
static const char* strictTransportSecurityValue =
"max-age=31536000; includeSubdomains; preload";
@@ -26,40 +27,46 @@
static const char* cacheControlKey = "Cache-Control";
static const char* cacheControlValue = "no-Store,no-Cache";
-struct SecurityHeadersMiddleware {
- struct Context {};
+struct SecurityHeadersMiddleware
+{
+ struct Context
+ {
+ };
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
#ifdef BMCWEB_INSECURE_DISABLE_XSS_PREVENTION
- if ("OPTIONS"_method == req.method()) {
- res.end();
+ if ("OPTIONS"_method == req.method())
+ {
+ res.end();
+ }
+#endif
}
-#endif
- }
- void afterHandle(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
- javascript file. It doesn't hurt anything, it's just ugly.
- */
- res.addHeader(strictTransportSecurityKey, strictTransportSecurityValue);
- res.addHeader(uaCompatabilityKey, uaCompatabilityValue);
- res.addHeader(xframeKey, xframeValue);
- res.addHeader(xssKey, xssValue);
- res.addHeader(contentSecurityKey, contentSecurityValue);
- res.addHeader(pragmaKey, pragmaValue);
- res.addHeader(cacheControlKey, cacheControlValue);
+ void afterHandle(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
+ javascript file. It doesn't hurt anything, it's just ugly.
+ */
+ res.addHeader(strictTransportSecurityKey, strictTransportSecurityValue);
+ res.addHeader(uaCompatabilityKey, uaCompatabilityValue);
+ res.addHeader(xframeKey, xframeValue);
+ res.addHeader(xssKey, xssValue);
+ res.addHeader(contentSecurityKey, contentSecurityValue);
+ res.addHeader(pragmaKey, pragmaValue);
+ res.addHeader(cacheControlKey, cacheControlValue);
#ifdef BMCWEB_INSECURE_DISABLE_XSS_PREVENTION
- res.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
- res.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH");
- res.addHeader("Access-Control-Allow-Credentials", "true");
- res.addHeader("Access-Control-Allow-Headers",
- "Origin, Content-Type, Accept, Cookie, X-XSRF-TOKEN");
+ res.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
+ res.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH");
+ res.addHeader("Access-Control-Allow-Credentials", "true");
+ res.addHeader("Access-Control-Allow-Headers",
+ "Origin, Content-Type, Accept, Cookie, X-XSRF-TOKEN");
#endif
- }
+ }
};
-} // namespace crow
+} // namespace crow
diff --git a/include/sessions.hpp b/include/sessions.hpp
index f549fde..510f566 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -1,232 +1,284 @@
#pragma once
-#include <nlohmann/json.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_map.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <nlohmann/json.hpp>
+#include <pam_authenticate.hpp>
+#include <random>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace persistent_data {
+namespace persistent_data
+{
-enum class PersistenceType {
- TIMEOUT, // User session times out after a predetermined amount of time
- SINGLE_REQUEST // User times out once this request is completed.
+enum class PersistenceType
+{
+ TIMEOUT, // User session times out after a predetermined amount of time
+ SINGLE_REQUEST // User times out once this request is completed.
};
-struct UserSession {
- std::string uniqueId;
- std::string sessionToken;
- std::string username;
- std::string csrfToken;
- std::chrono::time_point<std::chrono::steady_clock> lastUpdated;
- PersistenceType persistence;
+struct UserSession
+{
+ std::string uniqueId;
+ std::string sessionToken;
+ std::string username;
+ std::string csrfToken;
+ std::chrono::time_point<std::chrono::steady_clock> lastUpdated;
+ PersistenceType persistence;
- /**
- * @brief Fills object with data from UserSession's JSON representation
- *
- * This replaces nlohmann's from_json to ensure no-throw approach
- *
- * @param[in] j JSON object from which data should be loaded
- *
- * @return a shared pointer if data has been loaded properly, nullptr
- * otherwise
- */
- static std::shared_ptr<UserSession> fromJson(const nlohmann::json& j) {
- std::shared_ptr<UserSession> userSession = std::make_shared<UserSession>();
- for (const auto& element : j.items()) {
- const std::string* thisValue =
- element.value().get_ptr<const std::string*>();
- if (thisValue == nullptr) {
- BMCWEB_LOG_ERROR << "Error reading persistent store. Property "
- << element.key() << " was not of type string";
- return nullptr;
- }
- if (element.key() == "unique_id") {
- userSession->uniqueId = *thisValue;
- } else if (element.key() == "session_token") {
- userSession->sessionToken = *thisValue;
- } else if (element.key() == "csrf_token") {
- userSession->csrfToken = *thisValue;
- } else if (element.key() == "username") {
- userSession->username = *thisValue;
- } else {
- BMCWEB_LOG_ERROR << "Got unexpected property reading persistent file: "
- << element.key();
- return nullptr;
- }
+ /**
+ * @brief Fills object with data from UserSession's JSON representation
+ *
+ * This replaces nlohmann's from_json to ensure no-throw approach
+ *
+ * @param[in] j JSON object from which data should be loaded
+ *
+ * @return a shared pointer if data has been loaded properly, nullptr
+ * otherwise
+ */
+ static std::shared_ptr<UserSession> fromJson(const nlohmann::json& j)
+ {
+ std::shared_ptr<UserSession> userSession =
+ std::make_shared<UserSession>();
+ for (const auto& element : j.items())
+ {
+ const std::string* thisValue =
+ element.value().get_ptr<const std::string*>();
+ if (thisValue == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Error reading persistent store. Property "
+ << element.key() << " was not of type string";
+ return nullptr;
+ }
+ if (element.key() == "unique_id")
+ {
+ userSession->uniqueId = *thisValue;
+ }
+ else if (element.key() == "session_token")
+ {
+ userSession->sessionToken = *thisValue;
+ }
+ else if (element.key() == "csrf_token")
+ {
+ userSession->csrfToken = *thisValue;
+ }
+ else if (element.key() == "username")
+ {
+ userSession->username = *thisValue;
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "Got unexpected property reading persistent file: "
+ << element.key();
+ return nullptr;
+ }
+ }
+
+ // For now, sessions that were persisted through a reboot get their idle
+ // timer reset. This could probably be overcome with a better
+ // understanding of wall clock time and steady timer time, possibly
+ // persisting values with wall clock time instead of steady timer, but
+ // the tradeoffs of all the corner cases involved are non-trivial, so
+ // this is done temporarily
+ userSession->lastUpdated = std::chrono::steady_clock::now();
+ userSession->persistence = PersistenceType::TIMEOUT;
+
+ return userSession;
}
-
- // For now, sessions that were persisted through a reboot get their idle
- // timer reset. This could probably be overcome with a better understanding
- // of wall clock time and steady timer time, possibly persisting values with
- // wall clock time instead of steady timer, but the tradeoffs of all the
- // corner cases involved are non-trivial, so this is done temporarily
- userSession->lastUpdated = std::chrono::steady_clock::now();
- userSession->persistence = PersistenceType::TIMEOUT;
-
- return userSession;
- }
};
class Middleware;
-class SessionStore {
- public:
- std::shared_ptr<UserSession> generateUserSession(
- const boost::string_view username,
- PersistenceType persistence = PersistenceType::TIMEOUT) {
- // TODO(ed) find a secure way to not generate session identifiers if
- // persistence is set to SINGLE_REQUEST
- static constexpr std::array<char, 62> alphanum = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'b', 'C',
- 'D', 'E', 'F', 'g', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'r', 'S', 'T', 'U', 'v', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
- 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+class SessionStore
+{
+ public:
+ std::shared_ptr<UserSession> generateUserSession(
+ const boost::string_view username,
+ PersistenceType persistence = PersistenceType::TIMEOUT)
+ {
+ // TODO(ed) find a secure way to not generate session identifiers if
+ // persistence is set to SINGLE_REQUEST
+ static constexpr std::array<char, 62> alphanum = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'b', 'C',
+ 'D', 'E', 'F', 'g', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'r', 'S', 'T', 'U', 'v', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
+ 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
- // entropy: 30 characters, 62 possibilities. log2(62^30) = 178 bits of
- // entropy. OWASP recommends at least 60
- // https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Entropy
- std::string sessionToken;
- sessionToken.resize(20, '0');
- std::uniform_int_distribution<int> dist(0, alphanum.size() - 1);
- for (int i = 0; i < sessionToken.size(); ++i) {
- sessionToken[i] = alphanum[dist(rd)];
- }
- // Only need csrf tokens for cookie based auth, token doesn't matter
- std::string csrfToken;
- csrfToken.resize(20, '0');
- for (int i = 0; i < csrfToken.size(); ++i) {
- csrfToken[i] = alphanum[dist(rd)];
- }
-
- std::string uniqueId;
- uniqueId.resize(10, '0');
- for (int i = 0; i < uniqueId.size(); ++i) {
- uniqueId[i] = alphanum[dist(rd)];
- }
- auto session = std::make_shared<UserSession>(
- UserSession{uniqueId, sessionToken, std::string(username), csrfToken,
- std::chrono::steady_clock::now(), persistence});
- auto it = authTokens.emplace(std::make_pair(sessionToken, session));
- // Only need to write to disk if session isn't about to be destroyed.
- needWrite = persistence == PersistenceType::TIMEOUT;
- return it.first->second;
- }
-
- std::shared_ptr<UserSession> loginSessionByToken(
- const boost::string_view token) {
- applySessionTimeouts();
- auto sessionIt = authTokens.find(std::string(token));
- if (sessionIt == authTokens.end()) {
- return nullptr;
- }
- std::shared_ptr<UserSession> userSession = sessionIt->second;
- userSession->lastUpdated = std::chrono::steady_clock::now();
- return userSession;
- }
-
- std::shared_ptr<UserSession> getSessionByUid(const boost::string_view uid) {
- applySessionTimeouts();
- // TODO(Ed) this is inefficient
- auto sessionIt = authTokens.begin();
- while (sessionIt != authTokens.end()) {
- if (sessionIt->second->uniqueId == uid) {
- return sessionIt->second;
- }
- sessionIt++;
- }
- return nullptr;
- }
-
- void removeSession(std::shared_ptr<UserSession> session) {
- authTokens.erase(session->sessionToken);
- needWrite = true;
- }
-
- std::vector<const std::string*> getUniqueIds(
- bool getAll = true,
- const PersistenceType& type = PersistenceType::SINGLE_REQUEST) {
- applySessionTimeouts();
-
- std::vector<const std::string*> ret;
- ret.reserve(authTokens.size());
- for (auto& session : authTokens) {
- if (getAll || type == session.second->persistence) {
- ret.push_back(&session.second->uniqueId);
- }
- }
- return ret;
- }
-
- bool needsWrite() { return needWrite; }
- int getTimeoutInSeconds() const {
- return std::chrono::seconds(timeoutInMinutes).count();
- };
-
- // Persistent data middleware needs to be able to serialize our authTokens
- // structure, which is private
- friend Middleware;
-
- static SessionStore& getInstance() {
- static SessionStore sessionStore;
- return sessionStore;
- }
-
- SessionStore(const SessionStore&) = delete;
- SessionStore& operator=(const SessionStore&) = delete;
-
- private:
- SessionStore() : timeoutInMinutes(60) {}
-
- void applySessionTimeouts() {
- auto timeNow = std::chrono::steady_clock::now();
- if (timeNow - lastTimeoutUpdate > std::chrono::minutes(1)) {
- lastTimeoutUpdate = timeNow;
- auto authTokensIt = authTokens.begin();
- while (authTokensIt != authTokens.end()) {
- if (timeNow - authTokensIt->second->lastUpdated >= timeoutInMinutes) {
- authTokensIt = authTokens.erase(authTokensIt);
- needWrite = true;
- } else {
- authTokensIt++;
+ // entropy: 30 characters, 62 possibilities. log2(62^30) = 178 bits of
+ // entropy. OWASP recommends at least 60
+ // https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Entropy
+ std::string sessionToken;
+ sessionToken.resize(20, '0');
+ std::uniform_int_distribution<int> dist(0, alphanum.size() - 1);
+ for (int i = 0; i < sessionToken.size(); ++i)
+ {
+ sessionToken[i] = alphanum[dist(rd)];
}
- }
+ // Only need csrf tokens for cookie based auth, token doesn't matter
+ std::string csrfToken;
+ csrfToken.resize(20, '0');
+ for (int i = 0; i < csrfToken.size(); ++i)
+ {
+ csrfToken[i] = alphanum[dist(rd)];
+ }
+
+ std::string uniqueId;
+ uniqueId.resize(10, '0');
+ for (int i = 0; i < uniqueId.size(); ++i)
+ {
+ uniqueId[i] = alphanum[dist(rd)];
+ }
+ auto session = std::make_shared<UserSession>(UserSession{
+ uniqueId, sessionToken, std::string(username), csrfToken,
+ std::chrono::steady_clock::now(), persistence});
+ auto it = authTokens.emplace(std::make_pair(sessionToken, session));
+ // Only need to write to disk if session isn't about to be destroyed.
+ needWrite = persistence == PersistenceType::TIMEOUT;
+ return it.first->second;
}
- }
- std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate;
- boost::container::flat_map<std::string, std::shared_ptr<UserSession>>
- authTokens;
- std::random_device rd;
- bool needWrite{false};
- std::chrono::minutes timeoutInMinutes;
+
+ std::shared_ptr<UserSession>
+ loginSessionByToken(const boost::string_view token)
+ {
+ applySessionTimeouts();
+ auto sessionIt = authTokens.find(std::string(token));
+ if (sessionIt == authTokens.end())
+ {
+ return nullptr;
+ }
+ std::shared_ptr<UserSession> userSession = sessionIt->second;
+ userSession->lastUpdated = std::chrono::steady_clock::now();
+ return userSession;
+ }
+
+ std::shared_ptr<UserSession> getSessionByUid(const boost::string_view uid)
+ {
+ applySessionTimeouts();
+ // TODO(Ed) this is inefficient
+ auto sessionIt = authTokens.begin();
+ while (sessionIt != authTokens.end())
+ {
+ if (sessionIt->second->uniqueId == uid)
+ {
+ return sessionIt->second;
+ }
+ sessionIt++;
+ }
+ return nullptr;
+ }
+
+ void removeSession(std::shared_ptr<UserSession> session)
+ {
+ authTokens.erase(session->sessionToken);
+ needWrite = true;
+ }
+
+ std::vector<const std::string*> getUniqueIds(
+ bool getAll = true,
+ const PersistenceType& type = PersistenceType::SINGLE_REQUEST)
+ {
+ applySessionTimeouts();
+
+ std::vector<const std::string*> ret;
+ ret.reserve(authTokens.size());
+ for (auto& session : authTokens)
+ {
+ if (getAll || type == session.second->persistence)
+ {
+ ret.push_back(&session.second->uniqueId);
+ }
+ }
+ return ret;
+ }
+
+ bool needsWrite()
+ {
+ return needWrite;
+ }
+ int getTimeoutInSeconds() const
+ {
+ return std::chrono::seconds(timeoutInMinutes).count();
+ };
+
+ // Persistent data middleware needs to be able to serialize our authTokens
+ // structure, which is private
+ friend Middleware;
+
+ static SessionStore& getInstance()
+ {
+ static SessionStore sessionStore;
+ return sessionStore;
+ }
+
+ SessionStore(const SessionStore&) = delete;
+ SessionStore& operator=(const SessionStore&) = delete;
+
+ private:
+ SessionStore() : timeoutInMinutes(60)
+ {
+ }
+
+ void applySessionTimeouts()
+ {
+ auto timeNow = std::chrono::steady_clock::now();
+ if (timeNow - lastTimeoutUpdate > std::chrono::minutes(1))
+ {
+ lastTimeoutUpdate = timeNow;
+ auto authTokensIt = authTokens.begin();
+ while (authTokensIt != authTokens.end())
+ {
+ if (timeNow - authTokensIt->second->lastUpdated >=
+ timeoutInMinutes)
+ {
+ authTokensIt = authTokens.erase(authTokensIt);
+ needWrite = true;
+ }
+ else
+ {
+ authTokensIt++;
+ }
+ }
+ }
+ }
+ std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate;
+ boost::container::flat_map<std::string, std::shared_ptr<UserSession>>
+ authTokens;
+ std::random_device rd;
+ bool needWrite{false};
+ std::chrono::minutes timeoutInMinutes;
};
-} // namespace persistent_data
-} // namespace crow
+} // namespace persistent_data
+} // namespace crow
// to_json(...) definition for objects of UserSession type
-namespace nlohmann {
+namespace nlohmann
+{
template <>
-struct adl_serializer<std::shared_ptr<crow::persistent_data::UserSession>> {
- static void to_json(
- nlohmann::json& j,
- const std::shared_ptr<crow::persistent_data::UserSession>& p) {
- if (p->persistence !=
- crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
- j = nlohmann::json{{"unique_id", p->uniqueId},
- {"session_token", p->sessionToken},
- {"username", p->username},
- {"csrf_token", p->csrfToken}};
+struct adl_serializer<std::shared_ptr<crow::persistent_data::UserSession>>
+{
+ static void
+ to_json(nlohmann::json& j,
+ const std::shared_ptr<crow::persistent_data::UserSession>& p)
+ {
+ if (p->persistence !=
+ crow::persistent_data::PersistenceType::SINGLE_REQUEST)
+ {
+ j = nlohmann::json{{"unique_id", p->uniqueId},
+ {"session_token", p->sessionToken},
+ {"username", p->username},
+ {"csrf_token", p->csrfToken}};
+ }
}
- }
};
-} // namespace nlohmann
+} // namespace nlohmann
diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
index 4eac803..47893bf 100644
--- a/include/ssl_key_handler.hpp
+++ b/include/ssl_key_handler.hpp
@@ -10,304 +10,355 @@
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
-#include <random>
-#include <boost/asio.hpp>
-namespace ensuressl {
+#include <boost/asio.hpp>
+#include <random>
+
+namespace ensuressl
+{
static void initOpenssl();
static void cleanupOpenssl();
static EVP_PKEY *createRsaKey();
static EVP_PKEY *createEcKey();
static void handleOpensslError();
-inline bool verifyOpensslKeyCert(const std::string &filepath) {
- bool privateKeyValid = false;
- bool certValid = false;
+inline bool verifyOpensslKeyCert(const std::string &filepath)
+{
+ bool privateKeyValid = false;
+ bool certValid = false;
- std::cout << "Checking certs in file " << filepath << "\n";
+ std::cout << "Checking certs in file " << filepath << "\n";
- FILE *file = fopen(filepath.c_str(), "r");
- if (file != NULL) {
- EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
- int rc;
- if (pkey != nullptr) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa != nullptr) {
- std::cout << "Found an RSA key\n";
- if (RSA_check_key(rsa) == 1) {
- // private_key_valid = true;
- } else {
- std::cerr << "Key not valid error number " << ERR_get_error() << "\n";
+ FILE *file = fopen(filepath.c_str(), "r");
+ if (file != NULL)
+ {
+ EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
+ int rc;
+ if (pkey != nullptr)
+ {
+ RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa != nullptr)
+ {
+ std::cout << "Found an RSA key\n";
+ if (RSA_check_key(rsa) == 1)
+ {
+ // private_key_valid = true;
+ }
+ else
+ {
+ std::cerr << "Key not valid error number "
+ << ERR_get_error() << "\n";
+ }
+ RSA_free(rsa);
+ }
+ else
+ {
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
+ if (ec != nullptr)
+ {
+ std::cout << "Found an EC key\n";
+ if (EC_KEY_check_key(ec) == 1)
+ {
+ privateKeyValid = true;
+ }
+ else
+ {
+ std::cerr << "Key not valid error number "
+ << ERR_get_error() << "\n";
+ }
+ EC_KEY_free(ec);
+ }
+ }
+
+ if (privateKeyValid)
+ {
+ X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
+ if (x509 == nullptr)
+ {
+ std::cout << "error getting x509 cert " << ERR_get_error()
+ << "\n";
+ }
+ else
+ {
+ rc = X509_verify(x509, pkey);
+ if (rc == 1)
+ {
+ certValid = true;
+ }
+ else
+ {
+ std::cerr << "Error in verifying private key signature "
+ << ERR_get_error() << "\n";
+ }
+ }
+ }
+
+ EVP_PKEY_free(pkey);
}
- RSA_free(rsa);
- } else {
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- if (ec != nullptr) {
- std::cout << "Found an EC key\n";
- if (EC_KEY_check_key(ec) == 1) {
- privateKeyValid = true;
- } else {
- std::cerr << "Key not valid error number " << ERR_get_error()
- << "\n";
- }
- EC_KEY_free(ec);
- }
- }
-
- if (privateKeyValid) {
- X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
- if (x509 == nullptr) {
- std::cout << "error getting x509 cert " << ERR_get_error() << "\n";
- } else {
- rc = X509_verify(x509, pkey);
- if (rc == 1) {
- certValid = true;
- } else {
- std::cerr << "Error in verifying private key signature "
- << ERR_get_error() << "\n";
- }
- }
- }
-
- EVP_PKEY_free(pkey);
+ fclose(file);
}
- fclose(file);
- }
- return certValid;
+ return certValid;
}
-inline void generateSslCertificate(const std::string &filepath) {
- FILE *pFile = NULL;
- std::cout << "Generating new keys\n";
- initOpenssl();
+inline void generateSslCertificate(const std::string &filepath)
+{
+ FILE *pFile = NULL;
+ std::cout << "Generating new keys\n";
+ initOpenssl();
- // std::cerr << "Generating RSA key";
- // EVP_PKEY *pRsaPrivKey = create_rsa_key();
+ // std::cerr << "Generating RSA key";
+ // EVP_PKEY *pRsaPrivKey = create_rsa_key();
- std::cerr << "Generating EC key\n";
- EVP_PKEY *pRsaPrivKey = createEcKey();
- if (pRsaPrivKey != nullptr) {
- std::cerr << "Generating x509 Certificate\n";
- // Use this code to directly generate a certificate
- X509 *x509;
- x509 = X509_new();
- 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;
- int serial = rd();
+ std::cerr << "Generating EC key\n";
+ EVP_PKEY *pRsaPrivKey = createEcKey();
+ if (pRsaPrivKey != nullptr)
+ {
+ std::cerr << "Generating x509 Certificate\n";
+ // Use this code to directly generate a certificate
+ X509 *x509;
+ x509 = X509_new();
+ 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;
+ int serial = rd();
- ASN1_INTEGER_set(X509_get_serialNumber(x509), serial);
+ ASN1_INTEGER_set(X509_get_serialNumber(x509), serial);
- // not before this moment
- X509_gmtime_adj(X509_get_notBefore(x509), 0);
- // Cert is valid for 10 years
- X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L);
+ // not before this moment
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
+ // Cert is valid for 10 years
+ X509_gmtime_adj(X509_get_notAfter(x509),
+ 60L * 60L * 24L * 365L * 10L);
- // set the public key to the key we just generated
- X509_set_pubkey(x509, pRsaPrivKey);
+ // set the public key to the key we just generated
+ X509_set_pubkey(x509, pRsaPrivKey);
- // get the subject name
- X509_NAME *name;
- name = X509_get_subject_name(x509);
+ // get the subject name
+ X509_NAME *name;
+ name = X509_get_subject_name(x509);
- 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,
- 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);
+ 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,
+ 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);
- // Sign the certificate with our private key
- X509_sign(x509, pRsaPrivKey, EVP_sha256());
+ // Sign the certificate with our private key
+ X509_sign(x509, pRsaPrivKey, EVP_sha256());
- pFile = fopen(filepath.c_str(), "wt");
+ pFile = fopen(filepath.c_str(), "wt");
- if (pFile != nullptr) {
- PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, NULL);
+ if (pFile != nullptr)
+ {
+ PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0,
+ NULL);
- PEM_write_X509(pFile, x509);
- fclose(pFile);
- pFile = NULL;
- }
+ PEM_write_X509(pFile, x509);
+ fclose(pFile);
+ pFile = NULL;
+ }
- X509_free(x509);
+ X509_free(x509);
+ }
+
+ EVP_PKEY_free(pRsaPrivKey);
+ pRsaPrivKey = NULL;
}
- EVP_PKEY_free(pRsaPrivKey);
- pRsaPrivKey = NULL;
- }
-
- // cleanup_openssl();
+ // cleanup_openssl();
}
-EVP_PKEY *createRsaKey() {
- RSA *pRSA = NULL;
+EVP_PKEY *createRsaKey()
+{
+ RSA *pRSA = NULL;
#if OPENSSL_VERSION_NUMBER < 0x00908000L
- pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
+ pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
#else
- RSA_generate_key_ex(pRSA, 2048, NULL, NULL);
+ RSA_generate_key_ex(pRSA, 2048, NULL, NULL);
#endif
- EVP_PKEY *pKey = EVP_PKEY_new();
- 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");
- handleOpensslError();
- EVP_PKEY_free(pKey);
- pKey = NULL;
- }
- } else {
- handleOpensslError();
- if (pRSA != nullptr) {
- RSA_free(pRSA);
- pRSA = NULL;
- }
- if (pKey != nullptr) {
- EVP_PKEY_free(pKey);
- pKey = NULL;
- }
- }
- return pKey;
-}
-
-EVP_PKEY *createEcKey() {
- EVP_PKEY *pKey = NULL;
- int eccgrp = 0;
- eccgrp = OBJ_txt2nid("prime256v1");
-
- EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp);
- if (myecc != nullptr) {
- EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE);
- EC_KEY_generate_key(myecc);
- pKey = EVP_PKEY_new();
- if (pKey != nullptr) {
- if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) {
+ EVP_PKEY *pKey = EVP_PKEY_new();
+ if ((pRSA != nullptr) && (pKey != nullptr) &&
+ EVP_PKEY_assign_RSA(pKey, pRSA))
+ {
/* pKey owns pRSA from now */
- if (EC_KEY_check_key(myecc) <= 0) {
- fprintf(stderr, "EC_check_key failed.\n");
+ if (RSA_check_key(pRSA) <= 0)
+ {
+ fprintf(stderr, "RSA_check_key failed.\n");
+ handleOpensslError();
+ EVP_PKEY_free(pKey);
+ pKey = NULL;
}
- }
}
- }
- return pKey;
+ else
+ {
+ handleOpensslError();
+ if (pRSA != nullptr)
+ {
+ RSA_free(pRSA);
+ pRSA = NULL;
+ }
+ if (pKey != nullptr)
+ {
+ EVP_PKEY_free(pKey);
+ pKey = NULL;
+ }
+ }
+ return pKey;
}
-void initOpenssl() {
+EVP_PKEY *createEcKey()
+{
+ EVP_PKEY *pKey = NULL;
+ int eccgrp = 0;
+ eccgrp = OBJ_txt2nid("prime256v1");
+
+ EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp);
+ if (myecc != nullptr)
+ {
+ EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_generate_key(myecc);
+ pKey = EVP_PKEY_new();
+ if (pKey != nullptr)
+ {
+ if (EVP_PKEY_assign_EC_KEY(pKey, myecc))
+ {
+ /* pKey owns pRSA from now */
+ if (EC_KEY_check_key(myecc) <= 0)
+ {
+ fprintf(stderr, "EC_check_key failed.\n");
+ }
+ }
+ }
+ }
+ return pKey;
+}
+
+void initOpenssl()
+{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- RAND_load_file("/dev/urandom", 1024);
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ RAND_load_file("/dev/urandom", 1024);
#endif
}
-void cleanupOpenssl() {
- CRYPTO_cleanup_all_ex_data();
- ERR_free_strings();
+void cleanupOpenssl()
+{
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
- ERR_remove_thread_state(0);
+ ERR_remove_thread_state(0);
#endif
- EVP_cleanup();
+ EVP_cleanup();
}
-void handleOpensslError() { ERR_print_errors_fp(stderr); }
-inline void ensureOpensslKeyPresentAndValid(const std::string &filepath) {
- bool pemFileValid = false;
+void handleOpensslError()
+{
+ ERR_print_errors_fp(stderr);
+}
+inline void ensureOpensslKeyPresentAndValid(const std::string &filepath)
+{
+ bool pemFileValid = false;
- pemFileValid = verifyOpensslKeyCert(filepath);
+ pemFileValid = verifyOpensslKeyCert(filepath);
- if (!pemFileValid) {
- std::cerr << "Error in verifying signature, regenerating\n";
- generateSslCertificate(filepath);
- }
+ if (!pemFileValid)
+ {
+ std::cerr << "Error in verifying signature, regenerating\n";
+ generateSslCertificate(filepath);
+ }
}
-inline boost::asio::ssl::context getSslContext(
- const std::string &ssl_pem_file) {
- boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23};
- mSslContext.set_options(boost::asio::ssl::context::default_workarounds |
- boost::asio::ssl::context::no_sslv2 |
- boost::asio::ssl::context::no_sslv3 |
- boost::asio::ssl::context::single_dh_use |
- boost::asio::ssl::context::no_tlsv1 |
- boost::asio::ssl::context::no_tlsv1_1);
+inline boost::asio::ssl::context getSslContext(const std::string &ssl_pem_file)
+{
+ boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23};
+ mSslContext.set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::no_sslv3 |
+ boost::asio::ssl::context::single_dh_use |
+ boost::asio::ssl::context::no_tlsv1 |
+ boost::asio::ssl::context::no_tlsv1_1);
- // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer);
- mSslContext.use_certificate_file(ssl_pem_file,
- boost::asio::ssl::context::pem);
- mSslContext.use_private_key_file(ssl_pem_file,
- boost::asio::ssl::context::pem);
+ // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer);
+ mSslContext.use_certificate_file(ssl_pem_file,
+ boost::asio::ssl::context::pem);
+ mSslContext.use_private_key_file(ssl_pem_file,
+ boost::asio::ssl::context::pem);
- // Set up EC curves to auto (boost asio doesn't have a method for this)
- // There is a pull request to add this. Once this is included in an asio
- // drop, use the right way
- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
- if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1) {
- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
- }
+ // Set up EC curves to auto (boost asio doesn't have a method for this)
+ // There is a pull request to add this. Once this is included in an asio
+ // drop, use the right way
+ // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
+ if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1)
+ {
+ BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
+ }
- // From mozilla "compatibility"
- std::string mozillaCompatibilityCiphers =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "DHE-RSA-AES128-GCM-SHA256:"
- "DHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA256:"
- "ECDHE-ECDSA-AES128-SHA:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-RSA-AES128-SHA:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES256-SHA:"
- "ECDHE-RSA-AES256-SHA:"
- "DHE-RSA-AES128-SHA256:"
- "DHE-RSA-AES128-SHA:"
- "DHE-RSA-AES256-SHA256:"
- "DHE-RSA-AES256-SHA:"
- "ECDHE-ECDSA-DES-CBC3-SHA:"
- "ECDHE-RSA-DES-CBC3-SHA:"
- "EDH-RSA-DES-CBC3-SHA:"
- "AES128-GCM-SHA256:"
- "AES256-GCM-SHA384:"
- "AES128-SHA256:"
- "AES256-SHA256:"
- "AES128-SHA:"
- "AES256-SHA:"
- "DES-CBC3-SHA:"
- "!DSS";
+ // From mozilla "compatibility"
+ std::string mozillaCompatibilityCiphers = "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "DHE-RSA-AES128-GCM-SHA256:"
+ "DHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-ECDSA-AES128-SHA256:"
+ "ECDHE-RSA-AES128-SHA256:"
+ "ECDHE-ECDSA-AES128-SHA:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "ECDHE-RSA-AES128-SHA:"
+ "ECDHE-ECDSA-AES256-SHA384:"
+ "ECDHE-ECDSA-AES256-SHA:"
+ "ECDHE-RSA-AES256-SHA:"
+ "DHE-RSA-AES128-SHA256:"
+ "DHE-RSA-AES128-SHA:"
+ "DHE-RSA-AES256-SHA256:"
+ "DHE-RSA-AES256-SHA:"
+ "ECDHE-ECDSA-DES-CBC3-SHA:"
+ "ECDHE-RSA-DES-CBC3-SHA:"
+ "EDH-RSA-DES-CBC3-SHA:"
+ "AES128-GCM-SHA256:"
+ "AES256-GCM-SHA384:"
+ "AES128-SHA256:"
+ "AES256-SHA256:"
+ "AES128-SHA:"
+ "AES256-SHA:"
+ "DES-CBC3-SHA:"
+ "!DSS";
- // From mozilla "modern"
- std::string mozillaModernCiphers =
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA256";
+ // From mozilla "modern"
+ std::string mozillaModernCiphers = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-ECDSA-AES256-SHA384:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "ECDHE-ECDSA-AES128-SHA256:"
+ "ECDHE-RSA-AES128-SHA256";
- std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
+ std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
- if (SSL_CTX_set_cipher_list(mSslContext.native_handle(),
- mozillaCompatibilityCiphers.c_str()) != 1) {
- BMCWEB_LOG_ERROR << "Error setting cipher list\n";
- }
- return mSslContext;
+ if (SSL_CTX_set_cipher_list(mSslContext.native_handle(),
+ mozillaCompatibilityCiphers.c_str()) != 1)
+ {
+ BMCWEB_LOG_ERROR << "Error setting cipher list\n";
+ }
+ return mSslContext;
}
-} // namespace ensuressl
+} // namespace ensuressl
#endif
\ No newline at end of file
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 2e286e1..c419c97 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -1,359 +1,448 @@
#pragma once
-#include <pam_authenticate.hpp>
-#include <persistent_data_middleware.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/common.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_set.hpp>
+#include <pam_authenticate.hpp>
+#include <persistent_data_middleware.hpp>
+#include <random>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace token_authorization {
+namespace token_authorization
+{
-class Middleware {
- public:
- struct Context {
- std::shared_ptr<crow::persistent_data::UserSession> session;
- };
+class Middleware
+{
+ public:
+ struct Context
+ {
+ std::shared_ptr<crow::persistent_data::UserSession> session;
+ };
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
- if (isOnWhitelist(req)) {
- return;
- }
-
- ctx.session = performXtokenAuth(req);
- if (ctx.session == nullptr) {
- ctx.session = performCookieAuth(req);
- }
- if (ctx.session == nullptr) {
- boost::string_view authHeader = req.getHeaderValue("Authorization");
- if (!authHeader.empty()) {
- // Reject any kind of auth other than basic or token
- if (boost::starts_with(authHeader, "Token ")) {
- ctx.session = performTokenAuth(authHeader);
- } else if (boost::starts_with(authHeader, "Basic ")) {
- ctx.session = performBasicAuth(authHeader);
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
+ if (isOnWhitelist(req))
+ {
+ return;
}
- }
- }
- if (ctx.session == nullptr) {
- BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
-
- // If it's a browser connecting, don't send the HTTP authenticate header,
- // to avoid possible CSRF attacks with basic auth
- if (http_helpers::requestPrefersHtml(req)) {
- res.result(boost::beast::http::status::temporary_redirect);
- res.addHeader("Location", "/#/login");
- } else {
- res.result(boost::beast::http::status::unauthorized);
- // only send the WWW-authenticate header if this isn't a xhr from the
- // browser. most scripts,
- if (req.getHeaderValue("User-Agent").empty()) {
- res.addHeader("WWW-Authenticate", "Basic");
+ ctx.session = performXtokenAuth(req);
+ if (ctx.session == nullptr)
+ {
+ ctx.session = performCookieAuth(req);
}
- }
+ if (ctx.session == nullptr)
+ {
+ boost::string_view authHeader = req.getHeaderValue("Authorization");
+ if (!authHeader.empty())
+ {
+ // Reject any kind of auth other than basic or token
+ if (boost::starts_with(authHeader, "Token "))
+ {
+ ctx.session = performTokenAuth(authHeader);
+ }
+ else if (boost::starts_with(authHeader, "Basic "))
+ {
+ ctx.session = performBasicAuth(authHeader);
+ }
+ }
+ }
- res.end();
- return;
+ if (ctx.session == nullptr)
+ {
+ BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
+
+ // If it's a browser connecting, don't send the HTTP authenticate
+ // header, to avoid possible CSRF attacks with basic auth
+ if (http_helpers::requestPrefersHtml(req))
+ {
+ res.result(boost::beast::http::status::temporary_redirect);
+ res.addHeader("Location", "/#/login");
+ }
+ else
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ // only send the WWW-authenticate header if this isn't a xhr
+ // from the browser. most scripts,
+ if (req.getHeaderValue("User-Agent").empty())
+ {
+ res.addHeader("WWW-Authenticate", "Basic");
+ }
+ }
+
+ res.end();
+ return;
+ }
+
+ // TODO get user privileges here and propagate it via MW Context
+ // else let the request continue unharmed
}
- // TODO get user privileges here and propagate it via MW Context
- // else let the request continue unharmed
- }
-
- template <typename AllContext>
- void afterHandle(Request& req, Response& res, Context& ctx,
- AllContext& allctx) {
- // TODO(ed) THis should really be handled by the persistent data
- // middleware, but because it is upstream, it doesn't have access to the
- // session information. Should the data middleware persist the current
- // user session?
- if (ctx.session != nullptr &&
- ctx.session->persistence ==
- crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
- persistent_data::SessionStore::getInstance().removeSession(ctx.session);
- }
- }
-
- private:
- const std::shared_ptr<crow::persistent_data::UserSession> performBasicAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
-
- std::string authData;
- boost::string_view param = auth_header.substr(strlen("Basic "));
- if (!crow::utility::base64Decode(param, authData)) {
- return nullptr;
- }
- std::size_t separator = authData.find(':');
- if (separator == std::string::npos) {
- return nullptr;
+ template <typename AllContext>
+ void afterHandle(Request& req, Response& res, Context& ctx,
+ AllContext& allctx)
+ {
+ // TODO(ed) THis should really be handled by the persistent data
+ // middleware, but because it is upstream, it doesn't have access to the
+ // session information. Should the data middleware persist the current
+ // user session?
+ if (ctx.session != nullptr &&
+ ctx.session->persistence ==
+ crow::persistent_data::PersistenceType::SINGLE_REQUEST)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ ctx.session);
+ }
}
- std::string user = authData.substr(0, separator);
- separator += 1;
- if (separator > authData.size()) {
- return nullptr;
- }
- std::string pass = authData.substr(separator);
+ private:
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performBasicAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
+ std::string authData;
+ boost::string_view param = auth_header.substr(strlen("Basic "));
+ if (!crow::utility::base64Decode(param, authData))
+ {
+ return nullptr;
+ }
+ std::size_t separator = authData.find(':');
+ if (separator == std::string::npos)
+ {
+ return nullptr;
+ }
- if (!pamAuthenticateUser(user, pass)) {
- return nullptr;
+ std::string user = authData.substr(0, separator);
+ separator += 1;
+ if (separator > authData.size())
+ {
+ return nullptr;
+ }
+ std::string pass = authData.substr(separator);
+
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
+
+ if (!pamAuthenticateUser(user, pass))
+ {
+ return nullptr;
+ }
+
+ // TODO(ed) generateUserSession is a little expensive for basic
+ // auth, as it generates some random identifiers that will never be
+ // used. This should have a "fast" path for when user tokens aren't
+ // needed.
+ // This whole flow needs to be revisited anyway, as we can't be
+ // calling directly into pam for every request
+ return persistent_data::SessionStore::getInstance().generateUserSession(
+ user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
}
- // TODO(ed) generateUserSession is a little expensive for basic
- // auth, as it generates some random identifiers that will never be
- // used. This should have a "fast" path for when user tokens aren't
- // needed.
- // This whole flow needs to be revisited anyway, as we can't be
- // calling directly into pam for every request
- return persistent_data::SessionStore::getInstance().generateUserSession(
- user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
- }
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performTokenAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
- const std::shared_ptr<crow::persistent_data::UserSession> performTokenAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
-
- boost::string_view token = auth_header.substr(strlen("Token "));
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performXtokenAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
-
- boost::string_view token = req.getHeaderValue("X-Auth-Token");
- if (token.empty()) {
- return nullptr;
- }
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performCookieAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
-
- boost::string_view cookieValue = req.getHeaderValue("Cookie");
- if (cookieValue.empty()) {
- return nullptr;
+ boost::string_view token = auth_header.substr(strlen("Token "));
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
- auto startIndex = cookieValue.find("SESSION=");
- if (startIndex == std::string::npos) {
- return nullptr;
- }
- startIndex += sizeof("SESSION=") - 1;
- auto endIndex = cookieValue.find(";", startIndex);
- if (endIndex == std::string::npos) {
- endIndex = cookieValue.size();
- }
- boost::string_view authKey =
- cookieValue.substr(startIndex, endIndex - startIndex);
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performXtokenAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
- const std::shared_ptr<crow::persistent_data::UserSession> session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(
- authKey);
- if (session == nullptr) {
- return nullptr;
+ boost::string_view token = req.getHeaderValue("X-Auth-Token");
+ if (token.empty())
+ {
+ return nullptr;
+ }
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
+
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performCookieAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
+
+ boost::string_view cookieValue = req.getHeaderValue("Cookie");
+ if (cookieValue.empty())
+ {
+ return nullptr;
+ }
+
+ auto startIndex = cookieValue.find("SESSION=");
+ if (startIndex == std::string::npos)
+ {
+ return nullptr;
+ }
+ startIndex += sizeof("SESSION=") - 1;
+ auto endIndex = cookieValue.find(";", startIndex);
+ if (endIndex == std::string::npos)
+ {
+ endIndex = cookieValue.size();
+ }
+ boost::string_view authKey =
+ cookieValue.substr(startIndex, endIndex - startIndex);
+
+ const std::shared_ptr<crow::persistent_data::UserSession> session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ authKey);
+ if (session == nullptr)
+ {
+ return nullptr;
+ }
#ifndef BMCWEB_INSECURE_DISABLE_CSRF_PREVENTION
- // RFC7231 defines methods that need csrf protection
- if (req.method() != "GET"_method) {
- boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
- // Make sure both tokens are filled
- if (csrf.empty() || session->csrfToken.empty()) {
- return nullptr;
- }
- // Reject if csrf token not available
- if (csrf != session->csrfToken) {
- return nullptr;
- }
- }
+ // RFC7231 defines methods that need csrf protection
+ if (req.method() != "GET"_method)
+ {
+ boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
+ // Make sure both tokens are filled
+ if (csrf.empty() || session->csrfToken.empty())
+ {
+ return nullptr;
+ }
+ // Reject if csrf token not available
+ if (csrf != session->csrfToken)
+ {
+ return nullptr;
+ }
+ }
#endif
- return session;
- }
-
- // checks if request can be forwarded without authentication
- bool isOnWhitelist(const crow::Request& req) const {
- // it's allowed to GET root node without authentica tion
- if ("GET"_method == req.method()) {
- if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
- req.url == "/redfish" || req.url == "/redfish/" ||
- req.url == "/redfish/v1/odata" || req.url == "/redfish/v1/odata/") {
- return true;
- } else if (crow::webassets::routes.find(std::string(req.url)) !=
- crow::webassets::routes.end()) {
- return true;
- }
+ return session;
}
- // it's allowed to POST on session collection & login without
- // authentication
- if ("POST"_method == req.method()) {
- if ((req.url == "/redfish/v1/SessionService/Sessions") ||
- (req.url == "/redfish/v1/SessionService/Sessions/") ||
- (req.url == "/login")) {
- return true;
- }
- }
+ // checks if request can be forwarded without authentication
+ bool isOnWhitelist(const crow::Request& req) const
+ {
+ // it's allowed to GET root node without authentica tion
+ if ("GET"_method == req.method())
+ {
+ if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
+ req.url == "/redfish" || req.url == "/redfish/" ||
+ req.url == "/redfish/v1/odata" ||
+ req.url == "/redfish/v1/odata/")
+ {
+ return true;
+ }
+ else if (crow::webassets::routes.find(std::string(req.url)) !=
+ crow::webassets::routes.end())
+ {
+ return true;
+ }
+ }
- return false;
- }
+ // it's allowed to POST on session collection & login without
+ // authentication
+ if ("POST"_method == req.method())
+ {
+ if ((req.url == "/redfish/v1/SessionService/Sessions") ||
+ (req.url == "/redfish/v1/SessionService/Sessions/") ||
+ (req.url == "/login"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
};
// 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 requestRoutes(Crow<Middlewares...>& app) {
- static_assert(
- black_magic::Contains<persistent_data::Middleware, Middlewares...>::value,
- "token_authorization middleware must be enabled in app to use "
- "auth routes");
- BMCWEB_ROUTE(app, "/login")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- boost::string_view contentType = req.getHeaderValue("content-type");
- boost::string_view username;
- boost::string_view password;
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ static_assert(
+ black_magic::Contains<persistent_data::Middleware,
+ Middlewares...>::value,
+ "token_authorization middleware must be enabled in app to use "
+ "auth routes");
+ BMCWEB_ROUTE(app, "/login")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ boost::string_view contentType = req.getHeaderValue("content-type");
+ boost::string_view username;
+ boost::string_view password;
- bool looksLikeIbm = false;
+ bool looksLikeIbm = false;
- // This object needs to be declared at this scope so the strings
- // within it are not destroyed before we can use them
- nlohmann::json loginCredentials;
- // Check if auth was provided by a payload
- if (contentType == "application/json") {
- loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
- if (loginCredentials.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
+ // This object needs to be declared at this scope so the strings
+ // within it are not destroyed before we can use them
+ nlohmann::json loginCredentials;
+ // Check if auth was provided by a payload
+ if (contentType == "application/json")
+ {
+ loginCredentials =
+ nlohmann::json::parse(req.body, nullptr, false);
+ if (loginCredentials.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+
+ // check for username/password in the root object
+ // THis method is how intel APIs authenticate
+ nlohmann::json::iterator userIt =
+ loginCredentials.find("username");
+ nlohmann::json::iterator passIt =
+ loginCredentials.find("password");
+ if (userIt != loginCredentials.end() &&
+ passIt != loginCredentials.end())
+ {
+ const std::string* userStr =
+ userIt->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ else
+ {
+ // Openbmc appears to push a data object that contains the
+ // same keys (username and password), attempt to use that
+ auto dataIt = loginCredentials.find("data");
+ if (dataIt != loginCredentials.end())
+ {
+ // Some apis produce an array of value ["username",
+ // "password"]
+ if (dataIt->is_array())
+ {
+ if (dataIt->size() == 2)
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->begin();
+ nlohmann::json::iterator passIt2 =
+ dataIt->begin() + 1;
+ looksLikeIbm = true;
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr &&
+ passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
+ else if (dataIt->is_object())
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->find("username");
+ nlohmann::json::iterator passIt2 =
+ dataIt->find("password");
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // check if auth was provided as a headers
+ username = req.getHeaderValue("username");
+ password = req.getHeaderValue("password");
+ }
+
+ if (!username.empty() && !password.empty())
+ {
+ if (!pamAuthenticateUser(username, password))
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ }
+ else
+ {
+ auto session = persistent_data::SessionStore::getInstance()
+ .generateUserSession(username);
+
+ if (looksLikeIbm)
+ {
+ // IBM requires a very specific login structure, and
+ // doesn't actually look at the status code.
+ // TODO(ed).... Fix that upstream
+ res.jsonValue = {
+ {"data",
+ "User '" + std::string(username) + "' logged in"},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+
+ // Hack alert. Boost beast by default doesn't let you
+ // declare multiple headers of the same name, and in
+ // most cases this is fine. Unfortunately here we need
+ // to set the Session cookie, which requires the
+ // httpOnly attribute, as well as the XSRF cookie, which
+ // requires it to not have an httpOnly attribute. To get
+ // the behavior we want, we simply inject the second
+ // "set-cookie" string into the value header, and get
+ // the result we want, even though we are technicaly
+ // declaring two headers here.
+ res.addHeader("Set-Cookie",
+ "XSRF-TOKEN=" + session->csrfToken +
+ "; Secure\r\nSet-Cookie: SESSION=" +
+ session->sessionToken +
+ "; Secure; HttpOnly");
+ }
+ else
+ {
+ // if content type is json, assume json token
+ res.jsonValue = {{"token", session->sessionToken}};
+ }
+ }
+ }
+ else
+ {
+ res.result(boost::beast::http::status::bad_request);
+ }
+ res.end();
+ });
+
+ BMCWEB_ROUTE(app, "/logout")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ auto& session =
+ app.template getContext<token_authorization::Middleware>(req)
+ .session;
+ if (session != nullptr)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ session);
+ }
res.end();
return;
- }
-
- // check for username/password in the root object
- // THis method is how intel APIs authenticate
- nlohmann::json::iterator userIt = loginCredentials.find("username");
- nlohmann::json::iterator passIt = loginCredentials.find("password");
- if (userIt != loginCredentials.end() &&
- passIt != loginCredentials.end()) {
- const std::string* userStr = userIt->get_ptr<const std::string*>();
- const std::string* passStr = passIt->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
- } else {
- // Openbmc appears to push a data object that contains the same
- // keys (username and password), attempt to use that
- auto dataIt = loginCredentials.find("data");
- if (dataIt != loginCredentials.end()) {
- // Some apis produce an array of value ["username",
- // "password"]
- if (dataIt->is_array()) {
- if (dataIt->size() == 2) {
- nlohmann::json::iterator userIt2 = dataIt->begin();
- nlohmann::json::iterator passIt2 = dataIt->begin() + 1;
- looksLikeIbm = true;
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
- const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
- const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
- }
- }
-
- } else if (dataIt->is_object()) {
- nlohmann::json::iterator userIt2 = dataIt->find("username");
- nlohmann::json::iterator passIt2 = dataIt->find("password");
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
- const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
- const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
- }
- }
- }
- }
- } else {
- // check if auth was provided as a headers
- username = req.getHeaderValue("username");
- password = req.getHeaderValue("password");
- }
-
- if (!username.empty() && !password.empty()) {
- if (!pamAuthenticateUser(username, password)) {
- res.result(boost::beast::http::status::unauthorized);
- } else {
- auto session = persistent_data::SessionStore::getInstance()
- .generateUserSession(username);
-
- if (looksLikeIbm) {
- // IBM requires a very specific login structure, and doesn't
- // actually look at the status code. TODO(ed).... Fix that
- // upstream
- res.jsonValue = {
- {"data", "User '" + std::string(username) + "' logged in"},
- {"message", "200 OK"},
- {"status", "ok"}};
-
- // Hack alert. Boost beast by default doesn't let you declare
- // multiple headers of the same name, and in most cases this is
- // fine. Unfortunately here we need to set the Session cookie,
- // which requires the httpOnly attribute, as well as the XSRF
- // cookie, which requires it to not have an httpOnly attribute.
- // To get the behavior we want, we simply inject the second
- // "set-cookie" string into the value header, and get the result
- // we want, even though we are technicaly declaring two headers
- // here.
- res.addHeader("Set-Cookie",
- "XSRF-TOKEN=" + session->csrfToken +
- "; Secure\r\nSet-Cookie: SESSION=" +
- session->sessionToken + "; Secure; HttpOnly");
- } else {
- // if content type is json, assume json token
- res.jsonValue = {{"token", session->sessionToken}};
- }
- }
-
- } else {
- res.result(boost::beast::http::status::bad_request);
- }
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/logout")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- auto& session =
- app.template getContext<token_authorization::Middleware>(req)
- .session;
- if (session != nullptr) {
- persistent_data::SessionStore::getInstance().removeSession(session);
- }
- res.end();
- return;
- });
+ });
}
-} // namespace token_authorization
-} // namespace crow
+} // namespace token_authorization
+} // namespace crow
diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp
index ad4b352..747a137 100644
--- a/include/web_kvm.hpp
+++ b/include/web_kvm.hpp
@@ -1,181 +1,202 @@
-#include <string>
#include <crow/app.h>
-#include <boost/endian/arithmetic.hpp>
#include <ast_jpeg_decoder.hpp>
#include <ast_video_puller.hpp>
+#include <boost/endian/arithmetic.hpp>
+#include <string>
-namespace crow {
-namespace kvm {
+namespace crow
+{
+namespace kvm
+{
static const std::string rfb33VersionString = "RFB 003.003\n";
static const std::string rfb37VersionString = "RFB 003.007\n";
static const std::string rfb38VersionString = "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 PixelFormatStruct {
- boost::endian::big_uint8_t bitsPerPixel;
- boost::endian::big_uint8_t depth;
- boost::endian::big_uint8_t isBigEndian;
- boost::endian::big_uint8_t isTrueColor;
- boost::endian::big_uint16_t redMax;
- boost::endian::big_uint16_t greenMax;
- boost::endian::big_uint16_t blueMax;
- boost::endian::big_uint8_t redShift;
- boost::endian::big_uint8_t greenShift;
- boost::endian::big_uint8_t blueShift;
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint8_t pad3;
+struct PixelFormatStruct
+{
+ boost::endian::big_uint8_t bitsPerPixel;
+ boost::endian::big_uint8_t depth;
+ boost::endian::big_uint8_t isBigEndian;
+ boost::endian::big_uint8_t isTrueColor;
+ boost::endian::big_uint16_t redMax;
+ boost::endian::big_uint16_t greenMax;
+ boost::endian::big_uint16_t blueMax;
+ boost::endian::big_uint8_t redShift;
+ boost::endian::big_uint8_t greenShift;
+ boost::endian::big_uint8_t blueShift;
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint8_t pad3;
};
-struct ServerInitializationMsg {
- boost::endian::big_uint16_t framebufferWidth;
- boost::endian::big_uint16_t framebufferHeight;
- PixelFormatStruct pixelFormat;
- boost::endian::big_uint32_t nameLength;
+struct ServerInitializationMsg
+{
+ boost::endian::big_uint16_t framebufferWidth;
+ boost::endian::big_uint16_t framebufferHeight;
+ PixelFormatStruct pixelFormat;
+ boost::endian::big_uint32_t nameLength;
};
-enum class client_to_server_msg_type : uint8_t {
- set_pixel_format = 0,
- fix_color_map_entries = 1,
- set_encodings = 2,
- framebuffer_update_request = 3,
- key_event = 4,
- pointer_event = 5,
- client_cut_text = 6
+enum class client_to_server_msg_type : uint8_t
+{
+ set_pixel_format = 0,
+ fix_color_map_entries = 1,
+ set_encodings = 2,
+ framebuffer_update_request = 3,
+ key_event = 4,
+ pointer_event = 5,
+ client_cut_text = 6
};
-enum class server_to_client_message_type : uint8_t {
- framebuffer_update = 0,
- set_color_map_entries = 1,
- bell_message = 2,
- server_cut_text = 3
+enum class server_to_client_message_type : uint8_t
+{
+ framebuffer_update = 0,
+ set_color_map_entries = 1,
+ bell_message = 2,
+ server_cut_text = 3
};
-struct SetPixelFormatMsg {
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint8_t pad3;
- PixelFormatStruct pixelFormat;
+struct SetPixelFormatMsg
+{
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint8_t pad3;
+ PixelFormatStruct pixelFormat;
};
-struct FrameBufferUpdateReq {
- boost::endian::big_uint8_t incremental;
- boost::endian::big_uint16_t xPosition;
- boost::endian::big_uint16_t yPosition;
- boost::endian::big_uint16_t width;
- boost::endian::big_uint16_t height;
+struct FrameBufferUpdateReq
+{
+ boost::endian::big_uint8_t incremental;
+ boost::endian::big_uint16_t xPosition;
+ boost::endian::big_uint16_t yPosition;
+ boost::endian::big_uint16_t width;
+ boost::endian::big_uint16_t height;
};
-struct KeyEventMsg {
- boost::endian::big_uint8_t downFlag;
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint32_t key;
+struct KeyEventMsg
+{
+ boost::endian::big_uint8_t downFlag;
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint32_t key;
};
-struct PointerEventMsg {
- boost::endian::big_uint8_t buttonMask;
- boost::endian::big_uint16_t xPosition;
- boost::endian::big_uint16_t yPosition;
+struct PointerEventMsg
+{
+ boost::endian::big_uint8_t buttonMask;
+ boost::endian::big_uint16_t xPosition;
+ boost::endian::big_uint16_t yPosition;
};
-struct ClientCutTextMsg {
- std::vector<uint8_t> data;
+struct ClientCutTextMsg
+{
+ std::vector<uint8_t> data;
};
-enum class encoding_type : uint32_t {
- raw = 0x00,
- copy_rectangle = 0x01,
- rising_rectangle = 0x02,
- corre = 0x04,
- hextile = 0x05,
- zlib = 0x06,
- tight = 0x07,
- zlibhex = 0x08,
- ultra = 0x09,
- zrle = 0x10,
- zywrle = 0x011,
- cache_enable = 0xFFFF0001,
- xor_enable = 0xFFFF0006,
- server_state_ultranvc = 0xFFFF8000,
- enable_keepAlive = 0xFFFF8001,
- enableftp_protocol_version = 0xFFFF8002,
- tight_compress_level_0 = 0xFFFFFF00,
- tight_compress_level_9 = 0xFFFFFF09,
- x_cursor = 0xFFFFFF10,
- rich_cursor = 0xFFFFFF11,
- pointer_pos = 0xFFFFFF18,
- last_rect = 0xFFFFFF20,
- new_framebuffer_size = 0xFFFFFF21,
- tight_quality_level_0 = 0xFFFFFFE0,
- tight_quality_level_9 = 0xFFFFFFE9
+enum class encoding_type : uint32_t
+{
+ raw = 0x00,
+ copy_rectangle = 0x01,
+ rising_rectangle = 0x02,
+ corre = 0x04,
+ hextile = 0x05,
+ zlib = 0x06,
+ tight = 0x07,
+ zlibhex = 0x08,
+ ultra = 0x09,
+ zrle = 0x10,
+ zywrle = 0x011,
+ cache_enable = 0xFFFF0001,
+ xor_enable = 0xFFFF0006,
+ server_state_ultranvc = 0xFFFF8000,
+ enable_keepAlive = 0xFFFF8001,
+ enableftp_protocol_version = 0xFFFF8002,
+ tight_compress_level_0 = 0xFFFFFF00,
+ tight_compress_level_9 = 0xFFFFFF09,
+ x_cursor = 0xFFFFFF10,
+ rich_cursor = 0xFFFFFF11,
+ pointer_pos = 0xFFFFFF18,
+ last_rect = 0xFFFFFF20,
+ new_framebuffer_size = 0xFFFFFF21,
+ tight_quality_level_0 = 0xFFFFFFE0,
+ tight_quality_level_9 = 0xFFFFFFE9
};
-struct FramebufferRectangle {
- 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 FramebufferRectangle
+{
+ 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 FramebufferUpdateMsg {
- boost::endian::big_uint8_t messageType{};
- std::vector<FramebufferRectangle> rectangles;
+struct FramebufferUpdateMsg
+{
+ boost::endian::big_uint8_t messageType{};
+ std::vector<FramebufferRectangle> rectangles;
};
-inline std::string serialize(const FramebufferUpdateMsg& msg) {
- // calculate the size of the needed vector for serialization
- size_t vectorSize = 4;
- for (const auto& rect : msg.rectangles) {
- vectorSize += 12 + rect.data.size();
- }
+inline std::string serialize(const FramebufferUpdateMsg& msg)
+{
+ // calculate the size of the needed vector for serialization
+ size_t vectorSize = 4;
+ for (const auto& rect : msg.rectangles)
+ {
+ vectorSize += 12 + rect.data.size();
+ }
- std::string serialized(vectorSize, 0);
+ std::string serialized(vectorSize, 0);
- size_t i = 0;
- serialized[i++] = static_cast<char>(
- server_to_client_message_type::framebuffer_update); // Type
- serialized[i++] = 0; // Pad byte
- boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
- std::memcpy(&serialized[i], &numberOfRectangles, sizeof(numberOfRectangles));
- i += sizeof(numberOfRectangles);
+ size_t i = 0;
+ serialized[i++] = static_cast<char>(
+ server_to_client_message_type::framebuffer_update); // Type
+ serialized[i++] = 0; // Pad byte
+ boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
+ std::memcpy(&serialized[i], &numberOfRectangles,
+ sizeof(numberOfRectangles));
+ i += sizeof(numberOfRectangles);
- for (const auto& rect : msg.rectangles) {
- // copy the first part of the struct
- size_t bufferSize =
- sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
- std::memcpy(&serialized[i], &rect, bufferSize);
- i += bufferSize;
+ for (const auto& rect : msg.rectangles)
+ {
+ // copy the first part of the struct
+ size_t bufferSize =
+ sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
+ std::memcpy(&serialized[i], &rect, bufferSize);
+ i += bufferSize;
- std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
- i += rect.data.size();
- }
+ std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
+ i += rect.data.size();
+ }
- return serialized;
+ return serialized;
}
-enum class VncState {
- UNSTARTED,
- AWAITING_CLIENT_VERSION,
- AWAITING_CLIENT_AUTH_METHOD,
- AWAITING_CLIENT_INIT_msg,
- MAIN_LOOP
+enum class VncState
+{
+ UNSTARTED,
+ AWAITING_CLIENT_VERSION,
+ AWAITING_CLIENT_AUTH_METHOD,
+ AWAITING_CLIENT_INIT_msg,
+ MAIN_LOOP
};
-class ConnectionMetadata {
- public:
- ConnectionMetadata(){};
+class ConnectionMetadata
+{
+ public:
+ ConnectionMetadata(){};
- VncState vncState{VncState::UNSTARTED};
+ VncState vncState{VncState::UNSTARTED};
};
using meta_list = std::vector<ConnectionMetadata>;
@@ -183,171 +204,219 @@
ConnectionMetadata meta;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/kvmws")
- .websocket()
- .onopen([&](crow::websocket::Connection& conn) {
- if (meta.vncState == VncState::UNSTARTED) {
- meta.vncState = VncState::AWAITING_CLIENT_VERSION;
- conn.sendBinary(rfb38VersionString);
- } else { // SHould never happen
- conn.close();
- }
-
- })
- .onclose(
- [&](crow::websocket::Connection& conn, const std::string& reason) {
- meta.vncState = VncState::UNSTARTED;
- })
- .onmessage([&](crow::websocket::Connection& conn, const std::string& data,
- bool is_binary) {
- switch (meta.vncState) {
- case VncState::AWAITING_CLIENT_VERSION: {
- std::cout << "Client sent: " << data;
- if (data == rfb38VersionString || data == rfb37VersionString) {
- std::string authTypes{1,
- (uint8_t)RfbAuthScheme::no_authentication};
- conn.sendBinary(authTypes);
- meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
- } else if (data == rfb33VersionString) {
- // TODO(ed) Support older protocols
- meta.vncState = VncState::UNSTARTED;
- conn.close();
- } else {
- // TODO(ed) Support older protocols
- meta.vncState = VncState::UNSTARTED;
- conn.close();
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/kvmws")
+ .websocket()
+ .onopen([&](crow::websocket::Connection& conn) {
+ if (meta.vncState == VncState::UNSTARTED)
+ {
+ meta.vncState = VncState::AWAITING_CLIENT_VERSION;
+ conn.sendBinary(rfb38VersionString);
}
- } break;
- case VncState::AWAITING_CLIENT_AUTH_METHOD: {
- std::string securityResult{{0, 0, 0, 0}};
- if (data[0] == (uint8_t)RfbAuthScheme::no_authentication) {
- meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
- } else {
- // Mark auth as failed
- securityResult[3] = 1;
- meta.vncState = VncState::UNSTARTED;
+ else
+ { // SHould never happen
+ conn.close();
}
- conn.sendBinary(securityResult);
- } break;
- case VncState::AWAITING_CLIENT_INIT_msg: {
- // Now send the server initialization
- ServerInitializationMsg serverInitMsg{};
- serverInitMsg.framebufferWidth = 800;
- serverInitMsg.framebufferHeight = 600;
- serverInitMsg.pixelFormat.bitsPerPixel = 32;
- serverInitMsg.pixelFormat.isBigEndian = 0;
- serverInitMsg.pixelFormat.isTrueColor = 1;
- serverInitMsg.pixelFormat.redMax = 255;
- serverInitMsg.pixelFormat.greenMax = 255;
- serverInitMsg.pixelFormat.blueMax = 255;
- serverInitMsg.pixelFormat.redShift = 16;
- serverInitMsg.pixelFormat.greenShift = 8;
- serverInitMsg.pixelFormat.blueShift = 0;
- serverInitMsg.nameLength = 0;
- std::cout << "size: " << sizeof(serverInitMsg);
- // 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*>(&serverInitMsg),
- sizeof(serverInitMsg));
- std::cout << "s.size() " << s.size();
- conn.sendBinary(s);
- meta.vncState = VncState::MAIN_LOOP;
- } break;
- 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 "
- << static_cast<std::size_t>(type) << "\n";
- switch (type) {
- case client_to_server_msg_type::set_pixel_format: {
- } break;
-
- case client_to_server_msg_type::fix_color_map_entries: {
- } break;
- case client_to_server_msg_type::set_encodings: {
- } break;
- case client_to_server_msg_type::framebuffer_update_request: {
- // Make sure the buffer is long enough to handle what we're
- // about to do
- if (data.size() >= sizeof(FrameBufferUpdateReq) +
- sizeof(client_to_server_msg_type)) {
- auto msg = reinterpret_cast<const FrameBufferUpdateReq*>(
- 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
- // with the websocket, not recreated every time
- ast_video::SimpleVideoPuller p;
- p.initialize();
- auto out = p.readVideo();
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode,
- out.ySelector, out.uvSelector);
-
- FramebufferUpdateMsg bufferUpdateMsg;
-
- // If the viewer is requesting a full update, force write
- // of all pixels
-
- FramebufferRectangle thisRect;
- thisRect.x = msg->xPosition;
- thisRect.y = msg->yPosition;
- thisRect.width = out.width;
- thisRect.height = out.height;
- thisRect.encoding =
- static_cast<uint8_t>(encoding_type::raw);
- std::cout << "Encoding is " << thisRect.encoding;
- thisRect.data.reserve(
- static_cast<std::size_t>(thisRect.width) *
- static_cast<std::size_t>(thisRect.height) * 4);
- std::cout << "Width " << out.width << " Height "
- << out.height;
-
- for (int i = 0; i < out.width * out.height; i++) {
- auto& pixel = d.outBuffer[i];
- thisRect.data.push_back(pixel.b);
- thisRect.data.push_back(pixel.g);
- thisRect.data.push_back(pixel.r);
- thisRect.data.push_back(0);
+ })
+ .onclose(
+ [&](crow::websocket::Connection& conn, const std::string& reason) {
+ meta.vncState = VncState::UNSTARTED;
+ })
+ .onmessage([&](crow::websocket::Connection& conn,
+ const std::string& data, bool is_binary) {
+ switch (meta.vncState)
+ {
+ case VncState::AWAITING_CLIENT_VERSION:
+ {
+ std::cout << "Client sent: " << data;
+ if (data == rfb38VersionString ||
+ data == rfb37VersionString)
+ {
+ std::string authTypes{
+ 1, (uint8_t)RfbAuthScheme::no_authentication};
+ conn.sendBinary(authTypes);
+ meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
}
-
- bufferUpdateMsg.rectangles.push_back(std::move(thisRect));
- auto serialized = serialize(bufferUpdateMsg);
-
- conn.sendBinary(serialized);
-
- } // TODO(Ed) handle error
-
+ else if (data == rfb33VersionString)
+ {
+ // TODO(ed) Support older protocols
+ meta.vncState = VncState::UNSTARTED;
+ conn.close();
+ }
+ else
+ {
+ // TODO(ed) Support older protocols
+ meta.vncState = VncState::UNSTARTED;
+ conn.close();
+ }
}
-
break;
+ case VncState::AWAITING_CLIENT_AUTH_METHOD:
+ {
+ std::string securityResult{{0, 0, 0, 0}};
+ if (data[0] == (uint8_t)RfbAuthScheme::no_authentication)
+ {
+ meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
+ }
+ else
+ {
+ // Mark auth as failed
+ securityResult[3] = 1;
+ meta.vncState = VncState::UNSTARTED;
+ }
+ conn.sendBinary(securityResult);
+ }
+ break;
+ case VncState::AWAITING_CLIENT_INIT_msg:
+ {
+ // Now send the server initialization
+ ServerInitializationMsg serverInitMsg{};
+ serverInitMsg.framebufferWidth = 800;
+ serverInitMsg.framebufferHeight = 600;
+ serverInitMsg.pixelFormat.bitsPerPixel = 32;
+ serverInitMsg.pixelFormat.isBigEndian = 0;
+ serverInitMsg.pixelFormat.isTrueColor = 1;
+ serverInitMsg.pixelFormat.redMax = 255;
+ serverInitMsg.pixelFormat.greenMax = 255;
+ serverInitMsg.pixelFormat.blueMax = 255;
+ serverInitMsg.pixelFormat.redShift = 16;
+ serverInitMsg.pixelFormat.greenShift = 8;
+ serverInitMsg.pixelFormat.blueShift = 0;
+ serverInitMsg.nameLength = 0;
+ std::cout << "size: " << sizeof(serverInitMsg);
+ // 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*>(&serverInitMsg),
+ sizeof(serverInitMsg));
+ std::cout << "s.size() " << s.size();
+ conn.sendBinary(s);
+ meta.vncState = VncState::MAIN_LOOP;
+ }
+ break;
+ 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 "
+ << static_cast<std::size_t>(type) << "\n";
+ switch (type)
+ {
+ case client_to_server_msg_type::set_pixel_format:
+ {
+ }
+ break;
- case client_to_server_msg_type::key_event: {
- } break;
+ case client_to_server_msg_type::
+ fix_color_map_entries:
+ {
+ }
+ break;
+ case client_to_server_msg_type::set_encodings:
+ {
+ }
+ break;
+ case client_to_server_msg_type::
+ framebuffer_update_request:
+ {
+ // Make sure the buffer is long enough to handle
+ // what we're about to do
+ if (data.size() >=
+ sizeof(FrameBufferUpdateReq) +
+ sizeof(client_to_server_msg_type))
+ {
+ auto msg = reinterpret_cast<
+ const FrameBufferUpdateReq*>(
+ data.data() + // NOLINT
+ sizeof(client_to_server_msg_type));
+ // TODO(ed) find a better way to do this
+ // deserialization
- case client_to_server_msg_type::pointer_event: {
- } break;
+ // Todo(ed) lifecycle of the video puller
+ // and decoder should be with the websocket,
+ // not recreated every time
+ ast_video::SimpleVideoPuller p;
+ p.initialize();
+ auto out = p.readVideo();
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height,
+ out.mode, out.ySelector,
+ out.uvSelector);
- case client_to_server_msg_type::client_cut_text: {
- } break;
+ FramebufferUpdateMsg bufferUpdateMsg;
- default:
- break;
- }
+ // If the viewer is requesting a full
+ // update, force write of all pixels
+
+ FramebufferRectangle thisRect;
+ thisRect.x = msg->xPosition;
+ thisRect.y = msg->yPosition;
+ thisRect.width = out.width;
+ thisRect.height = out.height;
+ thisRect.encoding = static_cast<uint8_t>(
+ encoding_type::raw);
+ std::cout << "Encoding is "
+ << thisRect.encoding;
+ thisRect.data.reserve(
+ static_cast<std::size_t>(
+ thisRect.width) *
+ static_cast<std::size_t>(
+ thisRect.height) *
+ 4);
+ std::cout << "Width " << out.width
+ << " Height " << out.height;
+
+ for (int i = 0; i < out.width * out.height;
+ i++)
+ {
+ auto& pixel = d.outBuffer[i];
+ thisRect.data.push_back(pixel.b);
+ thisRect.data.push_back(pixel.g);
+ thisRect.data.push_back(pixel.r);
+ thisRect.data.push_back(0);
+ }
+
+ bufferUpdateMsg.rectangles.push_back(
+ std::move(thisRect));
+ auto serialized =
+ serialize(bufferUpdateMsg);
+
+ conn.sendBinary(serialized);
+
+ } // TODO(Ed) handle error
+ }
+
+ break;
+
+ case client_to_server_msg_type::key_event:
+ {
+ }
+ break;
+
+ case client_to_server_msg_type::pointer_event:
+ {
+ }
+ break;
+
+ case client_to_server_msg_type::client_cut_text:
+ {
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case VncState::UNSTARTED:
+ // Error? TODO
+ break;
}
-
- } break;
- case VncState::UNSTARTED:
- // Error? TODO
- break;
- }
-
- });
+ });
}
-} // namespace kvm
-} // namespace crow
\ 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
index 5eabffe..7f1c1f5 100644
--- a/include/webassets.hpp
+++ b/include/webassets.hpp
@@ -1,137 +1,161 @@
#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>
+#include <experimental/filesystem>
+#include <fstream>
+#include <string>
-namespace crow {
-namespace webassets {
+namespace crow
+{
+namespace webassets
+{
namespace filesystem = std::experimental::filesystem;
-struct CmpStr {
- bool operator()(const char* a, const char* b) const {
- return std::strcmp(a, b) < 0;
- }
+struct CmpStr
+{
+ bool operator()(const char* a, const char* b) const
+ {
+ return std::strcmp(a, b) < 0;
+ }
};
static boost::container::flat_set<std::string> routes;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- const static boost::container::flat_map<const char*, const char*, CmpStr>
- contentTypes{
- {{".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"},
- {".gif", "image/gif"},
- {".ico", "image/x-icon"},
- {".ttf", "application/x-font-ttf"},
- {".svg", "image/svg+xml"},
- {".eot", "application/vnd.ms-fontobject"},
- {".xml", "application/xml"},
- {".jpg", "image/jpeg"},
- {".jpeg", "image/jpeg"},
- {".json", "application/json"},
- // 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"}}};
- filesystem::path rootpath{"/usr/share/www/"};
- filesystem::recursive_directory_iterator dirIter(rootpath);
- // In certain cases, we might have both a gzipped version of the file AND a
- // non-gzipped version. To avoid duplicated routes, we need to make sure we
- // get the gzipped version first. Because the gzipped path should be longer
- // than the non gzipped path, if we sort in Ascending order, we should be
- // guaranteed to get the gzip version first.
- std::vector<filesystem::directory_entry> paths(filesystem::begin(dirIter),
- filesystem::end(dirIter));
- std::sort(paths.rbegin(), paths.rend());
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ const static boost::container::flat_map<const char*, const char*, CmpStr>
+ contentTypes{
+ {{".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"},
+ {".gif", "image/gif"},
+ {".ico", "image/x-icon"},
+ {".ttf", "application/x-font-ttf"},
+ {".svg", "image/svg+xml"},
+ {".eot", "application/vnd.ms-fontobject"},
+ {".xml", "application/xml"},
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".json", "application/json"},
+ // 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"}}};
+ filesystem::path rootpath{"/usr/share/www/"};
+ filesystem::recursive_directory_iterator dirIter(rootpath);
+ // In certain cases, we might have both a gzipped version of the file AND a
+ // non-gzipped version. To avoid duplicated routes, we need to make sure we
+ // get the gzipped version first. Because the gzipped path should be longer
+ // than the non gzipped path, if we sort in Ascending order, we should be
+ // guaranteed to get the gzip version first.
+ std::vector<filesystem::directory_entry> paths(filesystem::begin(dirIter),
+ filesystem::end(dirIter));
+ std::sort(paths.rbegin(), paths.rend());
- for (const filesystem::directory_entry& dir : paths) {
- filesystem::path absolutePath = dir.path();
- filesystem::path relativePath{
- absolutePath.string().substr(rootpath.string().size() - 1)};
- 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)) {
- dirIter.disable_recursion_pending();
- }
- } else if (filesystem::is_regular_file(dir)) {
- std::string extension = relativePath.extension();
- filesystem::path webpath = relativePath;
- const char* contentEncoding = nullptr;
-
- if (extension == ".gz") {
- webpath = webpath.replace_extension("");
- // Use the non-gzip version for determining content type
- extension = webpath.extension().string();
- contentEncoding = "gzip";
- }
-
- if (boost::starts_with(webpath.filename().string(), "index.")) {
- webpath = webpath.parent_path();
- if (webpath.string().size() == 0 || webpath.string().back() != '/') {
- // insert the non-directory version of this path
- routes.insert(webpath);
- webpath += "/";
+ for (const filesystem::directory_entry& dir : paths)
+ {
+ filesystem::path absolutePath = dir.path();
+ filesystem::path relativePath{
+ absolutePath.string().substr(rootpath.string().size() - 1)};
+ 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))
+ {
+ dirIter.disable_recursion_pending();
+ }
}
- }
+ else if (filesystem::is_regular_file(dir))
+ {
+ std::string extension = relativePath.extension();
+ filesystem::path webpath = relativePath;
+ const char* contentEncoding = nullptr;
- std::pair<boost::container::flat_set<std::string>::iterator, bool>
- inserted = routes.insert(webpath);
-
- if (!inserted.second) {
- // Got a duplicated path. This is expected in certain situations
- BMCWEB_LOG_DEBUG << "Got duplicated path " << webpath;
- continue;
- }
- const char* contentType = nullptr;
-
- auto contentTypeIt = contentTypes.find(extension.c_str());
- if (contentTypeIt == contentTypes.end()) {
- BMCWEB_LOG_ERROR << "Cannot determine content-type for " << absolutePath
- << " with extension " << extension;
- } else {
- contentType = contentTypeIt->second;
- }
-
- app.routeDynamic(webpath)(
- [absolutePath, contentType, contentEncoding](const crow::Request& req,
- crow::Response& res) {
- if (contentType != nullptr) {
- res.addHeader("Content-Type", contentType);
+ if (extension == ".gz")
+ {
+ webpath = webpath.replace_extension("");
+ // Use the non-gzip version for determining content type
+ extension = webpath.extension().string();
+ contentEncoding = "gzip";
}
- if (contentEncoding != nullptr) {
- res.addHeader("Content-Encoding", contentEncoding);
+ if (boost::starts_with(webpath.filename().string(), "index."))
+ {
+ webpath = webpath.parent_path();
+ if (webpath.string().size() == 0 ||
+ webpath.string().back() != '/')
+ {
+ // insert the non-directory version of this path
+ routes.insert(webpath);
+ webpath += "/";
+ }
}
- // res.set_header("Cache-Control", "public, max-age=86400");
- std::ifstream inf(absolutePath);
- if (!inf) {
- BMCWEB_LOG_DEBUG << "failed to read file";
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ std::pair<boost::container::flat_set<std::string>::iterator, bool>
+ inserted = routes.insert(webpath);
+
+ if (!inserted.second)
+ {
+ // Got a duplicated path. This is expected in certain
+ // situations
+ BMCWEB_LOG_DEBUG << "Got duplicated path " << webpath;
+ continue;
+ }
+ const char* contentType = nullptr;
+
+ auto contentTypeIt = contentTypes.find(extension.c_str());
+ if (contentTypeIt == contentTypes.end())
+ {
+ BMCWEB_LOG_ERROR << "Cannot determine content-type for "
+ << absolutePath << " with extension "
+ << extension;
+ }
+ else
+ {
+ contentType = contentTypeIt->second;
}
- res.body() = {std::istreambuf_iterator<char>(inf),
- std::istreambuf_iterator<char>()};
- res.end();
- });
+ app.routeDynamic(webpath)(
+ [absolutePath, contentType, contentEncoding](
+ const crow::Request& req, crow::Response& res) {
+ if (contentType != nullptr)
+ {
+ res.addHeader("Content-Type", contentType);
+ }
+
+ if (contentEncoding != nullptr)
+ {
+ res.addHeader("Content-Encoding", contentEncoding);
+ }
+
+ // res.set_header("Cache-Control", "public, max-age=86400");
+ std::ifstream inf(absolutePath);
+ if (!inf)
+ {
+ BMCWEB_LOG_DEBUG << "failed to read file";
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+
+ res.body() = {std::istreambuf_iterator<char>(inf),
+ std::istreambuf_iterator<char>()};
+ res.end();
+ });
+ }
}
- }
-} // namespace webassets
-} // namespace webassets
-} // namespace crow
+} // namespace webassets
+} // namespace webassets
+} // namespace crow