mbroadst / qamqp

AMQP 0.9.1 implementation for Qt
Other
151 stars 128 forks source link

Connection suddenly closes with segfault #16

Closed qmor closed 9 years ago

qmor commented 9 years ago

Sometimes during data sending amqp connection closes with error: segfault at c4 ip 00007f6942cb3c9d sp 00007fff0094db18 error 6 in libqamqp.so.0.3.0[7f6942ca0000+3c000]

any advices?

mbroadst commented 9 years ago

@qmor can you build with debug symbols enabled and try to get a proper backtrace? I'll need more to work with to help solve your problem (at very least a description of what you were doing when the segfault occurred, and maybe the output when setting the environment variable QAMQP_DEBUG=1).

qmor commented 9 years ago

Connection:

CLOSE code: 501 text: FRAME_ERROR - type 0, all octets = <<>>: {invalid_frame_end_marker,0} class-id: 0 method-id: 0 exchange "" disconnected AMQP Disconnected exchange "" disconnected socket error: "The remote host closed the connection"

mbroadst commented 9 years ago

@qmor I'm still going to need at least an explanation of what you're trying to do, unless what you're telling me is that you connect a QAmqpClient to a server and leave it alone for a while and this just happens?

qmor commented 9 years ago

I'm just trying to send data:

if (defaultExchange) { defaultExchange->publish(QString(in_Info.data),queue_to_write); Info() << QString(in_Info.data) << " " <<queue_to_write <<msg_show; }

qmor commented 9 years ago

connecting to host: "192.168.3.87" , port: 5672 Starting new process 'gui' Final time: 0, Step: 0 Starting new process 'thread' Final time: 0, Step: 0 Creating main window... Connection:

Start version_major: 0 version_minor: 9 mechanisms: ("AMQPLAIN", "PLAIN") locales: en_US Connection: Tune channel_max: 0 frame_max: 131072 heartbeat: 580 Connection: OpenOK Open channel #1 Open channel #2 Open channel #3 Open channel #4 Channel#1: OpenOK Channel#2: OpenOK Channel#3: OpenOK Channel#4: OpenOK declared queue: "DP1" message count 4 Consumer count: 0 declared queue: "py_control" message count 0 Consumer count: 1 purged queue: "DP1" consume ok: "DP1" consumer tag = amq.ctag-v9GAPD9p2pQzMuHLHSH9rA void QAmqpQueuePrivate::deliver(const QAmqpMethodFrame&) Connection: CLOSE code: 501 text: FRAME_ERROR - type 2, all octets = <<>>: {frame_too_large,33555456,131064} class-id: 0 method-id: 0 exchange "" disconnected AMQP Disconnected exchange "" disconnected socket error: "The remote host closed the connection"

qmor commented 9 years ago

If i just start app and have no activity everything looks okay

mbroadst commented 9 years ago

@qmor ah, it looks like you're sending a huge amount of data and its not breaking it apart to satisfy the max frame size. I'll do some testing in a second, but first I need to fix a heartbeat issue :smile:

qmor commented 9 years ago

Have checked it. For now i'm printing out data size if (defaultExchange) { defaultExchange->publish(QString(in_Info.data),queue_to_write); Info() << "data size" << in_Info.data.size() << msg_show; Info() << QString(in_Info.data) << " " <<queue_to_write <<msg_show; }

data size13 CPIACK ,1,OK py_control Connection:

CLOSE code: 501 text: FRAME_ERROR - type 0, all octets = <<>>: {invalid_frame_end_marker,0} class-id: 0 method-id: 0 exchange "" disconnected AMQP Disconnected exchange "" disconnected socket error: "The remote host closed the connection"

mbroadst commented 9 years ago

@qmor this seems strange, the last log you posted indicates you were trying to send ~33MB:

text: FRAME_ERROR - type 2, all octets = <<>>: {frame_too_large,33555456,131064}

Can you maybe post a minimal code example that exhibits the behavior you're running into?

qmor commented 9 years ago

Thats all that i'm trying.

QString _res = QString(" %1 ,%2,%3").arg("CPIACK",QString::number(CpiCount),result); info.data = QByteArray(_res.toAscii().data()); _ptrAMQP.get()->Send(info);

void _QAMQP2CAMQP::Send(ICommunicationDeviceInfo& in_Info) ............. if (defaultExchange) { defaultExchange->publish(QString(in_Info.data),queue_to_write); Info() << "data size" << in_Info.data.size() << msg_show; Info() << QString(in_Info.data) << " " <<queue_to_write <<msg_show; }

Btw my app is using multithreading, maybe it could cause this problem?

mbroadst commented 9 years ago

@qmor yes multithreading could be a big problem if you aren't using one QAmqpClient per thread, it's not thread safe. What I mean by a minima working example is a smaller example of your code base that I can fully compile that shows the issue (setup QThreads, QObjects, main.cpp, run, etc), not just code snippits. It seems like you're experiencing a more complicated error, and it's hard for me to tell where it could be happening

qmor commented 9 years ago

Looks like i'm opening Connection in one thread, but sends data from another thread. Could it cause a problem?

mbroadst commented 9 years ago

@qmor yes that will be a problem unless you use QMetaObject::invokeMethod with a QueuedConnection, thus guaranteeing that you are calling the method from the originating thread. So you would do:

QMetaObject::invokeMethod(exchange, "publish", Qt::QueuedConnection, Q_ARG(QString, in_Info.data), Q_ARG(QString, queue_to_write));
qmor commented 9 years ago

new problem QMetaObject::invokeMethod: No such method QAmqpExchange::publish(const QString&,const QString&)

mbroadst commented 9 years ago

@qmor I don't believe it honors default values, so you'll have to use the whole signature:

  void publish(const QString &message, const QString &routingKey,
                 const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(),
                 int publishOptions = poNoOptions);
qmor commented 9 years ago

crazy Qt QMetaObject::invokeMethod: No such method QAmqpExchange::publish(const QString&,const QString&,const QAmqpMessage::PropertyHash &,int)

mbroadst commented 9 years ago

@qmor what version of Qt are you using? This definitely works for me, for instance I can modify the void tst_QAMQPExchange::confirmDontLoseMessages() test (tst_qamqpexchange:182) like this:

void tst_QAMQPExchange::testQueuedPublish()
{
    QAmqpExchange *defaultExchange = client->createExchange();
    defaultExchange->enableConfirms();
    QVERIFY(waitForSignal(defaultExchange, SIGNAL(confirmsEnabled())));

    QAmqpMessage::PropertyHash properties;
    properties[QAmqpMessage::DeliveryMode] = "2";   // make message persistent
    qRegisterMetaType<QAmqpMessage::PropertyHash>();
    for (int i = 0; i < 10000; ++i) {
        QMetaObject::invokeMethod(defaultExchange, "publish", Qt::QueuedConnection,
                                  Q_ARG(QString, "noop"), Q_ARG(QString, "confirms-test"),
                                  Q_ARG(QAmqpMessage::PropertyHash, properties));
    }

    QVERIFY(defaultExchange->waitForConfirms());
}
qmor commented 9 years ago

i'm using Qt 4.8.6 as i found method should be marked as Q_INVOKABLE https://stackoverflow.com/questions/24642370/qmetaobjectinvokemethod-no-such-method-when-using-inheritance

Could i prepare a micro patch for that?

thank you very much. For now app works stable

mbroadst commented 9 years ago

@qmor you don't need to mark it Q_INVOKABLE since its already a public Q_SLOT, I think maybe you have an out of date copy of qamqp downloaded/installed. I updated these methods to be slots somewhat recently: 3c2a039c0882ff4f8655ce6cc463a97798e31dd7

qmor commented 9 years ago

Oh my God. You're totally right. I'm using old version d45f5b0 updating now. Thanks again.

mbroadst commented 9 years ago

@qmor no problem, also if you update to master I just moved qRegisterMetaTypeQAmqpMessage::PropertyHash() to be run in QAmqpClientPrivate's ctor so that you won't have to register it yourself (if you're trying to publish with properties, that is)

mbroadst commented 9 years ago

@qmor does this resolve your issue?

qmor commented 9 years ago

Yes. Thank you very much. Perfect library.