AWS C++ Route53 Unknown(100) errors - c++

I'm trying to query a hosted zone on AWS with the C++ SDK and its not giving me error messages I can use (UNKNOWN/100/No message). I have dumped the request as well and don't see anything obviously wrong with it.
Any help on where I might look for a problem?
// note: The zone_id has been pulled correctly earlier in the code
Aws::String zone_id = "(set previously)";
auto type = Model::RRType::A;
// List records
{
auto lrrs = Model::ListResourceRecordSetsRequest();
lrrs.SetHostedZoneId(zone_id);
lrrs.SetStartRecordType(type);
auto outcome = route53->ListResourceRecordSets(lrrs);
if (outcome.IsSuccess())
{
std::cout << "LRRS worked\n";
auto result = outcome.GetResult().GetResourceRecordSets();
for (auto &r : result)
{
std::cout << r.GetName() << ":"
<< r.GetTTL() << ":"
<< static_cast<char>(r.GetType()) << std::endl;
}
}
else
{
std::cerr << "LRRS failed: "
<< static_cast<int>(outcome.GetError().GetErrorType())
<< std::endl
<< outcome.GetError()
<< std::endl;
}
}
This is the error I end up with when I run it:
LRRS failed: 100
HTTP response code: 400
Resolved remote host IP address: 55.146.15.201
Request ID:
Exception name:
Error message: No response body.
3 response headers:
connection : close
content-length : 0
date : Sun, 30 May 2021 01:50:29 GMT
I have tried all sorts of combinations on how to construct the query but with no luck. Any help would be much appreciated!

Ok I figured it out.
The zone_id returned via AWS API (ListHostedZonesByName) has reply like this:
/hostedZoneId/HSFDGFHJFFSDSRTDDD
The problem is, all the API afterwards don't expect to see the prefix and only expect to see HSFDGFHJFFSDSRTDDD. The same problem happened a few other places (ChangeResourceRecordSets, GetChange) and there's nothing obvious in the documents to explain this!
Hope this helps anyone else stumbling on this.

Related

Azure IoT Edge C++ module not sending device to cloud telemetry

I have written an IoT Edge C++ module that is sending the event output using the following function call:
bool IoTEdgeClient::sendMessageAsync(std::string message)
{
bool retVal = false;
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) START");
LOGGER_DEBUG(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) message : " << message);
Poco::Mutex::ScopedLock lock(_accessMutex);
MESSAGE_INSTANCE *messageInstance = CreateMessageInstance(message);
IOTHUB_CLIENT_RESULT clientResult = IoTHubModuleClient_LL_SendEventToOutputAsync(_iotHubModuleClientHandle, messageInstance->messageHandle, "output1", SendConfirmationCallback, messageInstance);
if (clientResult != IOTHUB_CLIENT_OK)
{
LOGGER_ERROR(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) ERROR : " << message << " Message id: " << messageInstance->messageTrackingId);
retVal = false;
}
else
{
retVal = true;
}
LOGGER_TRACE(IOT_CONNECTION_LOG, className + "::sendMessageAsync(...) END");
return retVal;
}
The result of the function call IoTHubModuleClient_LL_SendEventToOutputAsync is always coming as IOTHUB_CLIENT_OK. My module name is MicroServer and the route configured is:
FROM /messages/modules/MicroServer/outputs/output1 INTO $upstream
I do not see the SendConfirmationCallback function being called. Also, I do not see any device to cloud message appearing in the IoT hub. Any ideas why this is happening and how to fix it?
It turned out that I need to call this function atleast a couple of times per second
IoTHubModuleClient_LL_DoWork(_iotHubModuleClientHandle);
which I was not doing. As a result the code was not working properly. Once I started doing it. The code just worked.

Is there a way to list more than 1000 buckets using aws sdk C++?

The AWS SDK page shows this example:
Aws::S3::S3Client s3_client;
Aws::S3::Model::ListBucketsOutcome outcome = s3_client.ListBuckets();
This, however, allows returning up to 1000 buckets ONLY!
In our organization we have more than 1k buckets.
boto3 or java interface using ECS allows me to do pagination.
I can find NOTHING, however, for C++ and I was already digging in the dark corners of the Internet.
Anyone has any idea how to do that pagination in C++ since ListBuckets() does not get any request as the argument?
NOTE: I am not looking for workarounds like executing a boto script or jni within my C++ to solve that list buckets issue. I am interested to find a proper way to use SDK, which I personally, for unknown reason to me does not exist
I was having the same problem and I came across a solution for java here (https://stackoverflow.com/a/15352712/1856251) There are a number of solution there but the one in the link showed me the direction I needed.
It seems that for listing objects there is the concept of a Marker. This marker refers to the key to start with when listing. When it is empty the first key in the bucket. If you set this to the last key returned from the previous call to ListObjects then the next call will start from there. To do that you can call the member function.
void Aws::S3::Model::ListObjectsRequest::SetMarker( Aws::String && value)
More info can be found:
https://sdk.amazonaws.com/cpp/api/0.14.3/class_aws_1_1_s3_1_1_model_1_1_list_objects_request.html#a72bef4f7da7f91661a7642da7dc3aa36
Here is the code.
void myListObjects(const Aws::String& bucketName,
const Aws::String& region)
{
Aws::Client::ClientConfiguration config;
if (!region.empty())
{
config.region = region;
}
Aws::S3::S3Client s3_client(config);
Aws::S3::Model::ListObjectsRequest request;
request.WithBucket(bucketName);
std::string prelastMarker, lastMarker;
std::cout << "Objects in bucket '" << bucketName << "': "
<< std::endl << std::endl;
do {
auto outcome = s3_client.ListObjects(request);
prelastMarker = lastMarker;
if (outcome.IsSuccess())
{
Aws::Vector<Aws::S3::Model::Object> keyList =
outcome.GetResult().GetContents();
for (Aws::S3::Model::Object& object : keyList)
{
std::cout << object.GetKey() << std::endl;
}
lastMarker = keyList[keyList.size() - 1].GetKey();//outcome.GetResult().GetNextMarker();
request.SetMarker(lastMarker.c_str());
outcome = s3_client.ListObjects(request);
}
} while (prelastMarker != lastMarker);
}

Running arbitrary SQL commands MySQL C++ (X DevAPI)?

I've connected my C++ project to MySQL and successfully created a session. I was able to create a Schema. My issue is that when I try to run simple arbitrary queries like USE testSchema SHOW tables; using the MySQL/C++ api, I run into SQL syntax errors. When I run the function directly in the MySQL shell, the query runs perfectly fine.
Here is the full code
const char* url = (argc > 1 ? argv[1] : "mysqlx://pct#127.0.0.1");
cout << "Creating session on " << url << " ..." << endl;
Session sess(url);
{
cout << "Connected!" << endl;
// Create the Schema "testSchema"; This code creates a schema without issue
cout << "Creating Schema..." << endl;
sess.dropSchema("testSchema");
Schema mySchema = sess.createSchema("testSchema");
cout << "Schema Created!" << endl;
// Create the Table "testTable"; This code runs like normal, but the schema doesn't show
cout << "Creating Table with..." << endl;
SqlStatement sqlcomm = sess.sql("USE testSchema SHOW tables;");
sqlcomm.execute();
}
Here is the console output:
Creating session on mysqlx://pct#127.0.0.1 ...
Connected!
Creating Schema...
Schema Created!
Creating Table with...
MYSQL ERROR: CDK Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1
The error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1 is a MySQL error that means I have a syntax error in the query, but when I take a closer look at a query, I see there is nothing wrong with it.
I've copied and pasted the code directly from the cpp file into the mysql shell and it runs perfectly. This tells me that something is up with the formatting of how I'm entering the query in the sql() function. But the documentation for the sql() function is really terse and.
Here is the reference to the sql() function: https://dev.mysql.com/doc/dev/connector-cpp/8.0/class_session.html#a2e625b5223acd2a3cbc5c02d653a1426
Can someone please give me some insight on where I'm going wrong? Also here here is the full cpp code for more context:https://pastebin.com/3kQY8THC
Windows 10
Visual Studio 2019
MySQL 8.0 with Connect/C++ X DevAPI
You can do it in two steps:
sess.sql("USE testSchema").execute();
SqlStatement sqlcomm = sess.sql("SHOW tables");
SqlResult res = sqlcomm.execute();
for(auto row : res)
{
std::cout << row.get(0).get<std::string>() << std::endl;
}
Also, you can use the Schema::getTables():
for(auto table : mySchema.getTables())
{
std::cout << table.getName() << std::endl;
}
Keep in mind that the Schema::getTables() doesn't show the Collections created by Schema::createCollection(). There is also a Schema::getCollections():
for(auto collection : mySchema.getCollections())
{
std::cout << collection.getName() << std::endl;
}

Why Isn't find_one working in MongoDB C++?

I have a MongoDB 3.0.7 database, created with the mongo shell. The following works fine:
% mongo test
> vs = db.myCollection.findOne({"somefield.subfield": "somevalue"})
but when I do this in C++:
mongocxx::instance inst{};
mongocxx::client conn{};
auto db = conn["test"];
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I get "Failed to find object". What am I missing here?
Update: 11/23/2015, 10:00
I've installed the latest cxx driver (0.3.0), and made the following changes:
mongocxx::instance inst{};
mongocxx::client *connPtr;
bsoncxx::stdx::string_view connectionString("mongodb://localhost");
connPtr = new mongocxx::client(mongocxx::uri(connectionString));
auto db = connPtr->database("test");;
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I'm back to exactly the same thing. Calling db.list_collections(document{}) retrieves no results.
The bsoncxx library has two document types, views and values. A document::value contains the actual document data, and a document::view is just a reference to some underlying value. Values must outlive the views that use them.
There's a bug in the new c++11 driver with how document::values are passed around. This code produces a document::value :
document{} << "someField" << "someValue" << finalize;
The collection.find_one() method takes a document::view, and document::values convert implicitly to document::views. Unfortunately, this means if you dynamically build a document in your call to find_one(), as above, you can shoot yourself in the foot:
collection.find_one(document{} << "someField" << "someValue" << finalize);
finalize makes a temporary document::value, then find_one converts that to a document::view. The temporary value is dropped on the floor, leaving your view value-less, like a dangling pointer.
A workaround is to make your value in a separate call, and keep it around:
document::value doc = document{} << "someField" << "someValue" << finalize;
collection.find_one(doc.view());
I suspect this is what's causing your queries to fail; if not, it's something to make your code resilient to nonetheless!
You can track this ticket for the real fix for this problem.

net-snmp is not changing auth and priv protocol correctly

I'm using the net-snmp library (version 5.7.1) in a c++ programm under Linux. I have a Web-Frontend where a user can choose a SNMP-Version and configure it. SNMPv1 and SNMPv2 are working just fine, but I got some issues with SNMPv3.
Here is a picture of the frontend: Screenshot of Webinterface (Sorry for not uploading it directly here, but I need at least 10 reputation to do this)
When I start the c++ backend and enter all needed SNMPv3 credentials correctly, everything is working fine and the device is reachable. If I change for example the Auth Protocol from MD5 to SHA, but leave the rest of the credentials the same, I would expect that the device is not reachable anymore. In real it stays reachable. After restarting the backend the device is (as expected) not reachable anymore with the same settings.
After discovering this issue, I ran some tests. For the test I used different users and different settings. They were run with three different devices of different vendors and I got every time the same result. So it can not be device realated issue. The results can be seen here: Test results
My conclusion after testing was, that net-snmp seems to cache the selected auth and priv protocol for one user name. This can be seen very good at Test 2. The first time I use an user name with a specific protocol I get the expected result. After changing the protocol
a different result is expected, but I get still the same result as before.
At the end some information how the SNMP-calls are made:
There is a class called SNMPWrapper, which handels the whole SNMP-communication
Inside the constructor I call init_snmp() to init net-snmp
From the outside I can call only get(), set() and walk(). Every time one of these methods is called, a new SNMP-Session is created (First I create a new Session with snmp_sess_init(), than I set up the things needed and finally I open the session with snmp_sess_open()
After I made the request and received my answer I close the session with snmp_sess_close()
Question: Do I have to do any other clean up before changing a protocol in order to get it work correctly?
Edit: I added some code, that shows the described behaviour
int main(int argc, char** argv) {
struct snmp_session session, session1, *ss, *ss1;
struct snmp_pdu *pdu, *pdu1;
struct snmp_pdu *response, *response1;
oid anOID[MAX_OID_LEN];
size_t anOID_len = MAX_OID_LEN;
struct variable_list *vars;
int status, status1;
init_snmp("snmpapp");
const char* user = "md5";
string authpw = "123123123";
string privpw = "";
string ipString = "192.168.15.32";
char ip[16];
memset(&ip, 0, sizeof (ip));
ipString.copy(ip, sizeof (ip) - 1, 0);
/*
* First request: AuthProto is MD5, no PrivProto is used. The snmp-get
* request is successful
*/
snmp_sess_init(&session); /* set up defaults */
session.peername = ip;
session.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session.securityName = strdup(user);
session.securityNameLen = strlen(session.securityName);
// set the authentication method to MD5
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityAuthKeyLen = USM_AUTH_KU_LEN;;
if (generate_Ku(session.securityAuthProto,
session.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session: " << session.securityAuthProto[9] << " / SecurityAuthKey - session: " << session.securityAuthKey << endl;
ss = snmp_open(&session); /* establish the session */
if (!ss) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss: " << ss->securityAuthProto[9] << " / SecurityAuthKey - ss: " << ss->securityAuthKey << endl;
//send message
pdu = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu, anOID, anOID_len);
status = snmp_synch_response(ss, pdu, &response);
/*
* Process the response.
*/
if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response)
snmp_free_pdu(response);
if (!snmp_close(ss))
cout << "Snmp closing failed" << endl;
/*
* Second request: Only the authProto is changed from MD5 to SHA1. I expect,
* that the snmp-get fails, but it still succeeds.
*/
snmp_sess_init(&session1);
session1.peername = ip;
session1.version = SNMP_VERSION_3;
/* set the SNMPv3 user name */
session1.securityName = strdup(user);
session1.securityNameLen = strlen(session1.securityName);
// set the authentication method to SHA1
session1.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session1.securityAuthProto = usmHMACSHA1AuthProtocol;
session1.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
session1.securityAuthKeyLen = USM_AUTH_KU_LEN;
if (generate_Ku(session1.securityAuthProto,
session1.securityAuthProtoLen,
(u_char *) authpw.c_str(), strlen(authpw.c_str()),
session1.securityAuthKey,
&session1.securityAuthKeyLen) != SNMPERR_SUCCESS) {
//if code reaches here, the creation of the security key was not successful
}
cout << "SecurityAuthProto - session1: " << session1.securityAuthProto[9] << " / SecurityAuthKey - session1: " << session1.securityAuthKey << endl;
ss1 = snmp_open(&session1); /* establish the session */
if (!ss1) {
cout << "Couldn't open session1 correctly";
exit(2);
}
cout << "SecurityAuthProto - ss1: " << ss1->securityAuthProto[9] << " / SecurityAuthKey - ss1: " << ss1->securityAuthKey << endl;
//send message
pdu1 = snmp_pdu_create(SNMP_MSG_GET);
read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
snmp_add_null_var(pdu1, anOID, anOID_len);
status1 = snmp_synch_response(ss1, pdu1, &response1);
/*
* Process the response.
*/
if (status1 == STAT_SUCCESS && response1->errstat == SNMP_ERR_NOERROR) {
cout << "SNMP-read success" << endl;
} else {
cout << "SNMP-read fail" << endl;
}
if (response1)
snmp_free_pdu(response1);
snmp_close(ss1);
return 0;
}
I found the solution by myself:
net-snmp caches for every EngineId (device) the users. If there is an existing user for an engineID and you try to open a new session with this user, net-snmp will use the cached one. So the solution was to clear the list with cached users.
With this code snippet I could resolve my problem:
usmUser* actUser = usm_get_userList();
while (actUser != NULL) {
usmUser* dummy = actUser;
usm_remove_user(actUser);
actUser = dummy->next;
}
I hope I can help somebody else with this.
You can also update password for an existing user:
for (usmUser* actUser = usm_get_userList(); actUser != NULL; actUser = actUser->next) {
if (strcmp(actUser->secName, user) == 0) {
//this method calls generate_Ku with previous security data but with specified password
usm_set_user_password(actUser, "userSetAuthPass", authpw.c_str());
break;
}
}