I have the following proto file
package DS3DExcite.Cpp.ExternalVariantSwitcher.ProtocolBuffers;
message DGCommand
{
extensions 100 to max;
enum Type
{
AttachModel = 1;
AttachModelReply = 2;
....
...
SwitchVariants = 4;
}
required Type type = 1;
required uint32 id = 2;
optional uint32 replyTo = 3 [default = 0];
optional string message = 4;
}
message SwitchVariants
{
extend DGCommand
{
required SwitchVariants command = 103;
}
message VariantState
{
required string variant = 1;
required string state = 2;
}
repeated VariantState variants = 1;
repeated string variantNames = 2;
optional string state = 3;
}
I compiled the proto file with protobuf 2.4.1 version to generate .pb.h and .pb.cc files
Now I form the commands
DS3DExcite::Net::PVCConnector::ProtocolBuffers::DGCommand commandObj;
commandObj.set_type(DS3DExcite::Net::PVCConnector::ProtocolBuffers::DGCommand_Type_SwitchVariants);
commandObj.set_id(3);
DS3DExcite::Net::PVCConnector::ProtocolBuffers::SwitchVariants *objVarState;
objVarState = commandObj.MutableExtension(DS3DExcite::Net::PVCConnector::ProtocolBuffers::SwitchVariants::command);
DS3DExcite::Net::PVCConnector::ProtocolBuffers::SwitchVariants_VariantState *state = objVarState->add_variants();
state->set_state("OFF");
state->set_variant("M_Carpaint_3");
I serialise the message
int size = commandObj.ByteSize();
int sizeSize = sizeof(int);
std::vector<char> data(size ,0);
memcpy(data.data(), &size, sizeSize);
data.resize(size + sizeSize );
commandObj.SerializeToArray(static_cast<void*>(&(data[0])+sizeSize) ,size);
QByteArray byteArray = QByteArray::fromRawData(static_cast<const char*>(data.data()), data.size());
And I send this message on a Qtcp socket to server which deserializes the message and extract the information from the message .
At the server end this is the code to read
uint32 pendingData = 0;
rcvSocket->HasPendingData(pendingData); //rcvSocket is the serversside socket
if (pendingData == 0)
{
UE_LOG(PVCConnector, Warning, TEXT("Lost connection to client."));
break;
}
TArray<char> newData; //customized Array template
newData.InsertZeroed(0, pendingData);
int32 bytesRead = 0;
rcvSocket->Recv(reinterpret_cast<uint8*>(newData.GetData()), pendingData, bytesRead);
data += newData;
However at the server end the the desired information lands up in the unknown fields of ::google::protobuf::Message . What could be the reason ?
I had a similar problem whe I have been sending big enough messages. We decide, that this happens when message divided into several net packages. We use blobs to prevent that, and it works. About blobs, its technique to send message length, before message
I was able to solve the problem . There were 2 issues
1) The way I was converting to ByteArray
I replaced
QByteArray byteArray = QByteArray::fromRawData(static_cast<const char*>(data.data()), data.size());
with
QByteArray *byteArray = new QByteArray(reinterpret_cast<const char*>(data.data()), data.size());
2) The way I was sending the message on the socket . I just used
const int nbBytes = itM->second->write(qByteArray);
instead of using QTextStream
Related
I am new to protocol buffers and I am having issues with multiple messages using Any data.
I am not sure if I am using it correctly.
I have the following in message.proto
import "google/protobuf/any.proto";
message config {
string ip = 1;
string username = 2;
string serialnumber = 3;
};
message userdata {
string username = 1;
};
message ServerMessage {
config = 1;
userdata = 2;
google.protobuf.Any data = 3;
};
I am trying to serialize and send the data like below
ServerMessage server_msg;
google::protobuf::Any any;
server_msg.mutable_userdata()->set_username("test");
any.PackFrom(server_msg);
boost::asio::streambuf sbuf;
ostream serialized(&sbuf);
any.SerializeToOstream(&serialized);
On the receiving side, I try to deserialize like below
userdata msg;
google::protobuf::Any any;
any.ParseFromArray(message.data(), message.size());
if (any.Is<userdata>()) {
std::cout<<"It is a userdata mesage"<<std::endl;
}
if (any.Is<config>()) {
std::cout<<"it is a config message"<<std::endl;
}
if (any.UnpackTo(&msg)) {
std::cout<<msg.username()<<std::endl;
} else {
std::cout<<"could not unpack"<<std::endl;
}
The packing doesn't complain. But it is not able to unpack or determine the message type.
Am I packing it wrong?
I really appreciate your help with this!
I am not an expert on Protobuf, but I think the problem is that you are packing a ServerMessage and unpacking a userdata.
You should unpack a ServerMessage and then access the userdata() member.
I am currently messing the first time with iOS and Objective-C++. Im coming from C/C++ so please excuse my bad coding in the below examples.
I am trying to live stream the microphone audio of my iOS device over tcp, the iOS device is acting as server and sends the data to all clients that connect.
To do so, I am first using AVCaptureDevice and requestAccessForMediaType:AVMediaTypeAudio to request access to the microphone (along with the needed entry in the Info.plist).
Then I create a AVCaptureSession* using the below function:
AVCaptureSession* createBasicARecordingSession(aReceiver* ObjectReceivingAudioFrames){
AVCaptureSession* s = [[AVCaptureSession alloc] init];
AVCaptureDevice* aDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput* aInput = NULL;
if([aDevice lockForConfiguration:NULL] == YES && aDevice){
aInput = [AVCaptureDeviceInput deviceInputWithDevice:aDevice error:nil];
[aDevice unlockForConfiguration];
}
else if(!aDevice){
fprintf(stderr, "[d] could not create device. (%p)\n", aDevice);
return NULL;
}
else{
fprintf(stderr, "[d] could not lock device.\n");
return NULL;
}
if(!aInput){
fprintf(stderr, "[d] could not create input.\n");
return NULL;
}
AVCaptureAudioDataOutput* aOutput = [[AVCaptureAudioDataOutput alloc] init];
dispatch_queue_t aQueue = dispatch_queue_create("aQueue", NULL);
if(!aOutput){
fprintf(stderr, "[d] could not create output.\n");
return NULL;
}
[aOutput setSampleBufferDelegate:ObjectReceivingAudioFrames queue:aQueue];
// the below line does only work on macOS
//aOutput.audioSettings = settings;
[s beginConfiguration];
if([s canAddInput:aInput]){
[s addInput:aInput];
}
else{
fprintf(stderr, "[d] could not add input.\n");
return NULL;
}
if([s canAddOutput:aOutput]){
[s addOutput:aOutput];
}
else{
fprintf(stderr, "[d] could not add output.\n");
return NULL;
}
[s commitConfiguration];
return s;
}
The aReceiver* class (?) is defined below and receives the audio frames provided by the AVCaptureAudioDataOutput* object. The frames are stored inside a std::vector.
(im adding the code as image as I could not get it formatted right...)
Then I start the AVCaptureSession* using [audioSession start]
When a tcp client connects I first create a AudioConverterRef and two AudioStreamBasicDescription to convert the audio frames to AAC, see below:
AudioStreamBasicDescription asbdIn, asbdOut;
AudioConverterRef converter;
asbdIn.mFormatID = kAudioFormatLinearPCM;
//asbdIn.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
asbdIn.mFormatFlags = 12;
asbdIn.mSampleRate = 44100;
asbdIn.mChannelsPerFrame = 1;
asbdIn.mFramesPerPacket = 1;
asbdIn.mBitsPerChannel = 16;
//asbdIn.mBytesPerFrame = (asbdIn.mBitsPerChannel / 8) * asbdIn.mBitsPerChannel;
asbdIn.mBytesPerFrame = 2;
asbdIn.mBytesPerPacket = asbdIn.mBytesPerFrame;
asbdIn.mReserved = 0;
asbdOut.mFormatID = kAudioFormatMPEG4AAC;
asbdOut.mFormatFlags = 0;
asbdOut.mSampleRate = 44100;
asbdOut.mChannelsPerFrame = 1;
asbdOut.mFramesPerPacket = 1024;
asbdOut.mBitsPerChannel = 0;
//asbdOut.mBytesPerFrame = (asbdOut.mBitsPerChannel / 8) * asbdOut.mBitsPerChannel;
asbdOut.mBytesPerFrame = 0;
asbdOut.mBytesPerPacket = asbdOut.mBytesPerFrame;
asbdOut.mReserved = 0;
OSStatus err = AudioConverterNew(&asbdIn, &asbdOut, &converter);
Then I create a AudioBufferList* to store the encoded frames:
while(audioInput.locked){ // audioInput is my aReceiver*
usleep(0.2 * 1000000);
}
audioInput.locked = true;
UInt32 RequestedPackets = 8192;
//AudioBufferList* aBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList));
AudioBufferList* aBufferList = static_cast<AudioBufferList*>(calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * 1)));
aBufferList->mNumberBuffers = 1;
aBufferList->mBuffers[0].mNumberChannels = asbdIn.mChannelsPerFrame;
aBufferList->mBuffers[0].mData = static_cast<void*>(calloc(RequestedPackets, asbdIn.mBytesPerFrame));
aBufferList->mBuffers[0].mDataByteSize = asbdIn.mBytesPerFrame * RequestedPackets;
Then I go through the frames stored in the std::vector mentioned earlier and pass them to AudioConverterFillComplexBuffer(). After conversion, i concat all encoded frames into one NSMutableData which I then write() to the socket connected to the client.
long aBufferListSize = audioInput.aBufferList.size();
while(aBufferListSize > 0){
err = AudioConverterFillComplexBuffer(converter, feedAFrames, static_cast<void*>(&audioInput.aBufferList[audioInput.aBufferList.size() - aBufferListSize]), &RequestedPackets, aBufferList, NULL);
NSMutableData* encodedData = [[NSMutableData alloc] init];
long encodedDataLen = 0;
for(int i = 0; i < aBufferList->mNumberBuffers; i++){
Float32* frame = (Float32*)aBufferList->mBuffers[i].mData;
[encodedData appendBytes:frame length:aBufferList->mBuffers[i].mDataByteSize];
encodedDataLen += aBufferList->mBuffers[i].mDataByteSize;
}
unsigned char* encodedDataBytes = (unsigned char*)[encodedData bytes];
fprintf(stderr, "[d] got %li encoded bytes to send...\n", encodedDataLen);
long bytes = write(Client->GetFD(), encodedDataBytes, encodedDataLen);
fprintf(stderr, "[d] written %li of %li bytes.\n", bytes, encodedDataLen);
usleep(0.2 * 1000000);
aBufferListSize--;
}
audioInput.aBufferList.clear();
audioInput.locked = false;
Below is the feedAFrames() callback used in the AudioConverterFillComplexBuffer() call:
(again this is an image of the code, same reason as above)
Step 5 to 7 are repeated until the tcp connection is closed.
Each step runs without any noticeable error (I know I could include way better error handling here), and I do get data out of step 3 and 7. However it does not seem to be AAC what comes out at the end.
As im rather new to all of this, im really not sure what my error is, im sure there are several things I made wrong. It is kind of hard to find suitable example code of what I am trying to do, and the above is the best I could come up with until now with all that I have found paired with the apple dev documentation.
I hope someone might take some time to explain me what I did wrong and how I can get this to work. Thanks for reading until here!
I've been following this tutorial for SSL/TLS online (well its more of reading the guys source code and following along) but I've hit a bumpy road with this EncryptMessage part because it pushes the data out of the way and encrypts the wrong info.
The pbloBuffer that I send it is:
GET / HTTP/1.1\r\n
HOST: www.google.com\r\n\r\n
But when I do pbMessage = pbloBuffer + Sizes.cbHeader; I end up with (even the microsoft websites says to do this)
1\r\n
HOST: www.google.com\r\n\r\n
Now pbMessage is the code above, and that's inserted under SECBUFFER_DATA so it's not even getting the full data. From what I understand SECBUFFER_DATA is the "user" data that the Webserver will decode and process.
Can you find out how to fix this and properly send the encrypted data?
Full source: (This code is experimental as I am trying to understand it before I makes changes)
int Adaptify::EncryptSend(PBYTE pbloBuffer, int Size) {
SECURITY_STATUS scRet{ 0 };
SecBufferDesc Message{ 0 };
SecBuffer Buffers[4]{ 0 };
DWORD cbMessage = 0, cbData = 0;
PBYTE pbMessage = nullptr;
SecPkgContext_StreamSizes Sizes = { 0 };
QueryContextAttributesW(&hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
pbMessage = pbloBuffer + Sizes.cbHeader;
cbMessage = (DWORD)strlen((const char*)pbMessage);
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
Buffers[0].cbBuffer = Sizes.cbHeader;
Buffers[0].pvBuffer = pbloBuffer;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].pvBuffer = pbMessage;
Buffers[1].cbBuffer = cbMessage;
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
Buffers[2].cbBuffer = Sizes.cbTrailer;
Buffers[2].pvBuffer = pbMessage + cbMessage;
Buffers[3].BufferType = SECBUFFER_EMPTY;
Buffers[3].cbBuffer = SECBUFFER_EMPTY;
Buffers[3].pvBuffer = SECBUFFER_EMPTY;
Message.cBuffers = 4;
Message.pBuffers = Buffers;
Message.ulVersion = SECBUFFER_VERSION;
scRet = EncryptMessage(&hContext, 0, &Message, 0);
if (send(hSocket, (const char*)pbloBuffer, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer, 0) < 0) {
MessageBox(0, L"Send error", 0, 0);
}
return 0;
}
first - you need call QueryContextAttributesW only once after InitializeSecurityContextW return SEC_E_OK - no sense call it every time, when you need send data. and save result. say inherit your class from SecPkgContext_StreamSizes - class Adaptify : SecPkgContext_StreamSizes; and call on end handshake (once) QueryContextAttributesW(&hContext, SECPKG_ATTR_STREAM_SIZES, this);
about send send data - in your case Buffers[1].pvBuffer of course must point to your actual data pbloBuffer but not to pbloBuffer + Sizes.cbHeader code can be like this:
int Adaptify::EncryptSend(PBYTE pbloBuffer, int Size) {
SECURITY_STATUS ss = SEC_E_INSUFFICIENT_MEMORY;
if (PBYTE Buffer = new BYTE[cbHeader + Size + cbTrailer]) {
memcpy(Buffer + cbHeader, pbloBuffer, Size);
SecBuffer sb[4] = {
{ cbHeader, SECBUFFER_STREAM_HEADER, Buffer},
{ Size, SECBUFFER_DATA, Buffer + cbHeader},
{ cbTrailer, SECBUFFER_STREAM_TRAILER, Buffer + cbHeader + Size},
};
SecBufferDesc sbd = {
SECBUFFER_VERSION, 4, sb
};
if (SEC_E_OK == (ss = ::EncryptMessage(this, 0, &sbd, 0)))) {
if (SOCKET_ERROR == send(hSocket, (const char*)Buffer, sb[0].cbBuffer+sb[1].cbBuffer+sb[2].cbBuffer+sb[3].cbBuffer, 0))
ss = WSAGetLastError();
}
delete [] Buffer;
}
return ss;
}
so you need allocate new buffer with cbHeader + Size + cbTrailer size (wher Size is your actual message Size and copy your message at Buffer + cbHeader
I'm a newbie in C++ and Qt. I want to save in an array the value received in a serialport after I received the string: "Data".
I'm using the terminal example so the serialport works properly.
The read function in the Example is the same:
void MainWindow::readData()
{
QByteArray data = serial->readAll();
console->putData(data);
}
How can I modify it? thanks!!!
If your manual sending the data i recommend you add a start of frame delimiter and an end of frame delimiter and checksum preferably.
QByteArray packet_storage;
just declare it the where you declare serial.
StartOfMessage and EndOfMessage will depend on your device.
I don't know what your transmitting. Hopefully you can figure out from the documentation of your device what your sending out.
as for me i am using
enum Constants
{
StartOfMessage = '\x02', /* Value of byte that marks the start of a message */
EndOfMessage = '\x03', /* Value of byte that marks the end of a message */
CarridgeReturn = '\x0D', /* Carridge return is first byte of end of line */
LineFeed = '\x0A', /* Line feed is second byte of end of line */
NullChar = '\0' /* Null Character */
};
void MainWindow::readData()
{
// read all
QByteArray data = serial->readAll();
// store all read data packet_storage is a QByteArray
packet_storage.append(data);
int start_index = 0;
int end_index = 0;
// process packet if not empty
if(!packet_storage.isEmpty())
{
if( packet_storage.contains(StartOfMessage) && packet_storage.contains(EndOfMessage))
{
start_index = packet_storage.indexOf(StartOfMessage,0);
end_index = packet_storage.indexOf(EndOfMessage,0);
int length = 0;
for (int i=start_index; i <= end_index; i++)
{
length++;
}
// get data
QByteArray dt = packet_storage.mid(start_index,length);
// do your processing here.
// store in vector write to file etc.
processpacket(dt);
packet_storage.remove(start_index,dt.size());
}
}
}
I use the following code to encrypt a string with a key, using the 3-DES algorithm:
private bool Encode(string input, out string output, byte[] k, bool isDOS7)
{
try
{
if (k.Length != 16)
{
throw new Exception("Wrong key size exception");
}
int length = input.Length % 8;
if (length != 0)
{
length = 8 - length;
for (int i = 0; i < length; i++)
{
input += " ";
}
}
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.Zeros;
des.Key = k;
ICryptoTransform ic = des.CreateEncryptor();
byte[] bytePlainText = Encoding.Default.GetBytes(input);
MemoryStream ms = new MemoryStream();
CryptoStream cStream = new CryptoStream(ms,
ic,
CryptoStreamMode.Write);
cStream.Write(bytePlainText, 0, bytePlainText.Length);
cStream.FlushFinalBlock();
byte[] cipherTextBytes = ms.ToArray();
cStream.Close();
ms.Close();
output = Encoding.Default.GetString(cipherTextBytes);
}
catch (ArgumentException e)
{
output = e.Message;
//Log.Instance.WriteToEvent("Problem encoding, terminalID= "+objTerminalSecurity.TerminalID+" ,Error" + output, "Security", EventLogEntryType.Error);
return false;
}
return true;
}
I send the output parameter as is over to a WCF http-binding webservice, and I noticed that the actual encoded string looks different, it looks like there are some \t and \n but the charachters are about the same.
What is going on, why does the server get a different encoded string?
Usually cipher text is base64 encoded in an effort to be binary safe during transmission.
Also I would not use 3DES with ECB. That is awful, you must have copy pasted this from somewhere. Use AES with cbc mode and think about adding a cmac or hmac.