async_ read_until doesn't work as expected - string

So I am trying to write a program that reads and writes data through a tcp socket. I can successfully accept a connection, write data to it (though the write handler doesn't work as expected?). I also want to read data through the same socket - which doesnt seem to be working.
The class that handles all this is as follows:
using namespace boost::asio;
using namespace boost::asio::ip;
TcpServer::TcpServer(unsigned short port = 1700)
: ipPort(port){
tcp::acceptor acc(svc, tcp::endpoint(tcp::v4(), ipPort));
acc.listen();
acc.async_accept(socket, boost::bind(&TcpServer::Accept_Handler,this, placeholders::error));
SAY("Waiting for a New connection");
svc.run();
}
void TcpServer::Write_Handler(const boost::system::error_code& ec,
std::size_t bytes_transferred){
std::cout << ec.message() << std::endl;
if (!ec)
{
std::cout << "Just sent " << yawData << std::endl;
}
}
void TcpServer::Read_Handler(const boost::system::error_code& ec,
std::size_t bytes_transferred){
if (!ec)
{
std::string line;
std::istream is(&input_buffer_);
std::string test;
is >> test;
std::cout << "test" << test << std::endl;
std::getline(is, line);
if (!line.empty())
{
std::cout << "Recieved: " << line << std::endl;
}
}
else
std::cout << "Error reading:" << ec.message() << std::endl;
}
void TcpServer::Accept_Handler(const boost::system::error_code& ec){
if (!ec)
{
std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
connectMode = 1;
}
}
void TcpServer::Write_Data(){
if (connectMode){
SAY("Sent data");
std::ostringstream ss;
std::string sendBuffer;
ss << std::fixed << std::setprecision(2);
ss << yawData;
sendBuffer = ss.str() + "\r";
async_write(socket, buffer(sendBuffer), boost::bind(&TcpServer::Write_Handler, this,
placeholders::error,
placeholders::bytes_transferred));
}
}
void TcpServer::UpdateYaw(double data) {
yawData = data;
}
void TcpServer::Read_Data(){
if (connectMode){
async_read_until(socket, input_buffer_, "\n" , boost::bind(&TcpServer::Read_Handler, this,
placeholders::error,
placeholders::bytes_transferred));
}
}
TcpServer::~TcpServer(){
svc.stop();
}
The class header goes as:
class TcpServer {
private:
io_service svc;
tcp::socket socket{svc};
double yawData = 0;
unsigned short ipPort;
bool connectMode = 0;
streambuf input_buffer_;
void Write_Handler(const boost::system::error_code&,
std::size_t);
void Read_Handler(const boost::system::error_code&,
std::size_t);
void Accept_Handler(const boost::system::error_code&);
public:
TcpServer(unsigned short );
void Write_Data();
void Read_Data();
void UpdateYaw(double);
~TcpServer();
};
To use this, I call Write_Data(), followed by Read_Data(). Write_Data works, but the write handler isn't called - I can recieve data on the client side.
Read_Data() doesn't work at all. I know for sure that Data is being sent through the socket in teh format needed (ends with "\n")
Any ideas on what could possibly be wrong or, any debugging tips?
Thanks
EDIT
I plan to run the write_data and read_data functions from my main function as follows:
TcpServer *socketObj = new TcpServer(1700);
while ( i < 100 && trackObj->ReadTrackingState() != 0) {
SAY("Current Yaw - %.02f", trackObj->CurrentYaw());
socketObj->UpdateYaw(trackObj->CurrentYaw());
socketObj->Write_Data();
socketObj->Read_Data();
Platform::sleepMillis(1000);
i++;
}

void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
if (!ec) {
std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
connectMode = 1;
}
}
This function ends the async processing. It doesn't schedule any more async work and therefore io_service::run() ends, as documented.
You want to chain directly or use io_service::work to keep the service running. I suggest the chaining:
void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
if (!ec) {
std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
Write_Data();
}
}
But...
HOLD ON
You'll want to carefully review all the code.
void TcpServer::Write_Data() {
SAY("Sent data");
std::ostringstream ss;
std::string sendBuffer;
ss << std::fixed << std::setprecision(2);
ss << yawData;
sendBuffer = ss.str() + "\r";
async_write(socket, buffer(sendBuffer),
boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
}
What's going on here? First you create a temporary stream, fail to use it to append the carriage-return, and then pass the reference to a local string to async_write... That can't work. It's Undefined Behaviour.
A fix:
void TcpServer::Write_Data() {
SAY("Send data");
std::ostream ss(&output_buffer_);
ss << std::fixed << std::setprecision(2) << yawData << "\r";
async_write(socket, output_buffer_,
boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
}
DEMO
Live On Coliru
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <iomanip>
using namespace boost::asio;
using namespace boost::asio::ip;
template <typename T>
static inline void SAY(T&& v) { std::cout << std::forward<T>(v) << "\n"; }
class TcpServer {
private:
io_service svc;
tcp::socket socket{ svc };
double yawData = 0;
unsigned short ipPort;
streambuf input_buffer_, output_buffer_;
void Write_Handler(const boost::system::error_code &, std::size_t);
void Read_Handler(const boost::system::error_code &, std::size_t);
void Accept_Handler(const boost::system::error_code &);
public:
TcpServer(unsigned short = 1700);
void Write_Data();
void Read_Data();
void UpdateYaw(double);
~TcpServer();
};
TcpServer::TcpServer(unsigned short port) : ipPort(port) {
tcp::acceptor acc(svc, tcp::endpoint(tcp::v4(), ipPort));
acc.listen();
acc.async_accept(socket, boost::bind(&TcpServer::Accept_Handler, this, placeholders::error));
SAY("Waiting for a New connection");
svc.run();
}
void TcpServer::Write_Handler(const boost::system::error_code &ec, std::size_t /*bytes_transferred*/) {
std::cout << ec.message() << std::endl;
if (!ec) {
std::cout << "Just sent " << yawData << std::endl;
Read_Data();
}
}
void TcpServer::Read_Handler(const boost::system::error_code &ec, std::size_t /*bytes_transferred*/) {
if (!ec) {
std::cout << "Recieved: " << &input_buffer_ << std::endl;
} else
std::cout << "Error reading:" << ec.message() << std::endl;
}
void TcpServer::Accept_Handler(const boost::system::error_code &ec) {
if (!ec) {
std::cout << "Accepted a connection! - Now switching to write mode " << std::endl;
Write_Data();
}
}
void TcpServer::Write_Data() {
SAY("Send data");
std::ostream ss(&output_buffer_);
ss << std::fixed << std::setprecision(2) << yawData << "\r";
async_write(socket, output_buffer_,
boost::bind(&TcpServer::Write_Handler, this, placeholders::error, placeholders::bytes_transferred));
}
void TcpServer::UpdateYaw(double data) { yawData = data; }
void TcpServer::Read_Data() {
async_read_until(socket, input_buffer_, "\n", boost::bind(&TcpServer::Read_Handler, this, placeholders::error,
placeholders::bytes_transferred));
}
TcpServer::~TcpServer() { svc.stop(); }
int main() {
TcpServer server;
}

Related

How to use a specific DNS server/nameserver for name resolve queries in C++ boost::asio?

I would like to bypass system configured nameserver and use my own nameserver (or list of them) configured in application. I can do in nslookup in windows. How can I do it in C++ preferably by using boost::asio? I would like to avoid using std::system("nslookup ...> output.txt") and reading the file.
I cannot see where I can specify nameserver to use for lookup in boost::asio.
#include <boost/asio.hpp>
#include <string>
#include <iostream>
using namespace boost;
int main()
{
asio::io_service io_service;
asio::ip::tcp::resolver resolver(io_service);//how to pass specific nameserver?
asio::ip::tcp::resolver::iterator itr = resolver.resolve("bbc.co.uk","");
asio::ip::tcp::resolver::iterator end;
for (int i = 1; itr != end; itr++, i++)
std::cout << "hostname #" << i << ": " << itr->host_name() << " " << itr->endpoint() << '\n';
return 0;
}
You can't. The DNS resvoling is handled by the sockets api and you can't specify the DNS servers.
You will have to directly use either a OS specific API to resolve names like DnsQueryEx in win32 or using a library like LDNS.
/*
* DNSResolver.h
*
* Created on: Jan 12, 2023
* Author: marian
*/
#ifndef DNSRESOLVER_H_
#define DNSRESOLVER_H_
#include <cstdint>
#include <cstddef>
#include <vector>
#include <string_view>
#include <string>
#include <ostream>
#include <iostream>
#include <thread>
#include <chrono>
#include <boost/asio.hpp>
namespace tools
{
template <typename Func>
std::string_view find_first_success(const std::string_view& str,const Func& func, size_t pos0=0, char delim=',')
{
size_t pos=0;
do
{
pos=str.find_first_of(delim,pos0);
std::string_view sv=str.substr(pos0,pos-pos0);
if (func(sv))
return sv;
pos0=pos+1;
} while (pos!=std::string_view::npos);
return {};
}
template<int unused=0>
uint16_t be2uint16(const uint8_t* hi)
{
uint16_t hi1=*(hi+1);
return (((uint16_t)*hi)<<8)|hi1;
}
template<int unused=0>
uint32_t be2uint32(const uint8_t* hi)
{
uint32_t v3=*(hi+3);
uint32_t v2=*(hi+2);
uint32_t v1=*(hi+1);
uint32_t v0=*hi;
return (v0<<24)|(v1<<16)|(v2<<8)|v3;
}
template<int unused=0>
void out_IP4(std::ostream& os,uint32_t IP4)
{
os << (IP4>>24) << '.' << ((IP4>>16)&0xFF) << '.' << ((IP4>>8)&0xFF) << '.' << (IP4&0xFF);
}
}
namespace DNS
{
const char *rcode_msg[]={"No error","Format error","Server failure","Name error","Not implemented","Refused"};
const char *opcode_msg[]={"Standard query","Inverse query","Status"};
const char *type_msg[]={"0","A","NS","MD","MF","CNAME","SOA","MB","MG","MR","NULL","WKS","PTR","HINFO","MINFO","MX","TX"};
/*
A 1 a host address
NS 2 an authoritative name server
MD 3 a mail destination (Obsolete - use MX)
MF 4 a mail forwarder (Obsolete - use MX)
CNAME 5 the canonical name for an alias
SOA 6 marks the start of a zone of authority
MB 7 a mailbox domain name (EXPERIMENTAL)
MG 8 a mail group member (EXPERIMENTAL)
MR 9 a mail rename domain name (EXPERIMENTAL)
NULL 10 a null RR (EXPERIMENTAL)
WKS 11 a well known service description
PTR 12 a domain name pointer
HINFO 13 host information
MINFO 14 mailbox or mail list information
MX 15 mail exchange
TXT 16 text strings
*/
template<int unused=0>
void disp_type(std::ostream&os,uint16_t type)
{
os << (int)type;
if (type<=16)
os << " " << type_msg[type];
}
typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option; //somewhere in your headers to be used everywhere you need it
template<int unused=0>
class resolver
{
public:
resolver(const std::string_view& nameservers="127.0.0.53",boost::asio::chrono::milliseconds timeout=boost::asio::chrono::milliseconds{3000})
:nameservers_{nameservers},timeout_(timeout)
{}
std::vector<uint32_t> resolve(
const std::string_view& hostname,
std::string_view& nameserver_used,
std::vector<uint32_t>* pTTLs=nullptr)
{
std::vector<uint8_t> result;
result.resize(1024);
nameserver_used=resolve(hostname,result);
if (nameserver_used.empty())
return {};
std::string qname;
std::vector<uint32_t> IP4s;
int cnt=answer_A(result,qname,IP4s,pTTLs);
(void)cnt;
if (hostname!=qname)
return {};
return IP4s;
}
void resolve_ostream(
const std::string_view& hostname,
std::string_view& nameserver_used,
std::ostream& os)
{
std::vector<uint8_t> result;
result.resize(1024);
nameserver_used=resolve(hostname,result);
if (nameserver_used.empty())
return;
os << "nameserver:" << nameserver_used << std::endl;
disp_result(os,result);
}
private:
static void out_name(std::ostream&os,const std::vector<uint8_t>& result,uint16_t& pos)
{
uint8_t sz=result[pos++];
for (;sz;)
{
if (sz>=64)
{
if ((sz>>6)!=3)
throw "label size exceed 64 character and not pointer, see RFC 1035";
uint16_t offset=(((uint16_t)(sz&63))<<8)|result[pos++];
out_name(os,result,offset);//recursion, hope not too deep
return;
}
uint16_t epos=pos+sz;
while (pos<epos)
os << result[pos++];
sz=result[pos++];
if (sz)
os << ".";
}
}
static void disp_rr(std::ostream&os,const std::vector<uint8_t>& result,uint16_t& pos)
{
if (pos>=result.size())
return;
if (result[pos]==0)
return;
out_name(os,result,pos);
if (((size_t)pos+10)>=(size_t)result.size())
{
throw "wrong packet size1";
}
uint16_t rr_type=tools::be2uint16(&result[pos]);
os << " (" ;
os << "type:" ; disp_type(os,rr_type) ;
pos+=2;
os << " class:" << tools::be2uint16(&result[pos]) ;
pos+=2;
os << " TTL:" << tools::be2uint32(&result[pos]) << " secs) ";
pos+=4;
uint16_t len=tools::be2uint16(&result[pos]);
pos+=2;
if (pos+len>result.size())
throw "wrong packet size2";
if (rr_type==1)
{
if (len!=4)
{
throw "unknown data size";
}
os << (int)result[pos] << "." << (int)result[pos+1] << "." << (int)result[pos+2] << "." << (int)result[pos+3];
} else if (rr_type==2)
{
uint16_t pos2=pos;
out_name(os,result,pos2);
} else
{
throw "unimplement type";
}
pos+=len;
}
static void split_rr(const std::vector<uint8_t>& result,
uint16_t& pos,
std::string& name,
uint16_t& rr_type,
uint16_t& rr_class,
uint32_t& TTL,
uint32_t& IP4,
std::string* pname2=nullptr
)
{
if (pos>=result.size())
return;
if (result[pos]==0)
return;
std::stringstream ss;
out_name(ss,result,pos);
name=ss.str();
if (((size_t)pos+10)>=(size_t)result.size())
{
throw "wrong packet size1";
}
rr_type=tools::be2uint16(&result[pos]);
pos+=2;
rr_class=tools::be2uint16(&result[pos]) ;
pos+=2;
TTL=tools::be2uint32(&result[pos]);
pos+=4;
uint16_t len=tools::be2uint16(&result[pos]);
pos+=2;
if (pos+len>result.size())
throw "wrong packet size2";
if (rr_type==1)
{
if (len!=4)
{
throw "unknown data size";
}
IP4=tools::be2uint32(&result[pos]); //*(uint32_t*)&result[pos];
} else if (rr_type==2)
{
uint16_t pos2=pos;
std::stringstream ss;
out_name(ss,result,pos2);
if (pname2)
*pname2=ss.str();
} else
{
throw "unimplement type";
}
pos+=len;
}
static int check_A(const std::vector<uint8_t>& result)
{
if (result.size()<12)
return -1;
uint8_t response=(result[2]>>7);
if (response!=1)
return -2;
uint8_t rcode=result[3]&0xf;
if (rcode!=0)
return -3;
uint8_t opcode=(result[2]>>3)&0xF;
if (opcode!=0)
return -4;
return 0;
}
static int answer_A(const std::vector<uint8_t>& result,
std::string& q_name,
std::vector<uint32_t>& IP4s,
std::vector<uint32_t>* pTTLs=nullptr)
{
int ret=check_A(result);
if (ret<0)
return ret;
std::string name;
uint16_t q_type=0;
uint16_t q_class=0;
uint16_t rr_type=0;
uint16_t rr_class=0;
uint32_t TTL=0;
uint32_t IP4=0;
uint16_t qc=tools::be2uint16(&result[4]);
uint16_t pos=12;
for (int i=0;i<qc;i++)//qc =1 usually
{
std::stringstream ss;
out_name(ss,result,pos);
q_name=ss.str();
q_type=tools::be2uint16(&result[pos]);
pos+=2;
q_class=tools::be2uint16(&result[pos]);
pos+=2;
}
uint16_t ac=tools::be2uint16(&result[6]);
IP4s.resize(ac);
if (pTTLs)
pTTLs->resize(ac);
for (int i=0;i<ac;i++)
{
split_rr(result,pos,name,rr_type,rr_class,TTL,IP4);
if (name!=q_name)
break;
if (rr_type!=q_type)
break;
if (rr_class!=q_class)
break;
IP4s[i]=IP4;
if (pTTLs)
(*pTTLs)[i]=TTL;
}
return ac;
}
static void disp_result(std::ostream&os,const std::vector<uint8_t>& result)
{
if (result.size()<12)
return;
os << std::string((result[2]&0x80) ? "response" : "query") << std::endl;
os << "size=" << result.size() << " bytes" << std::endl;
uint8_t opcode=(result[2]>>3)&0xF;
os << "Opcode:" << (int)opcode;
if (opcode<=2)
os << " " << opcode_msg[opcode];
os << std::endl;
os << ((result[2]&1) ? "recursion asked" : "recursion NOT asked") << std::endl;
if (result[2]&2)
os << "response truncated" << std::endl;
if (result[2]&4)
os << "Authoritative answer" << std::endl;
os << ((result[3]&0x80) ? "recursion available" : "recursion NOT available") << std::endl;
uint8_t rcode=result[3]&0xf;
os << "rcode:" << (int)rcode;
if (rcode<=5)
os << " " << rcode_msg[rcode];
os << std::endl;
uint16_t qc=tools::be2uint16(&result[4]);
os << "Query Count:" << qc << std::endl;
uint16_t ac=tools::be2uint16(&result[6]);
os << "Answer Count:" << ac << std::endl;
uint16_t nc=tools::be2uint16(&result[8]);
os << "Authoritative Name Server Count:" << nc << std::endl;
uint16_t arc=tools::be2uint16(&result[10]);
os << "Additional resource records Count:" << arc << std::endl;
uint16_t pos=12;
os << "_____________" << std::endl;
os << "Query:" << std::endl;
for (int i=0;i<qc;i++)//qc =1 usually
{
out_name(os,result,pos);
os << " (";
os << "type:"; disp_type(os,tools::be2uint16(&result[pos]));
pos+=2;
os << " class:" << tools::be2uint16(&result[pos]) << " ) ";
pos+=2;
os << std::endl;
}
//answer
if (ac)
{
os << "_________________________" << std::endl;
os << "Answer:" << std::endl;
}
for (int i=0;i<ac;i++)
{
disp_rr(os,result,pos);
os << std::endl;
}
if (nc)
{
os << "_________________________" << std::endl;
os << "Authoritative nameservers:" << std::endl;
}
for (int i=0;i<nc;i++)
{
disp_rr(os,result,pos);
os << std::endl;
}
if (arc)
{
os << "_________________________" << std::endl;
os << "Additional resource records:" << std::endl;
}
for (int i=0;i<arc;i++)
{
disp_rr(os,result,pos);
os << std::endl;
}
}
size_t udp_request(const boost::asio::const_buffer& request,
const boost::asio::mutable_buffer& response,
const std::string_view& destination_ip,
const unsigned short port,
boost::system::error_code& ec)
{
using namespace boost;
asio::ip::udp::socket socket(io_context_);
auto remote = asio::ip::udp::endpoint(asio::ip::make_address(destination_ip), port);
socket.open(boost::asio::ip::udp::v4());
size_t sent=socket.send_to(request, remote);
if (request.size()!=sent)
return 0;
return receive_from(socket,response,timeout_,ec);
}
std::size_t receive_from(
boost::asio::ip::udp::socket& sock,
const boost::asio::mutable_buffer& buffer,
boost::asio::chrono::steady_clock::duration timeout,
boost::system::error_code& ec)
{
std::size_t length = 0;
sock.async_receive(boost::asio::buffer(buffer),
[&](const boost::system::error_code& ec1,std::size_t sz){
ec=ec1;
length=sz;
}
);
run(sock,timeout);
return length;
}
void run(boost::asio::ip::udp::socket& sock,boost::asio::chrono::steady_clock::duration timeout)
{
// Restart the io_context, as it may have been left in the "stopped" state
// by a previous operation.
io_context_.restart();
// Block until the asynchronous operation has completed, or timed out. If
// the pending asynchronous operation is a composed operation, the deadline
// applies to the entire operation, rather than individual operations on
// the socket.
io_context_.run_for(timeout);
// If the asynchronous operation completed successfully then the io_context
// would have been stopped due to running out of work. If it was not
// stopped, then the io_context::run_for call must have timed out.
if (!io_context_.stopped())
{
// Cancel the outstanding asynchronous operation.
sock.cancel();
// Run the io_context again until the operation completes.
io_context_.run();
}
}
static std::vector<uint8_t> make_dns_request(const std::string_view& hostname)
{
static uint16_t id=257;
id++;
std::vector<uint8_t> req;
uint16_t epos=12+1+hostname.size();
req.resize(epos+1+4);//plus null plus type (2 bytes) plus class (2 bytes)
*((uint16_t*)&req[0])=id;
req[2]=1;//recursive
req[3]=32;//??, linux has 32, but 0 works too
req[5]=1;//one query
req[epos]=0;//end of string
req[epos+2]=1;//type A - host address
req[epos+4]=1;//class INT
uint16_t cnt=0;
for(int i=hostname.size()-1;i>=0;i--)
{
req[13+i]=(hostname[i]=='.') ? cnt : hostname[i];
cnt=(hostname[i]=='.') ? 0 : cnt+1;
}
req[12]=cnt;
return req;
}
std::string_view resolve(const std::string_view& hostname,std::vector<uint8_t>& result)
{
auto myrequest=make_dns_request(hostname);
return tools::find_first_success(nameservers_,
[&](const std::string_view& nameserver)
{
size_t sz=0;
try
{
boost::system::error_code ec;
sz=udp_request(boost::asio::buffer(myrequest),
boost::asio::mutable_buffer(&result[0],result.size()),
nameserver,53,ec);
if (ec.value()!=boost::system::errc::success)
{
std::cerr << "skipping due to error code not a success : error code=" << ec.value() << " " << ec.message() << std::endl;
return false;
}
if (sz<35)//min packet , 12 header+3 name+4 type/class+ 16 (rr type 1)
{
std::cerr << "skipping because packet size < 35" << std::endl;
return false;
}
if ((myrequest[0]!=result[0])||(myrequest[1]!=result[1]))
{
std::cerr << "skipping because ID respond not matching ID request " << std::endl;
return false;
}
if (check_A(result)<0)
{
std::cerr << "skipping because packet check failed " << std::endl;
return false;
}
}
catch(std::exception& ex)
{
std::cerr << "Skipping because of exception:" << ex.what() << std::endl;
return false;
}
catch(...)
{
std::cerr << "Skipping because of unknown exception:" << std::endl;
return false;
}
result.resize(sz);
return true;
});
}
private:
boost::asio::io_context io_context_;
std::string nameservers_;
boost::asio::chrono::milliseconds timeout_;
};
}
#endif /* DNSRESOLVER_H_ */
/*
* main.cpp
*
* Created on: Jan 12, 2023
* Author: marian
*/
#include <iostream>
#include <vector>
#include "DNSResolver.h"
#define check_offset if (offset==argc) { print_error(); return 1;}
int main (int argc, char **argv) {
auto print_error=[&]()
{
std::cerr << "Usage: " << argv[0] << " [-v] [-t timeout_msecs] [--nottl] [--nons] <query> [csv_ip_nameserver_list] \n";
std::cerr << "Example: " << argv[0] << " bbc.co.uk 127.0.0.53,8.8.8.8" << std::endl;
std::cerr << "Example: " << argv[0] << " -v bbc.co.uk" << std::endl;
};
if (argc < 2) {
print_error();
return 1;
}
int offset=1;
bool verbose= (std::string(argv[offset])=="-v");
if (verbose)
offset++;
check_offset;
int millisecs=3000;
if (std::string(argv[offset])=="-t")
{
offset++;
check_offset;
millisecs=std::stoi(argv[offset++]);
}
check_offset;
bool ttl=true;
if (std::string(argv[offset])=="--nottl")
{
ttl=false;
offset++;
}
check_offset;
bool ns=true;
if (std::string(argv[offset])=="--nons")
{
ns=false;
offset++;
}
check_offset;
const char *dname=argv[offset];
const char *nameservers= (offset+1<argc) ? argv[offset+1] : "127.0.0.53,8.8.8.8";
if (ns)
std::cout << "nameservers:" << nameservers << std::endl;
DNS::resolver resolver{nameservers,boost::asio::chrono::milliseconds{millisecs}};
if (verbose)
{
std::string_view nameserver_used;
resolver.resolve_ostream(dname,nameserver_used,std::cout);
return 0;
}
std::vector<uint32_t> TTLs;
std::string_view nameserver_used;
std::vector<uint32_t> IP4s=resolver.resolve(dname,nameserver_used,&TTLs);
if (ns&&(!nameserver_used.empty()))
std::cout << "nameserver:" << nameserver_used << std::endl;
int n=IP4s.size();
if (!n)
{
std::cerr << "Error: No IPs found" << std::endl;
return 2;
}
for (int i=0;i<n;i++)
{
tools::out_IP4(std::cout,IP4s[i]);
if (ttl)
std::cout << " (TTL:" << TTLs[i] << " sec)" ;
std::cout << std::endl;
}
return 0;
}

ZeroMQ : a thread stops exactly after 2 hours in a while(1)-loop. Why & how to resolve this?

It does not crash so there is no core to analyse. It simply stops.
I have experimented multiple times. It stops exactly after 2 hours.
OS : qnx6.5.0
LIBs : ZeroMQ and Protobuf
I just have a single thread, it looks something like this :
dummyFrontEnd::dummyFrontEnd():context(1),socket(context,ZMQ_PUB) {
}
void dummyFrontEnd::Init()
{
socket.connect("tcp://127.0.0.1:5555");
cout << "Connecting .... " << endl;
}
void dummyFrontEnd::SendCANalyserTable(const std::string& filename)
{
...
zmq::message_t create_values( protoTable.ByteSizeLong()
+ sizeof(uint16_t)
);
*((uint16_t*)create_values.data()) = TABLEMSG_ID; // ID
protoTable.SerializeToArray( create_values.data()
+ sizeof(uint16_t),
protoTable.ByteSizeLong()
);
try {
socket.send(create_values,ZMQ_NOBLOCK);
}
catch (int e){
std::cout << "SPD exception e : "
<< e
<< std::endl;
}
protoTable.clear_columnvalues();
usleep(1);
}
}
void main(){
...
...
while(1) {
if (arguments.canalyser_filename != "") {
dmyFntEnd.SendCANalyserTable(arguments.canalyser_filename);
if (arguments.verbose) {
cout << "DummyFrontEnd"
<< "completed sending CANalyser table"
<< endl;
}
}
}
...
...
}

std::thread context of execution (c++14)

The problem appear when an in/out variable of a function called by std::thread changes the value during the execution...
Function:
static int func(stThread_t *&pStThread)
Parameters
pStThread: It´s a struct that has a pointer to std::thread and other variables (some flags)
typedef struct stThread {
stThread() noexcept {...};
stThread(const stThread &cRigth) noexcept {...};
stThread & operator = (const stThread &cRigth) noexcept {...};
std::thread *pThread;
volatile bool bBegin;
volatile bool bEnd;
} stThread_t;
The function func print the address of the std::thread of the parameter
pStThread and the thread id
func before 1785280 this_id 21968
after making an this_thread::sleep for 2 seconds, it print it again
func afer ... this_id 21968
static int func(stThread_t *&pStThread) {
std::thread::id this_id = std::this_thread::get_id();
long long p_begin = (long long)pStThread;
std::cout << "func before " << std::to_string(p_begin) << " this_id " << this_id << "\n";
std::cout.flush();
pStThread->bBegin = true;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
this_id = std::this_thread::get_id();
long long p_end = (long long)pStThread;
std::cout << "func afer " << std::to_string(p_end) << " this_id " << this_id << "\n";
std::cout.flush();
pStThread->bEnd = true;
return 1;
};
The address of the pointer to std::thread it´s changed (corrutped, deleted..?)
The pStThread is pushing_back of a list of pointer struct stThread_t
std::list<stThread_t*> listOfThreads;
listOfThreads.push_back(pStThread);
I read about std::move, but does not work with pointers
At the end there is a thread "garbage collector" that it is trying to erase all the threads pending of execution.
Full code here
#include <string>
#include <list>
#include <vector>
#include <map>
#include <thread>
#include <mutex>
#include <atomic>
#include <iostream>
typedef struct stThread {
stThread() noexcept {
pThread = NULL;
bBegin = false;
bEnd = false;
};
stThread(const stThread &cRigth) noexcept {
this->pThread = cRigth.pThread;
this->bBegin = (bool)cRigth.bBegin;
this->bEnd = (bool)cRigth.bEnd;
};
stThread & operator = (const stThread &cRigth) noexcept {
this->pThread = cRigth.pThread;
this->bBegin = (bool)cRigth.bBegin;
this->bEnd = (bool)cRigth.bEnd;
return *this;
};
std::thread *pThread;
volatile bool bBegin;
volatile bool bEnd;
} stThread_t;
class CMain
{
public:
typedef std::list<stThread_t*> MyList_threads;
MyList_threads listOfThreads;
public:
CMain() {
std::cout << std::boolalpha << "Ex1 is move-constructible? "
<< std::is_move_constructible<stThread_t>::value << '\n'
<< "Ex1 is trivially move-constructible? "
<< std::is_trivially_move_constructible<stThread_t>::value << '\n'
<< "Ex1 is nothrow move-constructible? "
<< std::is_nothrow_move_constructible<stThread_t>::value << '\n'
<< "Ex2 is trivially move-constructible? "
<< std::is_trivially_move_constructible<stThread_t>::value << '\n'
<< "Ex2 is nothrow move-constructible? "
<< std::is_nothrow_move_constructible<stThread_t>::value << '\n';
};
static int func(stThread_t *&pStThread) {
std::thread::id this_id = std::this_thread::get_id();
long long p_begin = (long long)pStThread;
std::cout << "func before " << std::to_string(p_begin) << " this_id " << this_id << "\n";
std::cout.flush();
pStThread->bBegin = true;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
this_id = std::this_thread::get_id();
long long p_end = (long long)pStThread;
std::cout << "func afer " << std::to_string(p_end) << " this_id " << this_id << "\n";
std::cout.flush();
pStThread->bEnd = true;
return 1;
};
int _createThreads() {
for (int iIdx = 0; (iIdx < 5); iIdx++) {
stThread_t *pStThread = new stThread_t;
pStThread->pThread = new std::thread(&CMain::func,
std::ref(pStThread));
if (pStThread) {
do {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} while (!pStThread->bBegin);
listOfThreads.push_back(pStThread);
std::string sLog;
sLog = "\nlistOfThreads.push_back " + std::to_string((long long)pStThread) + "\n";
std::cout << sLog;
std::cout.flush();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return 1;
};
int _main() {
_createThreads();
std::thread thread_collector([=]() {
bool bEnd = false;
MyList_threads::iterator it;
it = listOfThreads.end();
do {
stThread_t *pStThread = NULL;
if (it == listOfThreads.end()) {
it = listOfThreads.begin();
if (it == listOfThreads.end()) bEnd = true;
}
else it++;
if (it != listOfThreads.end()) {
if ((*it)->bEnd) {
pStThread = *it;
listOfThreads.erase(it);
it = listOfThreads.begin();
}
}
if (pStThread) {
if (pStThread->pThread) {
if (pStThread->pThread->joinable()) {
pStThread->pThread->join();
std::cout << " element deleted " << std::to_string((long long)pStThread) << "\n";
std::cout.flush();
}
delete pStThread->pThread;
pStThread->pThread = NULL;
}
delete pStThread;
}
pStThread = NULL;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} while (!bEnd);
});
if (thread_collector.joinable()) {
thread_collector.join();
}
return 1;
};
};
int main()
{
CMain _main;
_main._main();
return 0;
}
You have a rather straightforward bug, that is mostly unrelated to threading:
(1) func takes a reference to an stThread_t*.
static int func(stThread_t *&pStThread);
(2) You pass in a reference to pStThread
std::thread(&CMain::func,std::ref(pStThread));
(3) Which is a local variable whose lifetime ends as soon as the loop iteration is finished
for (int iIdx = 0; (iIdx < 5); iIdx++) {
stThread_t *pStThread = new stThread_t;
//...
}
(4) And consequently, you get undefined behavior when your function tries to access the object after it is destroyed. (be careful! here, "the object" refers to the pointer in question, not the object the pointer is pointing to)
It's unclear why you insist on passing pStThread by reference; your function doesn't actually modify the pointer (just what's pointed to), and you don't seem to intend to do any of the things that such a device is actually good for.

Copy constructor is being called instead of the move constructor

I'm trying to use the new C++11 move semantics, but the copy constructor gets called every time... Does anyone know what am I doing wrong? I'm using VS2012. Thanks in advance!
MemoryBlock::MemoryBlock(MemoryBlock& other)
: m_capacity(other.m_used), m_used(other.m_used), m_pointer(nullptr) {
std::wcout << L"Copy constructor called" << std::endl;
// ...
}
MemoryBlock& MemoryBlock::operator=(MemoryBlock& other) {
std::wcout << L"Copy assignment called" << std::endl;
if (this != &other) {
// ...
}
return *this;
}
MemoryBlock::MemoryBlock(MemoryBlock&& other)
: m_capacity(other.m_capacity), m_used(other.m_used), m_pointer(other.m_pointer) {
std::wcout << L"Move constructor called" << std::endl;
// ...
}
MemoryBlock& MemoryBlock::operator=(MemoryBlock&& other) {
std::wcout << L"Move assignment called" << std::endl;
if (this != &other) {
// ...
}
return *this;
}
MemoryBlock CreateRequest(const wchar_t *action) {
MemoryBlock request;
// ...
return request;
}
int __cdecl wmain(int argc, wchar_t *argv[]) {
// ...
MemoryBlock request = CreateRequest(argv[1]);
// ...
}

Runnable implementation using packaged_task in c++11

I am trying to create a Runnable interface in c++11 using packaged_task, with child class overriding run() function. I don't know why this code is not compiling. Its giving error related to type argument.
/usr/include/c++/4.8.1/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of()>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
Below is my code snippet. Could someone plz give me some information on this error and whether implementing Runnable this way is a right way to proceed ?
class Runnable {
public:
explicit Runnable() {
task_ = std::packaged_task<int()>(&Runnable::run);
result_ = task_.get_future();
std::cout << "starting task" << std::endl;
}
virtual int run() = 0;
int getResult() {
task_();
return result_.get();
}
virtual ~Runnable() {
std::cout << "~Runnable()" << std::endl;
}
private:
std::future<int> result_;
std::packaged_task<int()> task_;
};
class foo : public Runnable {
int fib(int n) {
if (n < 3) return 1;
else return fib(n-1) + fib(n-2);
}
public:
explicit foo(int n) : n_(n) {}
int run() {
cout << "in foo run() " << endl;
int res = fib(n_);
cout << "done foo run(), res = " << res << endl;
return res;
}
~foo() {}
private:
int n_;
};
int main(int argc, char*argv[]) {
stringstream oss;
oss << argv[1];
int n;
oss >> n;
shared_ptr<foo> obj(new foo(n));
obj->run();
cout << "done main" << endl;
return 0;
}

Resources