ANTLR4 C++ listener not calling overriden enterRule methods - antlr

I need some help with walking a tree with a listener (using C++). After initiating the tree walk with my listener and using gdb to attach to the process (I built the C++ runtime library with the Debug flag to be able to have the debug info in gdb), I can see it enters ParseTreeWalker::walk(), and if I execute getText() on the ParseTree* parameter I can see it has all the tokens from my input, so far so good. But when walk() calls enterRule():
void ParseTreeWalker::enterRule(ParseTreeListener *listener, ParseTree *r) const {
auto *ctx = downCast<ParserRuleContext*>(r);
listener->enterEveryRule(ctx);
ctx->enterRule(listener);
}
When I try to step in ctx->enterRule(listener) it just goes back to walk(). I've added breakpoints to my listener methods I want to debug but it appears they're not being called. I even added some std::cout statements in them but I don't see them being executed. I also added some std::cout statements to my overriden version of visitTerminal and those are getting printed...
If I inspect the ctx variable inside this method, it does seem to have the right type
_vptr.ParseTree = 0x6e6048 <vtable for MyParser::DocumentContext+16>...
So, I'm very confused, am I missing something obvious that's causing my enter* methods not get executed?
The generated BaseListener looks like this:
#include "antlr4-runtime.h"
#include "MyDCXParserListener.h"
class MyDCXParserBaseListener : public MyDCXParserListener {
public:
virtual void enterDocument(MyDCXParser::DocumentContext * /*ctx*/) override { }
virtual void exitDocument(MyDCXParser::DocumentContext * /*ctx*/) override { }
virtual void enterLine(MyDCXParser::LineContext * /*ctx*/) override { }
virtual void exitLine(MyDCXParser::LineContext * /*ctx*/) override { }
virtual void enterEveryRule(antlr4::ParserRuleContext * /*ctx*/) override { }
virtual void exitEveryRule(antlr4::ParserRuleContext * /*ctx*/) override { }
virtual void visitTerminal(antlr4::tree::TerminalNode * /*node*/) override { }
virtual void visitErrorNode(antlr4::tree::ErrorNode * /*node*/) override { }
};
The derived class I created looks like this:
.h
#include "antlr4-runtime.h"
#include "MyDCXParser.h"
#include "MyDCXParserBaseListener.h"
#include <iostream>
using namespace std;
class MyDCXListener : public MyDCXParserBaseListener
{
private:
public:
//
MyDCXListener();
//
~MyDCXListener();
// Don't allow copy constructor nor assignment operator
MyDCXListener(const MyDCXListener&) = delete;
MyDCXListener& operator=(const MyDCXListener&) = delete;
//
void enterDocument(MyDCXParser::DocumentContext * /*ctx*/) override;
void exitDocument(MyDCXParser::DocumentContext * /*ctx*/) override {}
void enterLine(MyDCXParser::LineContext * /*ctx*/) override;
void exitLine(MyDCXParser::LineContext * /*ctx*/) override {}
void visitTerminal(antlr4::tree::TerminalNode *node) override { std::cout << "visitTerminal(): '" << node->getText().c_str() << std::endl; }
};
.cpp
#include "MyDCXListener.h"
//
MyDCXListener::MyDCXListener()
{
}
MyDCXListener::~MyDCXListener()
{
}
void MyDCXListener::enterDocument(MyDCXParser::DocumentContext * ctx)
{
std::cout << "MyDCXListener::enterDocument()" << std::endl;
}
void MyDCXListener::enterLine(MyDCXParser::LineContext * ctx)
{
std::cout << "MyDCXListener::enterLine()" << std::endl;
}
I see the "visitTerminal" message but not the ones for enterDocument() nor enterLine()

Related

How to Serialize Custom Objects in Qt6

I have a custom class Dummy which I want to send as an object using Dynamic Replica in Qt6. I'm able to send the class but it's being transferred as QVariant which I'm not able to extract(or cast) from QVariabnt object.
Below is my implementation:
Dummy.h file
#ifndef CLIENT_DUMMY_H
#define CLIENT_DUMMY_H
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmap.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectsource.h>
#include <QtCore>
class Dummy {
Q_GADGET
Q_PROPERTY(QString m_name READ name WRITE setName)
public:
Dummy(){}
explicit Dummy(QString str) : m_name(str) {}
QString name() const {
return m_name;
}
void setName(QString str){
m_name = str;
}
~Dummy() = default;
private:
QString m_name;
};
Q_DECLARE_METATYPE(Dummy)
inline QDataStream &operator<<(QDataStream &ds, const Dummy &obj) {
QtRemoteObjects::copyStoredProperties(&obj, ds);
return ds;
}
inline QDataStream &operator>>(QDataStream &ds, Dummy &obj) {
QtRemoteObjects::copyStoredProperties(ds, &obj);
return ds;
}
inline bool operator==(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return left.name() == right.name();
}
inline bool operator!=(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return !(left == right);
}
inline QDebug operator<<(QDebug dbg, const Dummy &obj) {
dbg.nospace() << "Dummy(" << "m_name: " << obj.name() << ")";
return dbg.maybeSpace();
}
The class is present at both sides server as well as client.
.rep file
class Interface {
PROP(Dummy dummy);
[...removed extra code]
}
Server method sending data to client:
void send() {
Dummy dummy("DummyString");
setDummy(dummy);
}
Client side file:
Inside constructor:
QObject::connect(reptr.data(), SIGNAL(dummyChanged(Dummy)), this, SLOT(receiveDummy(Dummy)));
void DynamicClient::receiveDummy(Dummy dummy) {
if(reptr.data()->isReplicaValid()){
QVariant variant = reptr.data()->property("dummy");
qDebug() << variant;
}
}
But when object from server to client is sent, qDebug() prints below:
QVariant(Dummy, QVariant(QString, "DummyString"))
I'm not able to extract Dummy Object from Qvariant object.
I've tried registering my custom type using qRegisterMetaType() as well but still it didn't work. Apart from that, I've used qvariant_cast and variant.value() but I printed the value I get some random character each time.
Thanks in advance. I can post more code if required.
Turns out I was not registering the Dummy class on client side due to which client was not able to recognize the type.
qRegisterMetaType needs to be used at both ends.

Access struct directly of c++ from java code

I am new to javacpp i know java have not much experience in c++. This might be one of very simple question but i am struggling with this. How to access any variable type value written in header of c++ into java code using javacpp. Let us consider example:
C++ Code example:
There is function written in C++ which return the frame of video below is the code for it and expects an Struct argument to be passed.
unsigned char *
Videodecode::getframe_data (void *ptr)
{
GstSample *sample;
GstBuffer *buffer;
GstMapInfo map;
GstCaps *caps;
GstStructure *str;
gint width, height;
gstData *dataa = (gstData *) ptr;
sample = gst_app_sink_pull_sample ((GstAppSink*)dataa->sink);
if (sample != NULL) {
buffer = gst_sample_get_buffer (sample);
gst_buffer_map (buffer, &map, GST_MAP_READ);
if (map.data != NULL) {
caps = gst_sample_get_caps (sample);
if (caps != NULL);
str = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (str, "width", &width) ||
!gst_structure_get_int (str, "height", &height)) {
g_print ("No width/height available\n");
}
display_data = map.data;
//displayImg = Mat (Size (width, height ), CV_8UC3, map.data);
// cvtColor (displayImg, displayImg, COLOR_YUV2BGR_YUY2);
gst_buffer_unmap (buffer, &map);
gst_buffer_unref (buffer);
} else
gst_sample_unref (sample);
}
else {
//cout << "gstImageBuffer is NULL" << endl;
return NULL;
}
//return displayImg.data;
return display_data;
}
The structure which need to be passed as argument is below
typedef struct gstData_t
{
GstElement *pipeline;
GstElement *source;
GstElement *demux;
GstElement *parser;
GstElement *decoder;
GstElement *convert;
GstElement *capsfilter;
GstElement *sink;
GstElement *typefind;
} gstData;
Corresponding java code written to access it is below:
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.bytedeco.javacpp.FunctionPointer;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.annotation.Name;
import org.bytedeco.javacpp.annotation.NoOffset;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.Raw;
import org.bytedeco.javacpp.tools.Builder;
import org.bytedeco.javacpp.tools.ParserException;
#Platform(include = {"Videodecode.h",
},
includepath = {"/usr/include/gstreamer-1.0/","/usr/include/glib-2.0/","/usr/lib/x86_64-linux-gnu/glib-2.0/include/"},
//linkpath = {"/home/ign/git/JavaCppExample/src/main/resources/de/oltzen/javacppexample/"},
link = {"Videodecode"})
public class Videodecode {
NativeVideodecode nda;
static {
Class c = Videodecode.class;
Builder builder = null;
try {
builder = new Builder().classesOrPackages(c.getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoClassDefFoundError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
File[] outputFiles = builder.build();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Loader.load(c);
// Loader.load();
}
public Videodecode() {
nda = new NativeVideodecode();
}
public Videodecode(String filename) {
nda = new NativeVideodecode(filename);
}
public boolean filePathCpp(String str){
return nda.filePathCpp(str);
}
public boolean settingValCpp(String str){
return nda.settingValCpp(str);
}
public boolean process_event (int event) {
return nda.process_event(event);
}
public java.nio.ByteBuffer test1122 (String buffer) {
return nda.test1122(buffer);
}
public java.nio.ByteBuffer test112233 (String buffer) {
return nda.test1122(buffer);
}
public java.nio.ByteBuffer getframe_data(java.nio.ByteBuffer buffer){
return nda.getframe_data(buffer);
}
public Pointer gstData(){
return nda.gstData();
}
#Name("Videodecode")
public static class NativeVideodecode extends Pointer {
static {
Loader.load();
}
public NativeVideodecode() {
allocate();
}
public NativeVideodecode(String filename) {
System.out.println("filename "+filename);
allocate(filename);
}
public NativeVideodecode(Pointer p) {
super(p);
}
private native void allocate(String filename);
private native void allocate();
private native boolean filePathCpp(String str);
private native boolean settingValCpp(String str);
private native boolean process_event(int event);
private native java.nio.ByteBuffer test1122(String buffer);
private native java.nio.ByteBuffer test112233(String buffer);
// private native boolean test1122(byte[] buffer);
private native java.nio.ByteBuffer getframe_data (java.nio.ByteBuffer buffer);
#NoOffset private native Pointer gstData();
}
}
Problems being faced by me :
How to access Struct from C++ and pass it as an argument using java.
How to access frame data which is unsigned char*.
Approach which i tried to perform this.
To access Struct, i tried using offsetof but not sure how to use it in javacpp.
To access frame data i tried using java.nio.ByteBuffer but seems its not working properly.
While trying to compile code using mvn clean install below error is getting triggered.
[INFO] --- javacpp:1.3:build (javacpp.compiler) # projecustom ---
[INFO] Detected platform "linux-x86_64"
[INFO] Building for platform "linux-x86_64"
[WARNING] Could not load platform properties for class com.proje.decoder.connectorJavaCpp
[WARNING] Could not load platform properties for class com.proje.decoder.test1234
[INFO] Generating /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp
[INFO] Compiling /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/linux-x86_64/libjniVideodecode.so
[INFO] g++ -I/usr/include/gstreamer-1.0/ -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp -march=x86-64 -m64 -O3 -s -Wl,-rpath,$ORIGIN/ -Wl,-z,noexecstack -Wl,-Bsymbolic -Wall -fPIC -shared -o libjniVideodecode.so -lVideodecode
/home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp: In function ‘_jobject* Java_com_proje_decoder_Videodecode_00024NativeVideodecode_gstData(JNIEnv*, jobject)’:
/home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp:1532:21: error: ‘class Videodecode’ has no member named ‘gstData’
rptr = ptr->gstData();
edit:
let me try to take one simple example :
C++ Code:
#include <stdio.h>
struct test
{
int a;
std::string b;
};
class Foo {
public:
int n;
int m=70;
test tst;
// tst.a=10;
// tst.b="hi";
Foo(int n) : n(n) { }
virtual ~Foo() { }
virtual void bar() {
printf("Callback in C++ (n == %d)\n", n);
}
};
void callback(Foo *foo) {
foo->bar();
}
is it possible to write modify java code below to access a and b variables of struct
package com.ign.examples;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
#Platform(include="Foo.h")
public class VirtualFoo1 {
static { Loader.load(); }
public static class Foo extends Pointer {
static { Loader.load(); }
public Foo(int n) { allocate(n); }
private native void allocate(int n);
#NoOffset public native int n(); public native Foo n(int n);
#Virtual public native void bar();
public native int m(); public native void m(int m);
// public native #Cast("int") int a(); public native Foo a(int a);
public native Pointer tst(); public native void tst(Pointer tst);
}
public static native void callback(Foo foo);
public static void main(String[] args) {
Foo foo = new Foo(13);
System.out.println(foo.m());
}
}

How to override default signal handler of TextBuffer

I am trying to override the default on_erase signal handler of Gtk::TextView. I derive TextBuffer and override the default handler; but the override is not working. When using cast_static, the RefPtr is valid, but when using cast_dynamic the RefPtr is null.
#include <gtkmm.h>
#include "CTextBuffer.h"
class CMain : public Gtk::Window
{
public:
CMain();
virtual ~CMain();
private:
Gtk::TextView m_textView;
Glib::RefPtr<CTextBuffer> m_refTextBuffer;
};
#include "CMain.h"
CMain::CMain()
{
Glib::RefPtr<Gtk::TextBuffer> refTextBuffer = Gtk::TextBuffer::create();
m_refTextBuffer = Glib::RefPtr<CTextBuffer>::cast_dynamic(refTextBuffer);
m_textView.set_buffer(m_refTextBuffer);
add(m_textView);
show_all();
}
CMain::~CMain()
{}
#include <gtkmm.h>
class CTextBuffer : public Gtk::TextBuffer
{
public:
CTextBuffer();
virtual ~CTextBuffer();
protected:
virtual void on_erase(const TextBuffer::iterator& range_start, const TextBuffer::iterator& range_end);
};
#include "CTextBuffer.h"
CTextBuffer::CTextBuffer() {}
CTextBuffer::~CTextBuffer() {}
void CTextBuffer::on_erase (const TextBuffer::iterator& range_start, const TextBuffer::iterator& range_end)
{
Gtk::TextBuffer::on_erase(range_start, range_end);
}
Simply use a ref to your own type:
CMain::CMain()
{
Glib::RefPtr<CTextBuffer> refTextBuffer{ new CTextBuffer };
m_textView.set_buffer(refTextBuffer);
add(m_textView);
show_all();
}
void CTextBuffer::on_erase (const TextBuffer::iterator& range_start, const TextBuffer::iterator& range_end)
{
std::cout << "Own override was called" << std::endl;
Gtk::TextBuffer::on_erase(range_start, range_end);
}
You find some more information on how to usw own derived widgets here:
https://developer.gnome.org/gtkmm-tutorial/stable/sec-builder-using-derived-widgets.html.en

Qt5 QNetworkAccessManager finished signal never emits

I have a very confusing problem.
I had a simple project that was downloading files from some ftp servers. It worked very good.
Then, I tried implementing that same code into a larger project (first one was a Console App, and the second one is GUI, but I don't think that changes anything..).
After doing some debugging it seems to me that finished() signal from QNetworkAccessManager somehow never gets emitted (or received).
Again, the exact same lines of code work as a separate project.
downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QFile>
#include <QDebug>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
signals:
void dloadend();
void printed();
public slots:
void replyFinished (QNetworkReply *reply);
void doDownload(QUrl url);
void printDLend();
private:
QNetworkAccessManager *manager;
};
#endif // DOWNLOADER_H
downloader.cpp
#include "downloader.h"
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload(QUrl url)
{
qDebug()<<"entry: doDownload\n";
QNetworkRequest req(url);
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(printDLend()));//SLOT(replyFinished(QNetworkReply*)));
manager -> get(req);
qDebug()<<"exit: doDownload\n";
}
void Downloader::replyFinished (QNetworkReply *reply)
{
qDebug()<<"entry: reply\n";
if(reply->error()) {
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << "Download finished!";
QFile *file = new QFile("C:/users/jelicicm/Desktop/test1.hex");
if(file->open(QFile::Append))
{
file->write(reply->readAll());
file->flush(); file->close();
qDebug() <<"Downloaded file size:" <<file->size() <<"Bytes";
qDebug() <<"File name: "<< file->fileName();
;
}
delete file;
}
reply->deleteLater();
manager->deleteLater();
emit dloadend();
}
mainwindow.cpp (important part)
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader d;
QUrl url("ftp://ftp.xenbase.org/pub/Genomics/JGI/Xenla6.0/Xenla_6.0_JGI_Gene_Models.fasta.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d.doDownload(url);
QObject::connect(&d,SIGNAL(dloadend()),this, SLOT(printDLend()));
}
Can't get my head around this.
Any help is welcome,
Thanks!
EDIT> More info:
Debugger posts this>
url, debug
entry: doDownload
exit: doDownload
You create object Downloader on stack and it is deleted right after your function exits. You must create object using new, and provide MainWindow object as parent, so after you close MainWindow, the object will be destroyed.
If the download finish, you still need to destroy the object, so simply connect the dloadend() signal to deleteLater() slot, Qt loop will delete your object right after all signal are processed.
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader *d = new Downloader(this);
QUrl url("ftp://example.com/some.file.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d->doDownload(url);
QObject::connect(d,SIGNAL(dloadend()),this, SLOT(printDLend()));
QObject::connect(d,SIGNAL(dloadend()), d, SLOT(deleteLater()));
}

Gibberish coming from ASIO SSL Server code after the first message

I'm trying to write a SSL-based async server using Boost ASIO example code from here.
I get the first message and its response correctly at the client side. Then, I send a second message which is received fine at the server, however when the response is sent to client. It comes as some gibberish.
I have uploaded the server code to pastebin. Also, find it below:
// file - Server.h
class Server
{
public:
explicit Server(const std::string &address,
int port,
std::size_t threadPoolSize);
// run the io_service loop
void run();
// stop the server
void stop();
private:
//handle async accept operation
void handleAccept(const boost::system::error_code &e);
// number of threads in thread pool
std::size_t _threadPoolSize;
// the io_service
boost::asio::io_service _ioService;
// acceptor to listen for incoming connections
boost::asio::ip::tcp::acceptor _acceptor;
std::string get_password()
{
return "password";
}
// ssl context
boost::asio::ssl::context _context;
ConnectionPtr _connection;
};
//////////////////////////////////////////////////////////////////////////
// file - Server.cpp
//////////////////////////////////////////////////////////////////////////
Server::Server(const std::string& address,
int port,
std::size_t threadPoolSize)
: _threadPoolSize(threadPoolSize),
_acceptor(_ioService),
_context(_ioService, boost::asio::ssl::context::sslv23),
_connection()
{
try {
DEBUG_2("Starting server on port: ", port);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
_acceptor.open(endpoint.protocol());
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
_acceptor.bind(endpoint);
_acceptor.listen();
_context.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
_context.set_password_callback(boost::bind(&Server::get_password, this));
_context.use_certificate_chain_file("./demoCA/cacert.pem");
_context.use_private_key_file("./demoCA/private/cakey.pem",
boost::asio::ssl::context::pem);
// _context.use_tmp_dh_file("dh512.pem");
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
catch(std::exception& e)
{
STD_EXCEPTION_MESSAGE;
throw;
}
}
void Server::run()
{
// Create a pool of threads to run all of the io_services.
std::vector<boost::shared_ptr<boost::thread> > threads;
for (std::size_t i = 0; i < _threadPoolSize; ++i)
{
boost::shared_ptr<boost::thread>
thread(new boost::thread(
boost::bind(&boost::asio::io_service::run,
&_ioService)
)
);
threads.push_back(thread);
}
// Wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
threads[i]->join();
}
void Server::stop()
{
_ioService.stop();
}
void Server::handleAccept(const boost::system::error_code& e)
{
if (!e)
{
_connection->handshake();
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
}
////////////////////////////////////////////////////////////
// file - Connection.h
////////////////////////////////////////////////////////////
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
typedef boost::asio::ssl::stream< boost::asio::ip::tcp::socket >
ssl_socket;
class Connection
: public boost::enable_shared_from_this<Connection>
{
public:
explicit Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context);
//get socket from the connection
ssl_socket::lowest_layer_type& socket();
// do an SSL handshake
void handshake();
//get socket from the connection
boost::asio::io_service::strand& strand();
// start first async operation
void start();
void sendResponse(const Response& response);
void close();
// get remote IP address for this connection
std::string getIPAddress();
private:
void handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred);
void handleWrite(const boost::system::error_code& e);
boost::asio::io_service::strand _strand;
ssl_socket _socket;
void handleHandshake(const boost::system::error_code& e);
boost::array<char, 8192> _buffer;
};
typedef boost::shared_ptr<Connection> ConnectionPtr;
///////////////////////////////////////////////////////////////
// File - Connection.cpp
///////////////////////////////////////////////////////////////
Connection::Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context)
: _strand(io_service),
_socket(io_service, context)
{
}
ssl_socket::lowest_layer_type& Connection::socket()
{
return _socket.lowest_layer();
}
boost::asio::io_service::strand& Connection::strand()
{
return _strand;
}
void Connection::start()
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
void Connection::handshake()
{
std::cout << "doing ssl handshake" << std::endl;
_socket.async_handshake(boost::asio::ssl::stream_base::server,
_strand.wrap(
boost::bind(
&Connection::handleHandshake,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::handleHandshake(const boost::system::error_code& error)
{
if (!error)
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
else
{
std::cout << "error occured: " << error.message();
this->close();
}
}
void Connection::handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred)
{
if (!e) {
// handle read data
this->start();
}
else {
this->close();
}
}
void Connection::handleWrite(const boost::system::error_code& e)
{
if (!e) {
this->start();
}
else {
this->close();
}
}
void Connection::sendResponse(const Response& response)
{
boost::asio::async_write(_socket,
boost::asio::buffer(convertToString(response)),
_strand.wrap(
boost::bind(
&Connection::handleWrite,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::close()
{
boost::system::error_code ignoredCode;
socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignoredCode);
}
std::string Connection::getIPAddress()
{
return socket().remote_endpoint().address().to_string();
}
Can someone point me out as to what is being done wrongly here?
Update: The issue is resolved as noted by me in the comment. The issue was exactly similar to another old question on stackoverflow.
Your code doesn't recognize, that boost::asio::buffer is only the wrapper for objects from which it was constructed.
Here (in Connection::sendResponse):
boost::asio::buffer(convertToString(response))
You created buffer out of a (probably) temporary object, which was destroyed before it was used by boost::asio::async_write.
Boost.Asio documentation specifically tells you about that in the paragraph "Buffer invalidation"
For the boost::asio::buffer overloads that accept an argument of type
std::string, the buffer objects returned are invalidated according to
the rules defined for invalidation of references, pointers and
iterators referring to elements of the sequence (C++ Std, 21.3).