I'm trying to send and receive messages between two computers via RabbitMQ in C++. My sender code looks like this:
AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Create("192.168.1.1", 5672, "test", "test", "/");
channel->DeclareQueue("rabbit", false, true, false, false);
AmqpClient::BasicMessage::ptr_t msg = AmqpClient::BasicMessage::Create("Hello Rabbit!");
channel->BasicPublish("", "rabbit", msg);
std::cout << "[x] message sent!" << std::endl;
My receiver code on another computer with 192.168.1.1 ip address looks like this:
AmqpClient::Channel::ptr_t connection = AmqpClient::Channel::Create("localhost", 5672, "test", "test", "/");
connection->DeclareQueue("rabbit", false, true, false, false);
std::string consumer = connection->BasicConsume("rabbit", "", true, false);
while(true)
{
AmqpClient::Envelope::ptr_t envelope = connection->BasicConsumeMessage(consumer);
std::cout << "received message: " << envelope->Message()->Body() << std::endl;
std::cout << "[x] ready to receive new message..." << std::endl;
connection->BasicAck(envelope);
}
This works quite fine when the receiver starts to receive AFTER the sender code finishes and terminates. But when I first open the receiver to let it stand by and send message, on the sender side, I receive the following error:
terminate called after throwing an instance of 'AmqpClient::AccessRefusedException'
what(): channel error: 403: AMQP_BASIC_CONSUME_METHOD caused: ACCESS_REFUSED - queue 'rabbit' in vhost '/' in exclusive use
I know this error should raise when the declared queue is in exclusive mode, but here I declared it as non-exclusive (the third boolean parameter in channel->DeclareQueue). Also, my test user has full privilege. What could be the problem here? Thank you.
Ok, I found out that the default value for BasicConsume is exclusive, so it is important to let it be false when declaring your consumer as follows (the third boolean param):
std::string consumer = connection->BasicConsume("rabbit", "", true, false, false);
^^^^^
Interestingly, I didn't find any sentence about this on official documentation.
Related
I made a connection to BitCoin node via WinSock2. I sent the proper "getaddr" message and then the server responds, the replied data are ready to read, because Select() notifies this, but when I call Recv() there are 0 bytes read.
My code is working OK on localhost test server. The incomplete "getaddr" message (less than 24 bytes) is NOT replied by BitCoin node, only proper message, but I can't read the reply with Recv(). After returning 0 bytes, the Select() still returns there are data to read.
My code is divided into DLL which uses Winsock2 and the main() function.
Here are key fragments:
struct CMessageHeader
{
uint32_t magic;
char command[12];
uint32_t payload;
uint32_t checksum;
};
CSocket *sock = new CSocket();
int actual; /* Actually read/written bytes */
sock->connect("109.173.41.43", 8333);
CMessageHeader msg = { 0xf9beb4d9, "getaddr\0\0\0\0", 0, 0x5df6e0e2 }, rcv = { 0 };
actual = sock->send((const char *)&msg, sizeof(msg));
actual = sock->select(2, 0); /* Select read with 2 seconds waiting time */
actual = sock->receive((char *)&rcv, sizeof(rcv));
The key fragment of DLL code:
int CSocket::receive(char *buf, int len)
{
int actual;
if ((actual = ::recv(sock, buf, len, 0)) == SOCKET_ERROR) {
std::ostringstream s;
s << "Nie mozna odebrac " << len << " bajtow.";
throw(CError(s));
}
return(actual);
}
If select() reports the socket is readable, and then recv() returns 0 afterwards, that means the peer gracefully closed the connection on their end (ie, sent a FIN packet to you), so you need to close your socket.
On a side note, recv() can return fewer bytes than requested, so your receive() function should call recv() in a loop until all of the expected bytes have actually been received, or an error occurs (same with send(), too).
I'm working on an esp32 FreeRTOS application with two tasks. Its purpose is to take UART messages received from a peripheral device and transmit them via mqtt to a central broker.
The first task reads input from Serial1, processes the contents into a message structure, and adds it to a FreeRTOS queue:
typedef struct {
int length;
char buffer[AZ_EL_MAX_MESSAGE_LENGTH];
} tag_message_t;
void uart_read_task(void * pvParameters){
BaseType_t xStatus;
tag_message_t tag_message;
while(true) {
while(Serial1.available())
{
first_char = Serial1.read();
if (first_char == '+') // Indicates the beginning of a message
{
for(int i = 0; i < AZ_EL_MAX_MESSAGE_LENGTH; i++)
{
message_buffer[i] = Serial1.read();
if (message_buffer[i] == '\n') // End of message received
{
ESP_LOGV(TAG, "Message found: %s", message_buffer);
strncpy(tag_message.buffer, message_buffer, i + 1);
tag_message.length = i + 1;
xStatus = xQueueSend(xMessagesToSendQueue, (void*) &tag_message, 0);
if (xStatus != pdPASS)
ESP_LOGW(TAG, "Failed to queue message.");
break;
}
}
}
}
vTaskDelay(pdMS_TO_TICKS(20)); // Wait the minimum BLE advertisement period for messages to come in, i.e. 20ms
}
}
The main loop() (which is technically the second FreeRTOS task) then attempts to receive from that queue and transmit over MQTT to a local broker:
void setup()
{
Serial.begin(115200);
// Configure and start WiFi
configure_network();
connect_network();
// Configure the MQTT connection
configure_mqtt_client();
// Configure and create the inter-task queues
xMessagesToSendQueue = xQueueCreate(100, sizeof(tag_message_t));
if (xMessagesToSendQueue == NULL) {
ESP_LOGE(TAG, "Unable to create messaging queue. Will not create UART handling message queue.");
delay(10000);
esp_restart();
} else {
ESP_LOGI(TAG, "Messaging queue generated");
configure_uart();
xTaskCreate(uart_read_task, "UART_Processing", 20000, NULL, 1, NULL);
}
}
void loop()
{
const TickType_t xTicksToWait = pdMS_TO_TICKS(100); // milliseconds to wait
tag_message_t received_message;
if (network_connected) {
connect_mqtt_client();
while(mqtt_client.connected())
{
mqtt_client.loop();
// Process messages on the xMessagesToSendQueue
if (xMessagesToSendQueue != NULL)
{
ESP_LOGI(TAG, "Processing message");
if (xQueueReceive(xMessagesToSendQueue, &received_message, xTicksToWait) == pdPASS)
{
ESP_LOGD(TAG, "Received message, transmitting.");
if(!mqtt_client.publish("aoa", received_message.buffer, received_message.length));
ESP_LOGW(TAG, "Failed transmission.");
}
else
{
vTaskDelay(pdMS_TO_TICKS(50));
}
}
else
{
ESP_LOGE(TAG, "Messages queue is null.");
}
}
} else {
ESP_LOGE(TAG, "WARNING Device not connected to the network. Reconnecting.");
connect_network();
}
delay(5000);
}
I've verified that the MQTT broker works, that it connects to WiFi, and it can properly read messages from Serial1. HOWEVER, the xQueueReceive() call in loop() throws a LoadProhibited exception every time it's called.
Can anyone tell me what I'm getting wrong here?
All, thank you for your help. It turns out this wasn't a FreeRTOS issue. After a little research (i.e. reading this and watching a more experienced engineer explain things: [link]https://hackaday.com/2017/08/17/secret-serial-port-for-arduinoesp32/) it turns out ESP32 Serial1 pins are connected to flash memory.
Every time I tried Serial1.read() or Serial1.readBytesUntil() the ESP32 crashed. Turns out reading the flash is taboo?
I replaced '''Serial1.read()''' with '''Serial2.read()''' and others. That fixed everything. Now I'm off to optimizing my queues!
You are trying to receive an address on the Queue without casting it.
2 solutions: You either declare received_message as a Pointer:
tag_message_t* received_message;
...
received_message = new tag_message_t;
if (xQueueReceive(xMessagesToSendQueue, received_message, xTicksToWait) == pdPASS)
and don't forget to delete it right after usage.
Or you can cast it after receiving :
if (xQueueReceive(xMessagesToSendQueue, &received_message, xTicksToWait) == pdPASS)
{
received_message = *(static_cast<tag_message_t*>(&received_message));
ESP_LOGD(TAG, "Received message, transmitting.");
if(!mqtt_client.publish("aoa", received_message.buffer, received_message.length));
ESP_LOGW(TAG, "Failed transmission.");
}
or any other sort of dereferencing you might wanna try.
There is also the possibility xQueueReceive is already doing that! So let's be sure of what is going on by adding this:
ESP_LOGD(TAG, "Received message, transmitting. %s", received_message.buffer);
Right after you get the message.
I don't think tag_message is being deleted inside the task, so if the struct is still valid and present, if you properly parse/cast its address, you should be able to acquire the message without any issues.
I have a write sensitive APB register which shall push into a FIFO with clock domain crossing. I though I would write:
val myFlow = Flow(...)
busCtrl.driveFlow(myFlow,address=4)
val myFifo = StreamFifoCC(...)
myFifo.io.push << myFlow
But the << operator requires a Stream, so a type error happens.
myFifo.io.push << myFlow.toStream
Should be fine, if the fifo overflow, the myFlow transaction will be lost
I am writing a distributed rendezvous implementation.
Requester - requests a tensor.
Responder - looks the tensor up and sends it to the requester.
If an error occurs on the responder side, I would like to send the error code to the requester which will propagate it to upper levels.
I saw that on GRPC the Status is converted to a ::grpc::status. Is that enough for Status serialization (i.e. can I simply mem-copy the ::grpc::status bytes inside my message body and send it, or is there another call required to flatten the data)? Thanks.
So, it seems clear that I can't mem-copy the ::grpc::status directly because it has the error_message and error_details fields of type ::grpc::string which is basically a typedef of std::string. So the data is not flat as far as I know, nor can I count on it.
I couldn't find a code example of how the serialization is done, so I did the following:
Create a Proto object with 3 fields: error_code, error_message, error_details.
When serializing, I would set those fields manually from the ::grpc::status and then call proto.SerializeToArray().
When deserializing, ParseProtoUnlimited(&proto) and then create a ::grpc::status from the proto fields.
Seems clean enough. Maybe just a little code duplication.
Proto:
message ErrorStatusProto {
int32 error_code = 1;
string error_message = 2;
string error_details = 3;
}
Serialize:
::grpc::Status gs = ToGrpcStatus(rm.status_);
ErrorStatusProto gsProto;
gsProto.set_error_code(gs.error_code());
gsProto.set_error_message(gs.error_message());
gsProto.set_error_details(gs.error_details());
gsProto.SerializeToArray(&message[kErrorStatusStartIndex],
gsProto.ByteSize());
if (gsProto.ByteSize() > kErrorStatusMaxSize) {
LOG(ERROR) << "Error status (" << gsProto.ByteSize() << " bytes) "
<< "is too big to fit in RDMA message ("
<< kErrorStatusMaxSize << " bytes). Truncated.";
}
Deserialize:
ErrorStatusProto gsProto;
CHECK(ParseProtoUnlimited(
&gsProto, &message[kErrorStatusStartIndex], kErrorStatusMaxSize))
<< "Failed to parse error status proto from message. Aborting.";
::grpc::Status gs((::grpc::StatusCode)gsProto.error_code(),
gsProto.error_message(), gsProto.error_details());
rm.status_ = FromGrpcStatus(gs);
HI all,
I am trying to modify the code provided by MS try to access the the Network Adapter Configuration
I am getting null pointer exception in it when i try to access the Mac Address or IPAddress property im using VC++ 2005. check for the // exception here: vtProp is returned as NULL line where am getting the exception.
#define _WIN32_DCOM
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
# pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "comsuppw.lib")
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_NetworkAdapterConfiguration"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for NIC(s) name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
//hr = pclsObj->Get(L"Caption", 0, &vtProp, 0, 0);
// wcout << " Caption : " << vtProp.bstrVal << endl;
// VariantClear(&vtProp);
// pclsObj->Release();
hr = pclsObj->Get(L"MACAddress", 0, &vtProp, 0, 0);
// exception here: vtProp is returned as NULL
wcout << " MACAddress : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
// pclsObj->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
what is wrong in the code??
Abdul khaliq
This is old but I had the same problem and I didn't see a solution anywhere. I solved it by putting a check for VT_NULL.
if( vtProp.vt != VT_NULL )
wcout << " MACAddress : " << vtProp.bstrVal << endl;
I don't understand why some of the results are VT_NULL but I suspect it could be avoided by adding a "where" clause to the "select" statement.
Thanks to finnw for the tip!
I'd start by initializing the vtProp variable -- it shouldn't matter, but sometimes COM servers make assumptions about out params;
VariantInit(&vtProp);
Then you can inspect vtProp after it's been returned and see what the actual type is (.vt member) -- maybe it's not a string, for some reason?
Could you post back with the type (you can cross-reference with the VARTYPE definition from oaidl.h to see what the friendly name(s) are)?
The list of network adapters usually contains a few "virtual" adapters, and they don't all have MAC addresses. Some (e.g. "Packet Scheduler Miniport') duplicate the MAC addresses of physical adapters. You just need to check the vt field (it may be VT_EMPTY) and remove duplicates from the resulting list.