char *consume_message(amqp_connection_state_t connection_state_, const char *queue_name_, uint64_t *out_body_size_) { amqp_basic_consume_ok_t *result = amqp_basic_consume(connection_state_, fixed_channel_id, amqp_cstring_bytes(queue_name_), amqp_empty_bytes, /*no_local*/ 0, /*no_ack*/ 1, /*exclusive*/ 0, amqp_empty_table); assert(result != NULL); amqp_envelope_t envelope; struct timeval timeout = { 5, 0 }; amqp_rpc_reply_t rpc_reply = amqp_consume_message(connection_state_, &envelope, &timeout, 0); assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL); *out_body_size_ = envelope.message.body.len; char *body = malloc(*out_body_size_); if (*out_body_size_) { memcpy(body, envelope.message.body.bytes, *out_body_size_); } amqp_destroy_envelope(&envelope); return body; }
int RabbitInBoundConnectionPoint::ListenMessage(void** destBuffer) throw (ConnectException) { amqp_rpc_reply_t res; amqp_envelope_t envelope; amqp_maybe_release_buffers(_conn); struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; res = amqp_consume_message(_conn, &envelope, &timeout, 0); if (AMQP_RESPONSE_NORMAL == res.reply_type) { int messageLen = (int) envelope.message.body.len; void* message = malloc(messageLen); memcpy(message, envelope.message.body.bytes, messageLen); amqp_basic_ack(_conn, 1, envelope.delivery_tag, false); GetRabbitError("Ack Error"); amqp_destroy_envelope(&envelope); *destBuffer = message; return messageLen; } else { if(res.library_error != AMQP_STATUS_TIMEOUT) { LOG(ERROR) << "Error al leer de Rabbit: " << amqp_error_string2(res.library_error); throw ConnectException("Error al leer de Rabbit", true); } } return 0; }
RabbitMQMessage::~RabbitMQMessage() { if (!acked && valid) { GST_WARNING ("Rejecting message because it is not acked"); amqp_basic_reject (connection->conn, 1, envelope.delivery_tag, /* requeue */ true); } amqp_destroy_envelope (&envelope); }
static void* _receiveThread(void* param) { MsgReceiver_t *receiver = (MsgReceiver_t *)param; amqp_envelope_t envelope; amqp_rpc_reply_t reply; amqp_frame_t *frame; time_t curtime; assert(receiver != NULL); LOG4CXX_DEBUG(logger, "_receiveThread: event receiver thread started"); sendLeaseRequest(receiver); curtime = getCurrentTime(); while(receiver->thread_run) { amqp_maybe_release_buffers(receiver->conn_state); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if(getElapsedSecond(curtime, getCurrentTime()) > 60*5) { sendLeaseRequest(receiver); curtime = getCurrentTime(); } reply = amqp_consume_message(receiver->conn_state, &envelope, NULL, 0); if(reply.reply_type == AMQP_RESPONSE_NORMAL) { // call handler MsgClientCallback_t callback = receiver->callback; LOG4CXX_INFO(logger, "_receiveThread: received a message"); if(callback != NULL) { LOG4CXX_INFO(logger, "_receiveThread: received a message - calling a callback function"); callback((const char*)envelope.routing_key.bytes, envelope.routing_key.len, (const char*)envelope.message.body.bytes, envelope.message.body.len); } int ack_result = amqp_basic_ack(receiver->conn_state, receiver->channel, envelope.delivery_tag, false); if(ack_result != 0) { LOG4CXX_ERROR(logger, "_receiveThread: ack failed " << ack_result); } amqp_destroy_envelope(&envelope); } else { LOG4CXX_INFO(logger, "_receiveThread: an exception occurred"); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); } receiver->thread_run = false; }
void Channel::listen(Callable_envelope& callback){ amqp_connection_state_t conn = this->conn_ptr->_getconn_n(); //open channel //amqp_channel_open(conn, channel); //die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); //set consumer amqp_basic_consume(conn, this->channel_n, amqp_cstring_bytes(this->queue_name.c_str()), amqp_empty_bytes, 0, 1, 0, amqp_empty_table);//auto ack consumer die_on_amqp_error(amqp_get_rpc_reply(this->conn_ptr->_getconn_n()), "rabbitmq_listen Consuming"); { while (1) { amqp_rpc_reply_t res; amqp_envelope_t envelope; amqp_maybe_release_buffers(conn); res = amqp_consume_message(conn, &envelope, NULL, 0); if (AMQP_RESPONSE_NORMAL != res.reply_type) { //this solution is not really work when network changed. label_listen_reconnet: Log::log.warning("Channel::listen, AMQP response abnormal\n"); Log::log.warning("Channel::listen, reconnecting...\n"); //first close previous amqp_channel_close(this->conn_ptr->_getconn_n(), this->channel_n, AMQP_REPLY_SUCCESS); amqp_connection_close(this->conn_ptr->_getconn_n(), AMQP_REPLY_SUCCESS); amqp_destroy_connection(this->conn_ptr->_getconn_n()); //reconnect to rabbitMQ server! this->conn_ptr->reconnnect(); amqp_channel_open(this->conn_ptr->_getconn_n(), channel_n); if(amqp_get_rpc_reply(this->conn_ptr->_getconn_n()).reply_type !=AMQP_RESPONSE_NORMAL){ Log::log.warning("Channel::publish:Opening channel_n error\n"); sleep(2); goto label_listen_reconnet; }else{ continue; } } callback.callback(envelope); amqp_destroy_envelope(&envelope); } } die_on_amqp_error(amqp_channel_close(conn, this->channel_n, AMQP_REPLY_SUCCESS), "Closing channel"); }
void consume(int argc, char* argv[]) { if (argc < 4) { help(); } std::string queue = argv[2]; int msg_cnt = atoi(argv[3]); // 消费 amqp_basic_qos(conn, channel_id, 0, /* prefetch_size */ 1, /* prefetch_count */ 0 /* global */); amqp_basic_consume(conn, /* connection */ channel_id, /* channel */ amqp_cstring_bytes(queue.c_str()), /* queue */ amqp_cstring_bytes(int2str(channel_id).c_str()), /* consumer_tag */ 0, /* no_local */ 0, /* no_ack */ 1, /* exclusive */ amqp_empty_table /* argument */ ); int got = 0; while (got++ < msg_cnt) { amqp_envelope_t envelope; memset(&envelope, 0, sizeof(envelope)); amqp_maybe_release_buffers(conn); amqp_consume_message(conn, &envelope, NULL, 0); check_amqp_reply("amqp consume msg failed.", ""); std::string data((char*)envelope.message.body.bytes, envelope.message.body.len); int channel_id = envelope.channel; int delivery_tag = envelope.delivery_tag; std::cout << "channelid: " << channel_id << ", delivery_tag: " << delivery_tag << ", data[" << data << "]" << std::endl; amqp_basic_ack(conn, channel_id, delivery_tag, 0 /* multiple */); check_amqp_reply("amqp basic ack failed.", "amqp basic ack succ."); amqp_destroy_envelope(&envelope); // usleep(10000); } }
void MQChannel::ConsumeMessage(TByteArray &outMessage) { std::unique_lock<std::mutex> lock(mQueueLock); mQueueCondition.wait(lock, [this]() { return mDeliveryQueue.size() > 0; }); amqp_envelope_t *envelope = mDeliveryQueue.front(); TByteArray message(envelope->message.body.len); if (outMessage.size() > 0) { memcpy(&outMessage[0], envelope->message.body.bytes, envelope->message.body.len); } mDeliveryQueue.pop(); amqp_destroy_envelope(envelope); delete envelope; }
/* Object destructor, it's executed automatically */ static HB_GARBAGE_FUNC( hb_amq_envelope_Destructor ) { /* Retrieve object pointer holder */ amqp_envelope_t ** ptr = ( amqp_envelope_t ** ) Cargo; /* Check if pointer is not NULL to avoid multiple freeing */ if( *ptr ) { /* Destroy the object */ amqp_destroy_envelope( *ptr ); hb_xfree( *ptr ); /* set pointer to NULL to avoid multiple freeing */ *ptr = NULL; } }
void rpc_run(struct status *status) { int ret; DEBUG(2, ("[*] Running RPC command\n")); /* Init command control */ if (!control_init(status)) { return; } /* Enter control loop */ while (rpc_check_run_flag(status)) { amqp_rpc_reply_t result; amqp_envelope_t envelope; amqp_basic_properties_t response_header; amqp_bytes_t response_body; response_header._flags = 0; amqp_maybe_release_buffers(status->conn); result = amqp_consume_message(status->conn, &envelope, NULL, 0); if (result.reply_type != AMQP_RESPONSE_NORMAL) { if (AMQP_RESPONSE_LIBRARY_EXCEPTION == result.reply_type && AMQP_STATUS_UNEXPECTED_STATE == result.library_error) { amqp_frame_t frame; if (AMQP_STATUS_OK != amqp_simple_wait_frame(status->conn, &frame)) { DEBUG(0, ("[!] Error consuming message\n")); control_abort(status); break; } if (AMQP_FRAME_METHOD == frame.frame_type) { switch (frame.payload.method.id) { case AMQP_BASIC_ACK_METHOD: /* if we've turned publisher confirms on, and we've published a message * here is a message being confirmed */ break; case AMQP_BASIC_RETURN_METHOD: /* if a published message couldn't be routed and the mandatory flag was set * this is what would be returned. The message then needs to be read. */ { amqp_message_t message; result = amqp_read_message(status->conn, frame.channel, &message, 0); if (AMQP_RESPONSE_NORMAL != result.reply_type) { control_abort(status); return; } amqp_destroy_message(&message); } break; case AMQP_CHANNEL_CLOSE_METHOD: /* a channel.close method happens when a channel exception occurs, this * can happen by publishing to an exchange that doesn't exist for example * * In this case you would need to open another channel redeclare any queues * that were declared auto-delete, and restart any consumers that were attached * to the previous channel */ return; case AMQP_CONNECTION_CLOSE_METHOD: /* a connection.close method happens when a connection exception occurs, * this can happen by trying to use a channel that isn't open for example. * * In this case the whole connection must be restarted. */ return; default: DEBUG(0, ("[!] An unexpected method was received %d\n", frame.payload.method.id)); return; } continue; } continue; } DEBUG(0, ("[!] Error consuming message\n")); control_abort(status); break; } DEBUG(2, ("Delivery %u, exchange %.*s routingkey %.*s\n", (unsigned) envelope.delivery_tag, (int) envelope.exchange.len, (char *) envelope.exchange.bytes, (int) envelope.routing_key.len, (char *) envelope.routing_key.bytes)); if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { DEBUG(2, ("Content-type: %.*s\n", (int) envelope.message.properties.content_type.len, (char *) envelope.message.properties.content_type.bytes)); } if (envelope.message.properties._flags & AMQP_BASIC_REPLY_TO_FLAG) { response_header._flags |= AMQP_BASIC_REPLY_TO_FLAG; response_header.reply_to = amqp_bytes_malloc_dup(envelope.message.properties.reply_to); DEBUG(2, ("Reply-to: %.*s\n", (int) envelope.message.properties.reply_to.len, (char *) envelope.message.properties.reply_to.bytes)); } if (envelope.message.properties._flags & AMQP_BASIC_CORRELATION_ID_FLAG) { response_header._flags |= AMQP_BASIC_CORRELATION_ID_FLAG; response_header.correlation_id = amqp_bytes_malloc_dup(envelope.message.properties.correlation_id); DEBUG(2, ("Correlation-id: %.*s\n", (int) envelope.message.properties.correlation_id.len, (char *) envelope.message.properties.correlation_id.bytes)); } /* Handle the request */ response_body = control_handle(status, envelope.message.body); DEBUG(2, ("[*] Sending response '%s'\n", (char*)response_body.bytes)); /* Send the response */ response_header._flags |= AMQP_BASIC_CONTENT_TYPE_FLAG; response_header.content_type = amqp_cstring_bytes("text/plain"); response_header._flags |= AMQP_BASIC_DELIVERY_MODE_FLAG; response_header.delivery_mode = 1; ret = amqp_basic_publish(status->conn, 1, amqp_empty_bytes, amqp_bytes_malloc_dup(envelope.message.properties.reply_to), 0, /* Mandatory */ 0, /* Inmediate */ &response_header, response_body); if (ret != AMQP_STATUS_OK) { DEBUG(0, ("[!] Error publishing command response: %s\n", amqp_error_string2(ret))); } //* Free memory */ amqp_destroy_envelope(&envelope); } /* Clean up control */ control_free(status); }
int main(int argc, char const *const *argv) { char const *hostname; int port, status; char const *exchange; char const *bindingkey; amqp_socket_t *socket = NULL; amqp_connection_state_t conn; amqp_bytes_t queuename; if (argc < 5) { fprintf(stderr, "Usage: amqp_listen host port exchange bindingkey\n"); return 1; } hostname = argv[1]; port = atoi(argv[2]); exchange = argv[3]; bindingkey = argv[4]; conn = amqp_new_connection(); socket = amqp_tcp_socket_new(conn); if (!socket) { die("creating TCP socket"); } status = amqp_socket_open(socket, hostname, port); if (status) { die("opening TCP socket"); } die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest"), "Logging in"); amqp_channel_open(conn, 1); die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); { amqp_queue_declare_ok_t *r = amqp_queue_declare(conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Declaring queue"); queuename = amqp_bytes_malloc_dup(r->queue); if (queuename.bytes == NULL) { fprintf(stderr, "Out of memory while copying queue name"); return 1; } } amqp_queue_bind(conn, 1, queuename, amqp_cstring_bytes(exchange), amqp_cstring_bytes(bindingkey), amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue"); amqp_basic_consume(conn, 1, queuename, amqp_empty_bytes, 0, 1, 0, amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); { while (1) { amqp_rpc_reply_t res; amqp_envelope_t envelope; amqp_maybe_release_buffers(conn); res = amqp_consume_message(conn, &envelope, NULL, 0); if (AMQP_RESPONSE_NORMAL != res.reply_type) { break; } printf("Delivery %u, exchange %.*s routingkey %.*s\n", (unsigned) envelope.delivery_tag, (int) envelope.exchange.len, (char *) envelope.exchange.bytes, (int) envelope.routing_key.len, (char *) envelope.routing_key.bytes); if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) envelope.message.properties.content_type.len, (char *) envelope.message.properties.content_type.bytes); } amqp_destroy_envelope(&envelope); } } die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), "Closing channel"); die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS), "Closing connection"); die_on_error(amqp_destroy_connection(conn), "Ending connection"); return 0; }
static void run(amqp_connection_state_t conn) { uint64_t start_time = now_microseconds(); int received = 0; int previous_received = 0; uint64_t previous_report_time = start_time; uint64_t next_summary_time = start_time + SUMMARY_EVERY_US; amqp_frame_t frame; uint64_t now; while (1) { amqp_rpc_reply_t ret; amqp_envelope_t envelope; now = now_microseconds(); if (now > next_summary_time) { int countOverInterval = received - previous_received; double intervalRate = countOverInterval / ((now - previous_report_time) / 1000000.0); printf("%d ms: Received %d - %d since last report (%d Hz)\n", (int)(now - start_time) / 1000, received, countOverInterval, (int) intervalRate); previous_received = received; previous_report_time = now; next_summary_time += SUMMARY_EVERY_US; } amqp_maybe_release_buffers(conn); ret = amqp_consume_message(conn, &envelope, NULL, 0); if (AMQP_RESPONSE_NORMAL != ret.reply_type) { if (AMQP_RESPONSE_LIBRARY_EXCEPTION == ret.reply_type && AMQP_STATUS_UNEXPECTED_STATE == ret.library_error) { if (AMQP_STATUS_OK != amqp_simple_wait_frame(conn, &frame)) { return; } if (AMQP_FRAME_METHOD == frame.frame_type) { switch (frame.payload.method.id) { case AMQP_BASIC_ACK_METHOD: /* if we've turned publisher confirms on, and we've published a message * here is a message being confirmed */ break; case AMQP_BASIC_RETURN_METHOD: /* if a published message couldn't be routed and the mandatory flag was set * this is what would be returned. The message then needs to be read. */ { amqp_message_t message; ret = amqp_read_message(conn, frame.channel, &message, 0); if (AMQP_RESPONSE_NORMAL != ret.reply_type) { return; } amqp_destroy_message(&message); } break; case AMQP_CHANNEL_CLOSE_METHOD: /* a channel.close method happens when a channel exception occurs, this * can happen by publishing to an exchange that doesn't exist for example * * In this case you would need to open another channel redeclare any queues * that were declared auto-delete, and restart any consumers that were attached * to the previous channel */ return; case AMQP_CONNECTION_CLOSE_METHOD: /* a connection.close method happens when a connection exception occurs, * this can happen by trying to use a channel that isn't open for example. * * In this case the whole connection must be restarted. */ return; default: fprintf(stderr ,"An unexpected method was received %d\n", frame.payload.method.id); return; } } } } else { amqp_destroy_envelope(&envelope); } received++; } }
static int rabbitmq_consume_message_and_forward(zloop_t *loop, zmq_pollitem_t *item, void* arg) { rabbit_listener_state_t *state = (rabbit_listener_state_t*)arg; void *receiver = state->receiver; amqp_connection_state_t conn = state->conn; amqp_rpc_reply_t res; amqp_envelope_t envelope; amqp_maybe_release_buffers(conn); // printf("[D] consuming\n"); res = amqp_consume_message(conn, &envelope, NULL, 0); if (AMQP_RESPONSE_NORMAL != res.reply_type) { zsys_interrupted = 1; log_amqp_error(res, "consuming from RabbitMQ"); return -1; } // if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { // printf("[D] content-type: %.*s\n", // (int) envelope.message.properties.content_type.len, // (char *) envelope.message.properties.content_type.bytes); // } const char *meta_data = NULL; amqp_basic_properties_t *properties = &envelope.message.properties; amqp_table_t *headers = &properties->headers; int n = headers->num_entries; for (int i = 0; i < n; i++) { amqp_bytes_t *key = &headers->entries[i].key; if (key->len == 4 && memcmp(key->bytes, "info", 4) == 0) { amqp_field_value_t *value = &headers->entries[i].value; if (value->kind == 'S' && value->value.bytes.len == sizeof(msg_meta_t)) meta_data = value->value.bytes.bytes; } } // send messages to main thread zmsg_t *msg = zmsg_new(); // skip request-stream prefix, leaving only app-env if (envelope.exchange.len > 15 && !strncmp(envelope.exchange.bytes, "request-stream-", 15)) zmsg_addmem(msg, envelope.exchange.bytes+15, envelope.exchange.len-15); else zmsg_addmem(msg, envelope.exchange.bytes, envelope.exchange.len); zmsg_addmem(msg, envelope.routing_key.bytes, envelope.routing_key.len); zmsg_addmem(msg, envelope.message.body.bytes, envelope.message.body.len); if (meta_data) zmsg_addmem(msg, meta_data, sizeof(msg_meta_t)); // zmsg_dump(msg); if (zmq_output_socket_ready(receiver)) { zmsg_send(&msg, receiver); } else { if (!zsys_interrupted) fprintf(stderr, "[E] dropped message because receiver socket wasn't ready\n"); zmsg_destroy(&msg); } amqp_destroy_envelope(&envelope); return 0; }
unsigned int rmq_receive() { pwr_tStatus sts; int search_remtrans = 0; remtrans_item* remtrans; amqp_rpc_reply_t ret; amqp_envelope_t envelope; struct timeval t = { 2, 0 }; rabbit_header header; int msg_received = 0; amqp_maybe_release_buffers(ctx->conn); ret = amqp_consume_message(ctx->conn, &envelope, &t, 0); switch (ret.reply_type) { case AMQP_RESPONSE_NORMAL: { break; } case AMQP_RESPONSE_NONE: return REM__SUCCESS; case AMQP_RESPONSE_SERVER_EXCEPTION: return REM__EXCEPTION; case AMQP_RESPONSE_LIBRARY_EXCEPTION: switch (ret.library_error) { case AMQP_STATUS_TIMEOUT: { amqp_destroy_envelope(&envelope); return REM__TIMEOUT; } case AMQP_STATUS_UNEXPECTED_STATE: { amqp_frame_t frame; sts = amqp_simple_wait_frame_noblock(ctx->conn, &frame, &t); if (sts == AMQP_STATUS_TIMEOUT) { printf("Wait frame timeout\n"); return REM__EXCEPTION; } else if (sts == AMQP_STATUS_OK) { if (frame.frame_type == AMQP_FRAME_METHOD) { switch (frame.payload.method.id) { case AMQP_BASIC_ACK_METHOD: printf("Basic ack method called\n"); break; case AMQP_BASIC_RETURN_METHOD: printf("Basic return method called\n"); break; case AMQP_CHANNEL_CLOSE_METHOD: printf("Channel close method called\n"); break; case AMQP_CONNECTION_CLOSE_METHOD: printf("Connection close method called\n"); break; default:; } } return REM__EXCEPTION; } else return REM__EXCEPTION; } } // Reconnect... rmq_close(1); return REM__EXCEPTION; default: printf("Unknown Reply type: %d\n", ret.reply_type); } if (debug) printf("Received message %d\n", (int)envelope.message.body.len); if (envelope.message.body.len > 0 && rn_rmq->DisableHeader) { /* Header disabled, take the first receive remtrans object */ remtrans = rn.remtrans; search_remtrans = 1; while (remtrans && search_remtrans) { /* Match? */ if (remtrans->objp->Direction == REMTRANS_IN) { search_remtrans = false; sts = RemTrans_Receive(remtrans, (char*)envelope.message.body.bytes, envelope.message.body.len); msg_received = 1; } remtrans = (remtrans_item*)remtrans->next; } if (search_remtrans) { rn_rmq->ErrCount++; errh_Info("RabbitMQ Receive no remtrans %s", rn_rmq->ReceiveQueue); } } else if (envelope.message.body.len >= sizeof(rabbit_header)) { memcpy(&header, envelope.message.body.bytes, sizeof(rabbit_header)); /* Convert the header to host byte order */ header.msg_size = ntohs(header.msg_size); header.msg_id[0] = ntohs(header.msg_id[0]); header.msg_id[1] = ntohs(header.msg_id[1]); search_remtrans = 1; remtrans = rn.remtrans; while (remtrans && search_remtrans) { if (remtrans->objp->Address[0] == header.msg_id[0] && remtrans->objp->Address[1] == header.msg_id[1] && remtrans->objp->Direction == REMTRANS_IN) { search_remtrans = false; sts = RemTrans_Receive(remtrans, (char*)envelope.message.body.bytes + sizeof(rabbit_header), envelope.message.body.len); if (sts != STATUS_OK && sts != STATUS_BUFF) errh_Error("Error from RemTrans_Receive, queue %s, status %d", rn_rmq->ReceiveQueue, sts, 0); msg_received = 1; break; } remtrans = (remtrans_item*)remtrans->next; } if (search_remtrans) { rn_rmq->ErrCount++; errh_Info("No remtrans for received message, queue %s, class %d, type %d", rn_rmq->ReceiveQueue, header.msg_id[0], header.msg_id[1]); } } if (ctx->op->Acknowledge) { if (msg_received) amqp_basic_ack(ctx->conn, ctx->channel, envelope.delivery_tag, 0); else /* Requeue the message */ amqp_basic_nack(ctx->conn, ctx->channel, envelope.delivery_tag, 0, 1); } amqp_destroy_envelope(&envelope); return sts; }
void * SWITCH_THREAD_FUNC mod_amqp_command_thread(switch_thread_t *thread, void *data) { mod_amqp_command_profile_t *profile = (mod_amqp_command_profile_t *) data; while (profile->running) { amqp_queue_declare_ok_t *recv_queue; amqp_bytes_t queueName = { 0, NULL }; /* Ensure we have an AMQP connection */ if (!profile->conn_active) { switch_status_t status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Amqp no connection- reconnecting...\n"); status = mod_amqp_connection_open(profile->conn_root, &(profile->conn_active), profile->name, profile->custom_attr); if ( status != SWITCH_STATUS_SUCCESS ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to connect with code(%d), sleeping for %dms\n", profile->name, status, profile->reconnect_interval_ms); switch_sleep(profile->reconnect_interval_ms * 1000); continue; } /* Check if exchange already exists */ amqp_exchange_declare(profile->conn_active->state, 1, amqp_cstring_bytes(profile->exchange), amqp_cstring_bytes("topic"), 0, /* passive */ 1, /* durable */ amqp_empty_table); if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Checking for command exchange")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to create missing command exchange", profile->name); continue; } /* Ensure we have a queue */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Creating command queue"); recv_queue = amqp_queue_declare(profile->conn_active->state, // state 1, // channel profile->queue ? amqp_cstring_bytes(profile->queue) : amqp_empty_bytes, // queue name 0, 0, // passive, durable 0, 1, // exclusive, auto-delete amqp_empty_table); // args if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Declaring queue")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to connect with code(%d), sleeping for %dms\n", profile->name, status, profile->reconnect_interval_ms); switch_sleep(profile->reconnect_interval_ms * 1000); continue; } if (queueName.bytes) { amqp_bytes_free(queueName); } queueName = amqp_bytes_malloc_dup(recv_queue->queue); if (!queueName.bytes) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory while copying queue name"); break; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Created command queue %.*s", (int)queueName.len, (char *)queueName.bytes); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Binding command queue to exchange %s", profile->exchange); /* Bind the queue to the exchange */ amqp_queue_bind(profile->conn_active->state, // state 1, // channel queueName, // queue amqp_cstring_bytes(profile->exchange), // exchange amqp_cstring_bytes(profile->binding_key), // routing key amqp_empty_table); // args if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Binding queue")) { mod_amqp_connection_close(profile->conn_active); profile->conn_active = NULL; switch_sleep(profile->reconnect_interval_ms * 1000); continue; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Amqp reconnect successful- connected\n"); continue; } // Start a command amqp_basic_consume(profile->conn_active->state, // state 1, // channel queueName, // queue amqp_empty_bytes, // command tag 0, 1, 0, // no_local, no_ack, exclusive amqp_empty_table); // args if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Creating a command")) { mod_amqp_connection_close(profile->conn_active); profile->conn_active = NULL; switch_sleep(profile->reconnect_interval_ms * 1000); continue; } while (profile->running && profile->conn_active) { amqp_rpc_reply_t res; amqp_envelope_t envelope; struct timeval timeout = {0}; char command[1024]; enum ECommandFormat { COMMAND_FORMAT_UNKNOWN, COMMAND_FORMAT_PLAINTEXT } commandFormat = COMMAND_FORMAT_PLAINTEXT; char *fs_resp_exchange = NULL, *fs_resp_key = NULL; amqp_maybe_release_buffers(profile->conn_active->state); timeout.tv_usec = 500 * 1000; res = amqp_consume_message(profile->conn_active->state, &envelope, &timeout, 0); if (res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION) { if (res.library_error == AMQP_STATUS_UNEXPECTED_STATE) { /* Unexpected frame. Discard it then continue */ amqp_frame_t decoded_frame; amqp_simple_wait_frame(profile->conn_active->state, &decoded_frame); } if (res.library_error == AMQP_STATUS_SOCKET_ERROR) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A socket error occurred. Tearing down and reconnecting\n"); break; } if (res.library_error == AMQP_STATUS_CONNECTION_CLOSED) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMQP connection was closed. Tearing down and reconnecting\n"); break; } if (res.library_error == AMQP_STATUS_TCP_ERROR) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A TCP error occurred. Tearing down and reconnecting\n"); break; } if (res.library_error == AMQP_STATUS_TIMEOUT) { // nop } /* Try consuming again */ continue; } if (res.reply_type != AMQP_RESPONSE_NORMAL) { break; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Delivery:%u, exchange:%.*s routingkey:%.*s\n", (unsigned) envelope.delivery_tag, (int) envelope.exchange.len, (char *) envelope.exchange.bytes, (int) envelope.routing_key.len, (char *) envelope.routing_key.bytes); if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Content-type: %.*s\n", (int) envelope.message.properties.content_type.len, (char *) envelope.message.properties.content_type.bytes); if (strncasecmp("text/plain", envelope.message.properties.content_type.bytes, strlen("text/plain")) == 0) { commandFormat = COMMAND_FORMAT_PLAINTEXT; } else { commandFormat = COMMAND_FORMAT_UNKNOWN; } } if (envelope.message.properties.headers.num_entries) { int x = 0; for ( x = 0; x < envelope.message.properties.headers.num_entries; x++) { char *header_key = (char *)envelope.message.properties.headers.entries[x].key.bytes; char *header_value = (char *)envelope.message.properties.headers.entries[x].value.value.bytes.bytes; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AMQP message custom header key[%s] value[%s]\n", header_key, header_value); if ( !strncmp(header_key, "x-fs-api-resp-exchange", 22)) { fs_resp_exchange = header_value; } else if (!strncmp(header_key, "x-fs-api-resp-key", 17)) { fs_resp_key = header_value; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring unrecognized event header [%s]\n", header_key); } } } if (commandFormat == COMMAND_FORMAT_PLAINTEXT) { switch_stream_handle_t stream = { 0 }; /* Collects the command output */ /* Convert amqp bytes to c-string */ snprintf(command, sizeof(command), "%.*s", (int) envelope.message.body.len, (char *) envelope.message.body.bytes); /* Execute the command */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Executing: %s\n", command); SWITCH_STANDARD_STREAM(stream); if ( fs_resp_exchange && fs_resp_key ) { switch_status_t status = switch_console_execute(command, 0, &stream); mod_amqp_command_response(profile, command, stream, fs_resp_exchange, fs_resp_key, status); } else { if (switch_console_execute(command, 0, &stream) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Remote command failed:\n%s\n", (char *) stream.data); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote command succeeded:\n%s\n", (char *) stream.data); } } switch_safe_free(stream.data); } /* Tidy up */ amqp_destroy_envelope(&envelope); } amqp_bytes_free(queueName); queueName.bytes = NULL; mod_amqp_connection_close(profile->conn_active); profile->conn_active = NULL; if (profile->running) { /* We'll reconnect, but sleep to avoid hammering resources */ switch_sleep(500); } } /* Terminate the thread */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Command listener thread stopped\n"); switch_thread_exit(thread, SWITCH_STATUS_SUCCESS); return NULL; }
static void run ( amqp_connection_state_t conn, int log_fd , const char *result_routing_key ) { int received = 0; amqp_frame_t frame; while ( 1 ) { amqp_rpc_reply_t ret; amqp_envelope_t envelope; amqp_maybe_release_buffers ( conn ); ret = amqp_consume_message ( conn, &envelope, NULL, 0 ); if ( AMQP_RESPONSE_NORMAL == ret.reply_type ) { int i; amqp_bytes_t body = envelope.message.body; const char *title = "A new message received:\n"; fprintf ( stdout, title, received ); for ( i = 0; i < body.len; i++ ) { fprintf ( stdout, "%c", * ( char* ) ( body.bytes + i ) ); } puts ( "\n" ); write ( log_fd, ( void * ) title, strlen ( title ) ); write ( log_fd, body.bytes, body.len ); write ( log_fd, ( void * ) "\n\n", 2 ); /* Send a reply. */ amqp_basic_properties_t props; props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_MESSAGE_ID_FLAG; printf("message id: %s", (const char*)envelope.message.properties.message_id.bytes); props.message_id = amqp_bytes_malloc_dup ( envelope.message.properties.message_id ); props.content_type = amqp_cstring_bytes ( "text/json" ); props.delivery_mode = 2; /* persistent delivery mode */ const char *result_body = "{\"IsException\": false, \"Result\": [{\"IsException\": false, \"Result\": []}]}"; die_on_error ( amqp_basic_publish ( conn, 1, amqp_cstring_bytes ( "" ), amqp_cstring_bytes ( result_routing_key ), 0, 0, &props, amqp_cstring_bytes ( result_body ) ), "Publishing" ); amqp_destroy_envelope ( &envelope ); } else { if ( AMQP_RESPONSE_LIBRARY_EXCEPTION == ret.reply_type && AMQP_STATUS_UNEXPECTED_STATE == ret.library_error ) { if ( AMQP_STATUS_OK != amqp_simple_wait_frame ( conn, &frame ) ) { return; } if ( AMQP_FRAME_METHOD == frame.frame_type ) { switch ( frame.payload.method.id ) { case AMQP_BASIC_ACK_METHOD: /* if we've turned publisher confirms on, and we've published a message * here is a message being confirmed */ break; case AMQP_BASIC_RETURN_METHOD: /* if a published message couldn't be routed and the mandatory flag was set * this is what would be returned. The message then needs to be read. */ { amqp_message_t message; ret = amqp_read_message ( conn, frame.channel, &message, 0 ); if ( AMQP_RESPONSE_NORMAL != ret.reply_type ) { return; } amqp_destroy_message ( &message ); } break; case AMQP_CHANNEL_CLOSE_METHOD: /* a channel.close method happens when a channel exception occurs, this * can happen by publishing to an exchange that doesn't exist for example * * In this case you would need to open another channel redeclare any queues * that were declared auto-delete, and restart any consumers that were attached * to the previous channel */ return; case AMQP_CONNECTION_CLOSE_METHOD: /* a connection.close method happens when a connection exception occurs, * this can happen by trying to use a channel that isn't open for example. * * In this case the whole connection must be restarted. */ return; default: fprintf ( stderr ,"An unexpected method was received %d\n", frame.payload.method.id ); return; } } } } received++; } }