#include #include #include #include "amqpbasicframe.h" // namespaces to use using namespace std; using namespace Copernica; /** * Our own socket handler */ class SocketHandler : public Network::TcpHandler { private: /** * Status of the connection, and substatuses * @var int */ int _status; int _connectionStatus; int _channelStatus; int _exchangeStatus; int _qosStatus; int _queueStatus; int _basicStatus; int _deleteStatus; int _restStatus; AMQP::AMQPBasic _basic; /** * Channel we're working on * @var int */ uint16_t _channel; std::string _exchangeName; std::string _queueName; public: /** * Constructor */ SocketHandler() : _status(0), _connectionStatus(0), _channelStatus(0), _qosStatus(0), _exchangeStatus(0), _queueStatus(0), _basicStatus(0), _deleteStatus(0), _restStatus(0), _basic(), _channel(0), _exchangeName("testexchange"), _queueName("testqueue") {} /** * Virtual destructor */ virtual ~SocketHandler() {} /** * Method that is called when the connection failed * @param socket Pointer to the socket */ virtual void onFailure(Network::TcpSocket *socket) { cout << "connection failure" << endl; } /** * Method that is called when the connection timed out (which also is a failure * @param socket Pointer to the socket */ virtual void onTimeout(Network::TcpSocket *socket) { cout << "connection timeout" << endl; } /** * Method that is called when the connection succeeded * @param socket Pointer to the socket */ virtual void onConnected(Network::TcpSocket *socket) { if(_status == 0){ // send protocol header frame AMQP::ProtocolHeaderFrame frame; socket->write(frame.buffer(), frame.size()); } } /** * Method that is called when the socket is closed (as a result of a TcpSocket::close() call) * @param socket Pointer to the socket */ virtual void onClosed(Network::TcpSocket *socket) { cout << "connection closed" << endl; } /** * Method that is called when the peer closed the connection * @param socket Pointer to the socket */ virtual void onLost(Network::TcpSocket *socket) { cout << "connection lost" << endl; } /** * Method that is called when data is received on the socket * @param socket Pointer to the socket * @param buffer Pointer to the filled input buffer */ virtual void onData(Network::TcpSocket *socket, Network::Buffer *buffer) { // try getting a frame auto frame = AMQP::Frame::decode(buffer->data(), buffer->length()); if(frame == nullptr) { std::cout << "error decoding received frame" << std::endl; return; } if(_status != 5) buffer->shrink(frame->totalSize()); if(_status == 0) { // the connection hasn't been set up, do this now. setupConnection(*socket, *buffer, frame); } if(_status == 1) { // time to setup the channel setupChannel(*socket, *buffer, frame); } if(_status == 2) { // time to do the QOS stuff setupQOS(*socket, *buffer, frame); } if(_status == 3) { // setup the exchange setupExchange(*socket, *buffer, frame); } if(_status == 4) { // setup the queue setupQueue(*socket, *buffer, frame); } if(_status == 5) { // publish testing etc testBasicFunctionalities(*socket, *buffer, frame); } if(_status == 6) { testRestStuff(*socket, *buffer, frame); } if(_status == 7) { // start deleting everything. deleteAMQP(*socket, *buffer, frame); } if(_status == 8) { socket->close(); } } void testRestStuff(Network::TcpSocket &socket, Network::Buffer &buffer, std::shared_ptr &frame) { if(_restStatus == 0) { std::cout << "rest testing"; std::string consumertag = ""; auto *sendframe = new AMQP::BasicCancelFrame(_channel, consumertag, false); socket.write(sendframe->buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; return; // wait for response } if(_restStatus == 1) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to BasicCancelOKFrame, should work"<buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; return; // wait for response } if(_restStatus == 3) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to BasicRecoverOKFrame, should work"<buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; // recover async does not wait for response. } if(_restStatus == 5) { declareQueue(socket, buffer); _restStatus++; return; //wait } if(_restStatus == 6) { waitDeclareQueueOK(buffer, frame); _restStatus = 20; } if(_restStatus == 20) { purgeQueue(socket, buffer); _restStatus++; return; } if(_restStatus == 21) { waitPurgeQueueOK(buffer, frame); _restStatus = 7; } if(_restStatus == 7) { auto *sendframe = new AMQP::TransactionSelectFrame(_channel); socket.write(sendframe->buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; return; // wait for response } if(_restStatus == 8) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to TransactionSelectOKFrame, should work"<buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; return; // wait for response } if(_restStatus == 10) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to TransactionCommitOKFrame, should work"<buffer(), sendframe->totalSize()); _restStatus++; delete sendframe; return; // wait for response } if(_restStatus == 12) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to TransactionRollbackOKFrame, should work"< &frame) { int lastDeliveryTag = 0; while(buffer.length() > 0) { if(_basicStatus != 20) { frame = AMQP::Frame::decode(buffer.data(), buffer.length()); buffer.shrink(frame->totalSize()); } auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to BasicDeliverFrame, should work"<deliveryTag(); frame = AMQP::Frame::decode(buffer.data(), buffer.length()); auto f2 = std::dynamic_pointer_cast(frame); if(f2 == nullptr){ std::cout<<"Error casting to BasicHeaderFrame, should work"<totalSize()); int bytesRead = f2->bodySize(); while(bytesRead > 0) { frame = AMQP::Frame::decode(buffer.data(), buffer.length()); auto f3 = std::dynamic_pointer_cast(frame); if(f3 == nullptr){ std::cout<<"Error casting to BodyFrame, should work"<totalSize()); auto payload = f3->payload(); bytesRead -= payload.size(); } } return lastDeliveryTag; } void testBasicFunctionalities(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { int lastDeliveryTag = 0; if(_basicStatus == 0) { // basic publish std::cout << "basic testing"; _basic.sendPublish(socket); _basicStatus++; } if(_basicStatus == 1) { // content header _basic.sendHeader(socket); _basicStatus++; } if(_basicStatus == 2) { // content body for(int i = 0 ; i < 10; i++) { _basic.sendBody(socket); } _basicStatus++; } if(_basicStatus == 3) { // basic consume frame _basic.sendConsume(socket); _basicStatus++; return; } if(_basicStatus == 4) { _basic.waitConsumeOK(buffer); _basicStatus++; } if(_basicStatus == 5) { // received consumeok frame, let's work on those basic deliver, content header, content body frames. _basic.waitDeliver(buffer); _basic.waitHeader(buffer); _basic.waitBody(buffer); _basicStatus++; } // done reading all incoming messages, ack them. if(_basicStatus == 6) { _basic.sendAck(socket); _basicStatus+=2; } if(_basicStatus == 8) { // send a basic get frame _basic.sendGet(socket); _basicStatus++; return; // wait for response } if(_basicStatus == 9) { // expect a basic-get-empty frame (at 5 & 6 we've cleared the queue) _basic.waitGetEmpty(buffer); _basicStatus ++; } if(_basicStatus == 10) { // send some more data to the queue, to test basicgetok for(int i = 0; i < 5; i++){ _basic.sendPublish(socket); _basic.sendHeader(socket); for(int i = 0; i < 10; i++) { _basic.sendBody(socket); } } _basicStatus++; } if(_basicStatus == 11) { // send a basic get frame _basic.sendGet(socket); _basicStatus++; return; // wait for response } if(_basicStatus == 12) { // expect a basic-get-empty frame (at 5 & 6 we've cleared the queue) _basic.waitGetOK(buffer); _basic.waitHeader(buffer); _basic.waitBody(buffer); _basicStatus++; } if(_basicStatus == 13) { // received consumeok frame, let's work on those basic deliver, content header, content body frames. while(buffer.length() > 0) { _basic.waitDeliver(buffer); _basic.waitHeader(buffer); _basic.waitBody(buffer); } _basicStatus++; } if(_basicStatus == 14) { // add some more messages to the queue _basic.sendPublish(socket); _basic.sendHeader(socket, 9); _basic.sendBody(socket); _basicStatus++; } if(_basicStatus == 15) { // channel flow frame auto *sendframe2 = new AMQP::ChannelFlowFrame(_channel, true); socket.write(sendframe2->buffer(), sendframe2->totalSize()); _basicStatus++; delete sendframe2; return; // wait for response } if(_basicStatus == 16) { // check if we've received a channelflowokframe auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to channelflowokframe, should work"<totalSize()); _basicStatus++; } if(_basicStatus == 17) { _status++; std::cout << " ... DONE" << std::endl; return; } } void purgeQueue(Network::TcpSocket& socket, Network::Buffer& buffer) { auto *sendframe = new AMQP::QueuePurgeFrame(_channel, _queueName); socket.write(sendframe->buffer(), sendframe->totalSize()); delete sendframe; } void waitPurgeQueueOK( Network::Buffer& buffer, std::shared_ptr &frame) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueuePurgeOKFrame, should work"<totalSize()); } void deleteAMQP(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { // queue deletion stuff // for purge testing, let's add a message to the queue (in case it is empty) if(_deleteStatus == 0) { // nothing deleted so far // queue purge auto *sendframe = new AMQP::QueuePurgeFrame(_channel, _queueName); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 1) { // nothing deleted so far // queue purge ok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueuePurgeOKFrame, should work"<totalSize()); _deleteStatus++; } if(_deleteStatus == 2) { // nothing deleted so far std::cout << "cleanup"; // unbind queue auto *sendframe = new AMQP::QueueUnbindFrame(_channel, _queueName, _exchangeName); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 3) { // nothing deleted so far // unbind queue ok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueueUnbindOKFrame, should work"<totalSize()); _deleteStatus++; } if(_deleteStatus == 4) { // nothing deleted so far // queue delete auto *sendframe = new AMQP::QueueDeleteFrame(_channel, _queueName); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 5) { // nothing deleted so far //// queue delete ok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueueDeleteOKFrame, should work"<totalSize()); _deleteStatus++; } //exchange deletion if(_deleteStatus == 6) { // send exchange delete auto *sendframe = new AMQP::ExchangeDeleteFrame(_channel, _exchangeName); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 7) { // expect exchangedeleteok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to ExchangeDeleteOKFrame, should work"<totalSize()); _deleteStatus++; } // channel close if(_deleteStatus == 8) { // send channel close std::string replyText = "200"; auto *sendframe = new AMQP::ChannelCloseFrame(_channel, 200, replyText); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 9) { // expect channelcloseok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to ChannelCloseOKFrame, should work"<totalSize()); _deleteStatus++; } // connection close if(_deleteStatus == 10) { // send exchange delete std::string replyText = "200"; auto *sendframe = new AMQP::ConnectionCloseFrame(0, 200, replyText); socket.write(sendframe->buffer(), sendframe->totalSize()); _deleteStatus++; delete sendframe; return; // wait for response } if(_deleteStatus == 11) { // expect exchangedeleteok auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to ConnectionCloseOKFrame, should work"<totalSize()); _deleteStatus++; _status++; std::cout << " ... DONE" << std::endl; } } void declareQueue(Network::TcpSocket& socket, Network::Buffer& buffer) { auto *sendframe = new AMQP::QueueDeclareFrame(_channel, _queueName, false, true, false, false, false); socket.write(sendframe->buffer(), sendframe->totalSize()); _queueStatus++; delete sendframe; } void waitDeclareQueueOK(Network::Buffer& buffer, std::shared_ptr &frame) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueueDeclareOKFrame, should work"<totalSize()); _queueStatus++; } void setupQueue(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { if(_queueStatus == 0) { // nothing has been done in the queue world std::cout << "set up queue " << _queueName; // send a queue declare frame declareQueue(socket, buffer); return; //wait for response } if(_queueStatus == 1) { waitDeclareQueueOK(buffer, frame); } if(_queueStatus == 2) { auto *sendframe = new AMQP::QueueBindFrame(_channel, _queueName, _exchangeName); socket.write(sendframe->buffer(), sendframe->totalSize()); _queueStatus++; delete sendframe; return; // wait for response } if(_queueStatus == 3) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to QueueBindOKFrame, should work"<totalSize()); _queueStatus++; _status++; std::cout << " ... DONE" << std::endl; } } void setupQOS(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { if(_qosStatus == 0) { // nothing has been done in the qos world std::cout << "set up qos"; // send the basic qos packet auto *sendframe = new AMQP::BasicQosFrame(_channel, 0, 3, false); socket.write(sendframe->buffer(), sendframe->totalSize()); _qosStatus++; delete sendframe; return; // we wait for a response } if(_qosStatus == 1) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to basicqosokframe, should work"<totalSize()); _status++; std::cout << " ... DONE" << std::endl; } } void setupChannel(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { if(_channelStatus == 0) { // nothing has been done in the channel world. std::cout << "set up channel"; // we send the channel open frame _channel = 1; auto *sendframe = new AMQP::ChannelOpenFrame(_channel); socket.write(sendframe->buffer(), sendframe->totalSize()); _channelStatus++; delete sendframe; return; // we wait for the response } if(_channelStatus == 1) { // check if we've received a channel open ok response auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to channelopenokframe, should work"<totalSize()); _channelStatus++; // received a response, send a new frame } if(_channelStatus == 2) { // channel flow frame auto *sendframe2 = new AMQP::ChannelFlowFrame(_channel, true); socket.write(sendframe2->buffer(), sendframe2->totalSize()); _channelStatus++; delete sendframe2; return; // wait for response } if(_channelStatus == 3) { // check if we've received a channelflowokframe auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to channelflowokframe, should work"<totalSize()); _status++; _channelStatus++; std::cout << " ... DONE" << std::endl; return; } } void setupExchange(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { if(_exchangeStatus == 0) { // nothing has been done in the exchange world. std::cout << "set up exchange"; // create an exchange declare frame const AMQP::Table *t = new AMQP::Table(); std::string type = "direct"; auto *sendframe = new AMQP::ExchangeDeclareFrame(_channel, _exchangeName, type, false, true, false, *t); socket.write(sendframe->buffer(), sendframe->totalSize()); _exchangeStatus++; delete t; delete sendframe; return; // await response } if(_exchangeStatus == 1) { // expect an exchangedeclareokframe auto f = std::dynamic_pointer_cast(frame); if(f == nullptr){ std::cout<<"Error casting to exchangedeclareokframe, should work"<totalSize()); _status++; _exchangeStatus++; std::cout << " ... DONE" << std::endl; return; } } void setupConnection(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr &frame) { // received connectionStart frame, send connectionStartOK frame if(_connectionStatus == 0) { std::cout << "set up connection"; auto f = std::dynamic_pointer_cast(frame); if(f == nullptr) { std::cout << "error casting to connectionstartframe, should work??" << std::endl; return; } buffer.shrink(frame->totalSize()); AMQP::Table *properties = new AMQP::Table(); std::string mechanism = "PLAIN"; std::string *response = new std::string("\0micha\0micha", 12); std::string locales = "en_US"; auto *sendframe = new AMQP::ConnectionStartOKFrame(_channel, *properties, mechanism, *response, locales); socket.write(sendframe->buffer(), sendframe->totalSize()); delete response; delete sendframe; delete properties; _connectionStatus++; return; // we wait for a response } // received connectionTuneFrame, probably if(_connectionStatus == 1) { auto f = std::dynamic_pointer_cast(frame); if(f == nullptr) { std::cout << "error casting to connectiontuneframe, should work??" << std::endl; return; } uint16_t channelMax = 10; uint32_t frameMax = 131072; uint16_t heartbeat = 0; auto *conopframe = new AMQP::ConnectionTuneOKFrame(_channel, channelMax, frameMax, heartbeat); socket.write(conopframe->buffer(), conopframe->totalSize()); _connectionStatus++; delete conopframe; // we respond to the server, now send a new frame } if(_connectionStatus == 2) { // after sending the tuneok frame, send the connection open frame std::string vhost = "/"; // rest of the fields are deprecated, the constructor handles that for us auto *conopframe = new AMQP::ConnectionOpenFrame(_channel, vhost); socket.write(conopframe->buffer(), conopframe->totalSize()); _connectionStatus++; delete conopframe; return; // we await a response } if(_connectionStatus == 3) { // we probably received the connection open ok frame buffer.shrink(frame->totalSize()); _status++; std::cout << " ... DONE" << std::endl; } } /** * Method that is called when the internal buffers are emptied and the socket * is in a writable state again. It is also called after a call to TcpSocket::wait() */ virtual void onWritable(Network::TcpSocket *socket) { cout << "socket writable" << endl; } }; /** * Main procedure * @param argc * @param argv * @return int */ int main(int argc, const char *argv[]) { // our own handler SocketHandler tcphandler; // create a socket Network::TcpSocket socket(Event::MainLoop::instance(), &tcphandler); // connect to the socket socket.connect(Network::Ipv4Address("127.0.0.1"), 5672); std::cout << "start main loop" << std::endl; // run the main event loop Event::MainLoop::instance()->run(); std::cout << "exited main loop" << std::endl; // done return 0; }