retrieving string from boost::tuples::tuple - boost-tuples

After reading the article at https://www.boost.org/doc/libs/1_67_0/libs/tuple/doc/html/tuple_users_guide.html
The following note is a problem for me.
Note that extracting tuples with std::string or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable.
What type should I use to unambiguously parse strings from a stream into a tuple?
When retrieving a std::string from a tuple the string is devided by white space. Which is not desired! Setting a delimiter e.g., a number sign ( # ) does not help.
// typedef tuple
typedef std::string td_current_gmt, td_remote_endpoint,
td_request, td_response, td_elapsed_time;
typedef boost::tuples::tuple<td_current_gmt, td_remote_endpoint,
td_request, td_response, td_elapsed_time> tuple_logging;
// store in tuple
tuple_logging tl{ current_gmt, remote_endpoint,
request, response, elapsed_time };
// write tuple to file
tl = boost::tuples::make_tuple(current_gmt, remote_endpoint,
request, response, elapsed_time);
boost::filesystem::path p = { "logging" };
boost::filesystem::ofstream ofs{ p };
ofs << /*boost::tuples::set_delimiter('#') <<*/ tl;
ofs.close();
// read tuple from file
tuple_logging tlin{ current_gmt, remote_endpoint,
request, response, elapsed_time };
boost::filesystem::ifstream ifs{ p };
//ifs >> boost::tuples::set_delimiter('#');
ifs >> tlin;
The output is (Fri, 16 Aug 2019 06:28:05)
But actually it has to be (Fri, 16 Aug 2019 06:28:05 GMT 192.168.178.14:52832 TRACE / HTTP/1.1 HTTP/1.1 200 OK 8.936800)

Here's the code.
void parse_logfile(
boost::filesystem::ifstream& ifs,
const boost::filesystem::path& p,
std::vector<tuple_logging>& vector_with_tuples
)
{
typedef std::string one_line_from_logging;
one_line_from_logging str;
tuple_logging tlin;
// clear vector
vector_with_tuples.clear();
// open log file for reading
ifs.open(p);
// read one line from log file, until eof
while (std::getline(ifs, str))
{
size_t sBegin = 0, sEnd = 0;
// 1
// first character on a line is '(',
// start at sBegin = 1
sBegin = sEnd + 1;
sEnd = str.find('#', sBegin);
std::string current_gmt_ = str.substr(sBegin, sEnd - sBegin);
// 2
sBegin = sEnd + 1;
sEnd = str.find('#', sBegin);
std::string remote_endpoint_ = str.substr(sBegin, sEnd - sBegin);
// 3
sBegin = sEnd + 1;
sEnd = str.find('#', sBegin);
std::string request_ = str.substr(sBegin, sEnd - sBegin);
// 4
sBegin = sEnd + 1;
sEnd = str.find('#', sBegin);
std::string response_ = str.substr(sBegin, sEnd - sBegin);
// 5
sBegin = sEnd + 1;
// last character on a line is ')'
sEnd = str.find(')', sBegin);
std::string elapsed_time_ = str.substr(sBegin, sEnd - sBegin);
// create tuple from parsed log data out of file
tlin = boost::tuples::make_tuple(
current_gmt_,
remote_endpoint_,
request_,
response_,
elapsed_time_
);
// set tuple into vector
vector_with_tuples.push_back(tlin);
}
// close log file
ifs.close();
}

Related

sendmsg() with Unix domain socket blocks forever on Mac with specific sizes

I'm sending messages on Unix domain sockets on Mac with sendmsg(). However, it sometimes hangs forever.
I've called getsockopt(socket, SOL_SOCKET, SO_SNDBUF, ...) to get the size of the send buffer. (The default is 2048).
If I try sending a message larger than 2048 bytes, I correctly get
EMSGSIZE and know I need to send a smaller message.
If I try sending a message less than 2036 bytes, the message is sent fine.
If I try sending a message between 2036 and 2048 bytes, the
sendmsg call...hangs forever.
What's going on here? What's the correct way to deal with this? Is it safe to just subtract 13 bytes from the maximum size I try sending, or could I run into issues if e.g. there's other messages in the buffer already?
Here's the (simplified) code I'm using:
// Get the maximum message size
int MaxMessageSize(int socket) {
int sndbuf = 0;
socklen_t optlen = sizeof(sndbuf);
if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) {
return -1;
}
return sndbuf;
}
// Send a message
static int send_chunk(int socket, const char *data, size_t size) {
struct msghdr msg = {0};
char buf[CMSG_SPACE(0)];
memset(buf, '\0', sizeof(buf));
int iov_len = size;
if (iov_len > 512) {
int stat = send_size(socket, iov_len);
if (stat < 0) return stat;
}
char iov_buf[iov_len];
memcpy(iov_buf, data, size);
struct iovec io = {.iov_base = (void *)iov_buf, .iov_len = iov_len};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(0);
msg.msg_controllen = CMSG_SPACE(0);
std::cerr << "Attempting to send message of size " << iov_len << std::endl;
ssize_t ret = sendmsg(socket, &msg, 0);
std::cerr << "sendmsg returned: " << ret << std::endl;
return ret;
}

Split encrypted messages into chunks and put them together again

I want to send GPG encrypted data via GET request of known format.
Issue #1: Data block size in the request is limited (4096 symbols), and it is not enough for a typical GPG message. So, I need to chunk it.
Issue #2: Chunks may be sent in the wrong order. Each chunk must have a unique message ID and serial number, so the messages can be put together.
GPG has the method to send encrypted data in text format (armoring). RFC 2440 standard allows chunking armored messages:
BEGIN PGP MESSAGE, PART X/Y
Used for multi-part messages, where the armor is split amongst Y
parts, and this is the Xth part out of Y.
BEGIN PGP MESSAGE, PART X
Used for multi-part messages, where this is the Xth part of an
unspecified number of parts. Requires the MESSAGE-ID Armor Header
to be used.
But, unfortunately, I've found no evidence that this feature is implemented in GPG.
And no word about chunking of public keys, which, actually, can be huge too.
So I turned down the idea of using native GPG armors for chunking.
My current home-made solution: binary encrypted data are splitted into chunks, then each chunk is put into a block, which contains UUID (MessageID analog), the serial number of the block, the total number of blocks, and CRC checksum of the block.
Like that:
[ UUID ][ Number ][ Total ][ Chunk of encrypted data ][ Checksum ]
Putting the message together out of that blocks is a bigger challenge, but doable as well.
But I want more clear solution, preferably on C++.
Could you help me?
Qt provides very simple methods for data serialization. I created a class to chunk, store, and rebuild binary data, and for now I don't think I need something more simple.
But, if someone knows a better solution, please share it with me.
#include <QByteArrayView>
#include <QDataStream>
#include <QException>
#include <QUuid>
enum CHUNKER {
MESSAGE_READY = 0,
BLOCK_ADDED
};
struct ChunkedMessage {
QUuid UUID;
QByteArray Data;
};
class Chunker {
public:
Chunker();
~Chunker();
static quint16 GetChecksum(QByteArray *Block);
static QByteArrayList ArmorData(QByteArray *Data, qsizetype *ChunkSize);
CHUNKER AddBlock(QByteArray *Block, ChunkedMessage *Message);
private:
struct MessageBlock {
QUuid UUID;
quint32 Number;
quint32 Total;
QByteArray Data;
};
QMap<QUuid, quint32> Sizes;
QMap<QUuid, QMap<quint32, Chunker::MessageBlock>*> Stack;
MessageBlock DearmorChunk(QByteArray *Block);
bool CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed);
};
Chunker::Chunker() { }
Chunker::~Chunker() { }
quint16 Chunker::GetChecksum(QByteArray *Block) { return qChecksum(QByteArrayView(*Block), Qt::ChecksumIso3309); }
QByteArrayList Chunker::ArmorData(QByteArray *Data, qsizetype *ChunkSize) {
QByteArrayList Result;
QUuid UUID = QUuid::createUuid();
qsizetype RealChunkSize = (*ChunkSize) - sizeof(UUID.toRfc4122()) - sizeof(quint32) - sizeof(quint32) - sizeof(quint16);
const quint32 ChunkCount = ((*Data).length() / RealChunkSize) + 1;
for (auto Pos = 0; Pos < ChunkCount; Pos++) {
QByteArray Block;
QDataStream Stream(&Block, QIODeviceBase::WriteOnly);
Stream << UUID.toRfc4122() << (Pos + 1) << ChunkCount << (*Data).mid(Pos * RealChunkSize, RealChunkSize);
Stream << Chunker::GetChecksum(&Block);
Result.push_back(Block);
}
return Result;
}
Chunker::MessageBlock Chunker::DearmorChunk(QByteArray *Block) {
Chunker::MessageBlock Result;
QDataStream Stream(Block, QIODeviceBase::ReadOnly);
QByteArray ClearBlock = (*Block).chopped(sizeof(quint16));
QByteArray BytesUUID;
quint16 Checksum;
Stream >> BytesUUID >> Result.Number >> Result.Total >> Result.Data >> Checksum;
Result.UUID = QUuid::fromRfc4122(QByteArrayView(BytesUUID));
if (Chunker::GetChecksum(&ClearBlock) != Checksum) throw std::runtime_error("Checksums are not equal");
return Result;
}
bool Chunker::CheckIntegrity(QUuid *UUID, QByteArray *Reconstructed) {
quint32 Size = this->Sizes[*UUID];
if (this->Stack[*UUID]->size() > Size) throw std::runtime_error("Corrupted message blocks");
if (this->Stack[*UUID]->size() < Size) return false;
for (quint32 Counter = 0; Counter < Size; Counter++) {
if (!(this->Stack[*UUID]->contains(Counter + 1))) return false;
(*Reconstructed).append((*(this->Stack[*UUID]))[Counter + 1].Data);
}
return true;
}
CHUNKER Chunker::AddBlock(QByteArray *Block, ChunkedMessage *Message) {
Chunker::MessageBlock DecodedBlock = Chunker::DearmorChunk(Block);
if (!this->Sizes.contains(DecodedBlock.UUID)) {
this->Sizes[(QUuid)DecodedBlock.UUID] = (quint32)DecodedBlock.Total;
this->Stack[(QUuid)DecodedBlock.UUID] = new QMap<quint32, Chunker::MessageBlock>;
}
(*(this->Stack[DecodedBlock.UUID]))[(quint32)(DecodedBlock.Number)] = Chunker::MessageBlock(DecodedBlock);
QByteArray ReconstructedData;
if (this->CheckIntegrity(&DecodedBlock.UUID, &ReconstructedData)) {
(*Message).UUID = (QUuid)(DecodedBlock.UUID);
(*Message).Data = (QByteArray)ReconstructedData;
this->Sizes.remove(DecodedBlock.UUID);
delete this->Stack[DecodedBlock.UUID];
this->Stack.remove(DecodedBlock.UUID);
return CHUNKER::MESSAGE_READY;
}
return CHUNKER::BLOCK_ADDED;
}

Reading binary data

I am trying to read data from a binary file. One block of data is 76 bytes long (this varies with the number of the 2-byte "main data items" in the middle of the block). The first datum is 4 bytes, second is 4 bytes, and then there are a bunch of 2 byte main data items, and at the end are 2 more 2-byte pieces of data.
Based on this Delphi sample I've learned how to read the file with the code below:
short AShortInt; // 16 bits
int AInteger; // 32 bits
try
{
infile=new TFileStream(myfile,fmOpenRead); // myfile is binary
BR = new TBinaryReader(infile, TEncoding::Unicode, false);
for (int rows = 0; rows < 5; rows++) { // just read the first 5 blocks of data for testing
AInteger = BR->ReadInt32(); // read first two 4 byte integers for this block
AInteger = BR->ReadInt32();
for (int i = 0; i < 32; i++) { // now read the 32 2-byte integers from this block
AShortInt = BR->ReadInt16();
}
AShortInt = BR->ReadInt16(); // read next to last 2-byte int
AShortInt = BR->ReadInt16(); // read the last 2-byte int
}
delete infile;
delete BR;
Close();
}
catch(...)
{
delete infile; // closes the file, doesn't delete it.
delete BR;
ShowMessage("Can't open file!");
Close();
}
But, what i would like to do is use a 76-byte wide buffer to read the entire block, and then pick the various datum out of that buffer. I put together the following code based on this question and i can read a whole block of data into the buffer.
UnicodeString myfile = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "binaryCOM.dat");
TFileStream*infile=0;
try
{
infile=new TFileStream(myfile,fmOpenRead);
const int bufsize=76;
char*buf=new char[bufsize];
int a = 0;
while(int bytesread=infile->Read(buf,bufsize)) {
a++; // just a place to break on Run to Cursor
}
delete[]buf;
}
catch(...)
{
delete infile;
ShowMessage("Can't open file!");
Close();
}
But i can't figure out how to piece together subsets out of the bytes in the buffer. Is there a way to concatenate bytes? So i could read a block of data into a 76 byte buffer and then do something like this below?
unsigned int FirstDatum = buf[0]+buf[1]+buf[2]+buf[3]; // concatenate the 4 bytes for the first piece of data
This will be an FMX app for Win32, iOS, and Android built in C++Builder 10.3.2.
Here is my modified code using Remy's suggestion of TMemoryStream.
UnicodeString myfile = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "binaryCOM.dat");
TMemoryStream *MS=0;
TBinaryReader *BR=0;
std::vector<short> myArray;
short AShortInt;
int AInteger;
int NumDatums = 32; // the variable number of 2-byte main datums
try
{
MS = new TMemoryStream();
MS->LoadFromFile(myfile);
BR = new TBinaryReader(MS, TEncoding::Unicode, false);
for (int rows = 0; rows < 5; rows++) { // testing with first 5 blocks of data
AInteger = BR->ReadInt32(); // read first two 4 byte integers
AInteger = BR->ReadInt32(); // here
for (int i = 0; i < NumDatums; i++) { // read the main 2-byte data
AShortInt = BR->ReadInt16();
myArray.push_back(AShortInt); // push it into vector
}
AShortInt = BR->ReadInt16(); // read next to last 2-byte int
AShortInt = BR->ReadInt16(); // read the last 2-byte int
// code here to do something with this block of data just read from file
}
}
delete MS;
delete BR;
}
catch(...)
{
delete MS;
delete BR;
ShowMessage("Can't open file.");
}

SAFEARRAY data to unsigned char*

I am trying to convert a SAFEARRAY data pointer to unsinged char*. However I am not getting the expected data. Here is a snippet.
SafeArrayLock(psaFrameData);
psaFrameData->rgsabound->cElements;
int nCount = psaFrameData->rgsabound->cElements - psaFrameData->rgsabound->lLbound + 1;
frameData = new unsigned char[nCount];
memset(frameData, 0, nCount);
for (int i = 0; i < nCount; ++i)
{
frameData[i] = ((unsigned char*)(psaFrameData)->pvData)[i];
}
SafeArrayUnlock(psaFrameData);
Do not manually lock the array and then access its pvData (or any of its other data members) directly. Use the various accessors functions instead, such as SafeArrayAccessData():
Increments the lock count of an array, and retrieves a pointer to the array data.
Try something more like this:
// safety check: make sure the array has only 1 dimension...
if (SafeArrayGetDim(psaFrameData) != 1)
{
// handle the error ...
}
else
{
// safety check: make sure the array contains byte elements...
VARTYPE vt = 0;
SafeArrayGetVartype(psaFrameData, &vt);
if (vt != VT_UI1)
{
// handle the error ...
}
else
{
// get a pointer to the array's byte data...
unsigned char *data;
if (FAILED(SafeArrayAccessData(psaFrameData, (void**)&data)))
{
// handle the error ...
}
else
{
// calculate the number of bytes in the array...
LONG lBound, uBound;
SafeArrayGetLBound(psaFrameData, 1, &lBound);
SafeArrayGetUBound(psaFrameData, 1, &uBound);
long nCount = uBound - lBound + 1;
// copy the bytes...
frameData = new unsigned char[nCount];
memcpy(frameData, data, nCount);
// release the pointer to the array's byte data...
SafeArrayUnaccessData(psaFrameData);
}
}
}

CAN communication not working between different PIC

I am working on project, and we need to establish a CAN communication between 4 nodes, 2 using a PIC 18F4580 and 2 using 18F25K80. In all those circuits, I'm using a Crystal oscillator 20MHz. The issue is when I test the communication between same PICs, it's working, but when I try with two different PICs it's not working.
The codes I used to test:
For the emitting PIC 18F4580 : Emitting a CAN message every 1 second :
int i;
unsigned char Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags; // can flags
unsigned char Rx_Data_Len; // received data length in bytes
char RxTx_Data[8]; // can rx/tx data buffer
char Msg_Rcvd; // reception flag
const long ID_cmd = 3, ID_led1 = 2; // node IDs
long Rx_ID;
void main() {
ADCON1=0xF;
TRISA=0xFF;
TRISD=0;
PORTD=0;
for(i=0;i<10;i++) {
PORTD=0xFF ^ PORTD; //Blinking Leds
Delay_ms(100);
}
Can_Init_Flags = 0; //
Can_Send_Flags = 0; // clear flags
Can_Rcv_Flags = 0; //
Can_Send_Flags = _CAN_TX_PRIORITY_0 & // form value to be used
_CAN_TX_XTD_FRAME & // with CANWrite
_CAN_TX_NO_RTR_FRAME;
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE & // form value to be used
_CAN_CONFIG_PHSEG2_PRG_ON & // with CANInit
_CAN_CONFIG_XTD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG;
CANInitialize(1,3,3,3,1,Can_Init_Flags); // Initialize CAN module
CANSetOperationMode(_CAN_MODE_NORMAL,0xFF); // set NORMAL mode
for(i=0;i<10;i++) {
PORTD=0xFF ^ PORTD; //Blinking Leds
Delay_ms(100);
}
while(1){
PORTD.F7=PORTA.F0;
PORTD.F6=PORTA.F1;
PORTD.F5=PORTA.F2;
PORTD.F4=PORTA.F3; //LEDS := SWITCHS
CANWrite(ID_cmd, RxTx_Data, 1, Can_Send_Flags); // send incremented data back
Delay_ms(1000);
}
}
For the receiving Node PIC 18F25K80 : Blink after receiving any CAN message (Should blink every 1 second) :
unsigned char Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags; // can flags
unsigned char Rx_Data_Len; // received data length in bytes
char RxTx_Data[8]; // can rx/tx data buffer
char Msg_Rcvd; // reception flag
const long ID_led1 = 2, ID_cmd = 3; // node IDs
long Rx_ID;
void main() {
//OSCCON |= 0b01110010;
TRISC = 0;
Can_Init_Flags = 0; //
Can_Send_Flags = 0; // clear flags
Can_Rcv_Flags = 0; //
Can_Send_Flags = _CAN_TX_PRIORITY_0 & // form value to be used
_CAN_TX_XTD_FRAME & // with CANWrite
_CAN_TX_NO_RTR_FRAME;
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE & // form value to be used
_CAN_CONFIG_PHSEG2_PRG_ON & // with CANInit
_CAN_CONFIG_XTD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG;
CANInitialize(1,3,3,3,1,Can_Init_Flags); // Initialize CAN module
CANSetOperationMode(_CAN_MODE_CONFIG,0xFF); // set CONFIGURATION mode
CANSetMask(_CAN_MASK_B1,-1,_CAN_CONFIG_XTD_MSG); // set all mask1 bits to ones
CANSetMask(_CAN_MASK_B2,-1,_CAN_CONFIG_XTD_MSG); // set all mask2 bits to ones
CANSetFilter(_CAN_FILTER_B2_F4,ID_cmd,_CAN_CONFIG_XTD_MSG);// set id of filter B2_F4 to 2nd node ID
CANSetOperationMode(_CAN_MODE_NORMAL,0xFF); // set NORMAL mode
while(1) { // endless loop
Msg_Rcvd = CANRead(&Rx_ID , RxTx_Data , &Rx_Data_Len, &Can_Rcv_Flags); // receive message
if ((Rx_ID == ID_cmd) && Msg_Rcvd) { // if message received check id
PORTC.F3=!PORTC.F3;
}
}
}
Any help would be greatly appreciated, thanks.
It's me again, it worked, the nodes must have the same oscillator value (in my case : 20MHz Crystal).

Resources