Boost error codes human-readable description - c++

I'm catching errors in Boost Asio program like
if (!error)
{
//do stuff
}
else
{
std::cout << "Error : " << error << std::endl;
//handle error
}
But the error isn't human-readable (e.g. connecting to SSL server without certificate gives error asio.ssl:335544539). Is there any better way how to display error ?

If you are likely using boost::system::error_code you can call:
error.message()
to get a more human-friendly message.
Using operator<< translates into:
os << ec.category().name() << ':' << ec.value()
Here you can check a detailed overview of the available members in error_code.

Related

Alternatives to using what() for exception details in boost

I am using the following C++ code from the boost library :
try{
child c(commandString, (std_out & std_err) > pipe_stream);
} catch(process_error &pe){
cout<<pe.what()<<" second line"<<endl;
}
The commandString is a command like ls or any other command. But if a command that does not exist is typed as per the documentation it throws the process_error exception.
I am catching the exception here but not sure if there is a better way to print out the details of the exception or error than pe.what() above?
If you look at the boost reference about boost::process::process_error, you can read this:
struct process_error : public system_error {
};
It merely inherits std::system_error but can then be distinguished in the catch-block from other system errors.
emphasis mine
If you look then at the std::system_error reference, like all other standard exceptions, what() is the way to provide detailed information about the raised error so I would say yes, this is the proper way to print out the exception details.
But since boost::process::process_error does not override the what() function, it would return the same as a std::system_error would.
An alternative interface is using std::error_code.
There are pros and cons:
PRO: it enables you to get more detail about where an error condition arose. (This is a hypothetical difference because it's not specified whether what() may include info beyond an error condition)
CON: it might not get as much detail as in the exception message
CON: since some errors are exceptional, it's harder to express the possible error conditions in the interface: the error conditions get in the way in a way that exceptions do not
in your code you might have created this problem by handling exceptions: now how do decide what value(s) to return
NEUTRAL: you may still have to handle exceptions because exceptions can arise from any related code (e.g. during setup, doing allocations).
NEUTRAL: the code() member of boost::process::process_error is likely to be 100% identical to the error_code that you get
Demo
Contrast the implementations and output below:
Live On Coliru
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int using_exceptions(std::string const& commandString) {
try {
bp::pstream pipe_stream;
bp::child c(commandString, (bp::std_out & bp::std_err) > pipe_stream);
c.wait();
return c.exit_code();
} catch (std::exception const& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return -1; // WHAT TO RETURN
}
}
int using_error_code(std::string const& commandString) {
try {
bp::pstream pipe_stream;
std::error_code ec;
bp::child c(commandString, (bp::std_out & bp::std_err) > pipe_stream,
ec);
if (ec) {
std::cerr << "Cannot spawn child process: " << ec.message() << "\n";
return -1; // WHAT TO RETURN?
} else {
c.wait(ec);
std::cerr << "Error: " << ec.message() << "\n";
return c.exit_code();
}
} catch (std::exception const& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return -1; // WHAT TO RETURN
}
}
int main()
{
auto cmd = "/usr/bin/bogus";
std::cout << "Using error_code: " << using_error_code(cmd) << "\n";
std::cout << "Using exceptions: " << using_exceptions(cmd) << "\n";
}
Prints
Using error_code: Cannot spawn child process: No such file or directory
-1
Using exceptions: Exception: execve failed: No such file or directory
-1

Why does Boost-Beast give me a partial message exception

I´m trying to use the boost beast http library for an HTTP Client. It´s working without any issues when I´m using a simulated server, however when I try connecting to the real server, boost::beast::http::read throws an exception saying "partial message".
I´ve been working on this issue for a couple days now but I can´t figure out why. Until now I´ve been using a different http client library and the server communication has been working without any similar issues.
I´d be grateful for any kind of idea or hint as to why this is happening and why it doesn't seem to be an issue when using a different library.
boost::beast::http::read throws an exception saying "partial message".
This happens because the message being parsed wasn't complete. A typical reason for it is when the content-length header is wrong, or the sender abandons the connection prematurely. E.g.:
Live On Compiler Explorer
This is what http::[async_]read ends up doing under the hood, but without the network related stuff:
#include <iostream>
#include <iomanip>
#include <string_view>
#include <boost/beast/http.hpp>
int main() {
using namespace boost::beast::http;
using boost::asio::buffer;
for (std::string_view buf : {
"GET / HTTP/1.1\r\n", // incomplete headers
"GET / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\n\r\ntrailing data",
"GET / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 42\r\n\r\nshort",
})
{
//std::cout << std::quoted(test) << "\n";
std::cout << "---------------------" << "\n";
request_parser<string_body> parser;
boost::system::error_code ec;
size_t n = parser.put(buffer(buf), ec);
if (n && !ec && !parser.is_done()) {
buf.remove_prefix(n);
n = parser.put(buffer(buf), ec); // body
}
if (!ec)
parser.put_eof(ec);
buf.remove_prefix(n);
std::cout
<< (parser.is_header_done()?"headers ok":"incomplete headers")
<< " / " << (parser.is_done()?"done":"not done")
<< " / " << ec.message() << "\n";
if (parser.is_header_done() && !parser.is_done())
std::cout << parser.content_length_remaining().value_or(0) << " more content bytes expected\n";
if (!buf.empty())
std::cout << "Remaining buffer: " << std::quoted(buf) << "\n";
}
}
Prints
---------------------
incomplete headers / not done / need more
---------------------
headers ok / done / Success
Remaining buffer: "trailing data"
---------------------
headers ok / not done / partial message
37 more content bytes expected
If you're not passing error_code to your calls they will throw the exception system_error with the same code, which is exactly what you see.
Side Note
If another library doesn't have this "problem" there are two options:
the library is sloppy (i.e. bad)
you're using it wrong (maybe you're not checking for errors)

Invalid argument error while using umount() function

I am trying to unmount a usb-storage device through a c++ code as follows.
while(umount("/dev/sdc1/")!=0)
{
std::cout << "ERROR: " << strerror(errno) << std::endl;
std::this_thread::sleep_for (std::chrono::seconds(2));
}
But, I get an error saying: Invalid argument.
What am I doing wrong?
Thanks in advance!

Get Exception Type

I was wondering if there's a way to get an string representation of an errors type/name from std::exception. Let's say I catch std::exception &err, is there a way to say something like err.getName() or err.getType(). I have a project that can throw a wide variety of errors, but I want to get the exact type if it has not been caught by something else. I'll show what I generally mean.
For simplicity sake, let's say libraryA has several uniquely defined exception types (libraryA::Exception_# where # is replaced by a number to uniquely identify the error).
Here's some simple code for this:
try{
doSomeTaskThatMightThrowAnError();
}catch(libraryA::Exception_1 &err){
std::cout << "Error type 1: " << err.what() << std::endl;
}catch(libraryA::Exception_2 &err){
std::cout << "Error type 2: " << err.what() << std::endl;
}catch(libraryA::Exception_3 &err){
std::cout << "Error type 3: " << err.what() << std::endl;
}catch(std::exception &err){
std::cout << "Unknown error: " << err.what() << std::endl;
}
Is there some way within catch(std::exception &err)'s block that I can say std::cout << "Unknown error type: " << err.getType() << '\n' << "Error message: " << err.what() << std::endl;
I want to catch std::exception as a precaution in case nothing else catches the error, but I want to be able to identify the exact error type so I may update my code and include another catch statement for it. Is this possible?
You can always use typeid(e).name() (remember to include <typeinfo> header).
But very little is guaranteed about the name so produced.
With Visual C++ it's nice and readable, with g++ it's mangled so that you practically need to use some compiler-specific functionality to demangle it.

catching exception from boost::filesystem::is_directory

I am currently catching errors from boost::filesystem::is_directory and showing the error to the user by calling "what()" on the exception. This gives the reason for failure but the error is strange to the user. For example:
boost::filesystem::is_directory: Access is denied
How can I catch the boost error and figure out what the actual cause is, so I can show a nicer error message?
By "nicer error message" would you mean something like
#include <iostream>
#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path p("/proc/1/fd/1");
try {
boost::filesystem::is_directory(p);
} catch(const boost::filesystem::filesystem_error& e)
{
if(e.code() == boost::system::errc::permission_denied)
std::cout << "Search permission is denied for one of the directories "
<< "in the path prefix of " << p << "\n";
else
std::cout << "is_directory(" << p << ") failed with "
<< e.code().message() << '\n';
}
}