char *basic_get(amqp_connection_state_t connection_state_, const char *queue_name_, uint64_t *out_body_size_) { amqp_rpc_reply_t rpc_reply; amqp_time_t deadline; struct timeval timeout = { 5, 0 }; int time_rc = amqp_time_from_now(&deadline, &timeout); assert(time_rc == AMQP_STATUS_OK); do { rpc_reply = amqp_basic_get(connection_state_, fixed_channel_id, amqp_cstring_bytes(queue_name_), /*no_ack*/ 1); } while (rpc_reply.reply_type == AMQP_RESPONSE_NORMAL && rpc_reply.reply.id == AMQP_BASIC_GET_EMPTY_METHOD && amqp_time_has_past(deadline) == AMQP_STATUS_OK); assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL); assert(rpc_reply.reply.id == AMQP_BASIC_GET_OK_METHOD); amqp_message_t message; rpc_reply = amqp_read_message(connection_state_, fixed_channel_id, &message, 0); assert(rpc_reply.reply_type == AMQP_RESPONSE_NORMAL); char *body = malloc(message.body.len); memcpy(body, message.body.bytes, message.body.len); *out_body_size_ = message.body.len; amqp_destroy_message(&message); return body; }
amqp_rpc_reply_t amqp_consume_message(amqp_connection_state_t state, amqp_envelope_t *envelope, struct timeval *timeout, AMQP_UNUSED int flags) { int res; amqp_frame_t frame; amqp_basic_deliver_t *delivery_method; amqp_rpc_reply_t ret; memset(&ret, 0, sizeof(amqp_rpc_reply_t)); memset(envelope, 0, sizeof(amqp_envelope_t)); res = amqp_simple_wait_frame_noblock(state, &frame, timeout); if (AMQP_STATUS_OK != res) { ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION; ret.library_error = res; goto error_out1; } if (AMQP_FRAME_METHOD != frame.frame_type || AMQP_BASIC_DELIVER_METHOD != frame.payload.method.id) { amqp_put_back_frame(state, &frame); ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION; ret.library_error = AMQP_STATUS_UNEXPECTED_STATE; goto error_out1; } delivery_method = frame.payload.method.decoded; envelope->channel = frame.channel; envelope->consumer_tag = amqp_bytes_malloc_dup(delivery_method->consumer_tag); envelope->delivery_tag = delivery_method->delivery_tag; envelope->redelivered = delivery_method->redelivered; envelope->exchange = amqp_bytes_malloc_dup(delivery_method->exchange); envelope->routing_key = amqp_bytes_malloc_dup(delivery_method->routing_key); if (amqp_bytes_malloc_dup_failed(envelope->consumer_tag) || amqp_bytes_malloc_dup_failed(envelope->exchange) || amqp_bytes_malloc_dup_failed(envelope->routing_key)) { ret.reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION; ret.library_error = AMQP_STATUS_NO_MEMORY; goto error_out2; } ret = amqp_read_message(state, envelope->channel, &envelope->message, 0); if (AMQP_RESPONSE_NORMAL != ret.reply_type) { goto error_out2; } ret.reply_type = AMQP_RESPONSE_NORMAL; return ret; error_out2: amqp_bytes_free(envelope->routing_key); amqp_bytes_free(envelope->exchange); amqp_bytes_free(envelope->consumer_tag); error_out1: return ret; }
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); }
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++; } }
expected_methods[0] = expected_method; return amqp_simple_wait_method_list_noblock(state, expected_channel, expected_methods, output, timeout); } int php_amqp_handle_basic_return(char **message, amqp_connection_resource *resource, amqp_channel_t channel_id, amqp_channel_object *channel, amqp_method_t *method TSRMLS_DC) { amqp_rpc_reply_t ret; amqp_message_t msg; int status = PHP_AMQP_RESOURCE_RESPONSE_OK; assert(AMQP_BASIC_RETURN_METHOD == method->id); amqp_basic_return_t *m = (amqp_basic_return_t *) method->decoded; ret = amqp_read_message(resource->connection_state, channel_id, &msg, 0); if (AMQP_RESPONSE_NORMAL != ret.reply_type) { return php_amqp_connection_resource_error(ret, message, resource, channel_id TSRMLS_CC); } if (channel->callbacks.basic_return.fci.size > 0) { status = php_amqp_call_basic_return_callback(m, &msg, &channel->callbacks.basic_return TSRMLS_CC); } else { zend_error(E_NOTICE, "Unhandled basic.return method from server received. Use AMQPChannel::setBasicReturnCallback() to process it."); status = PHP_AMQP_RESOURCE_RESPONSE_BREAK; } amqp_destroy_message(&msg); return status;
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++; } }
int main(int argc, char** argv) { int channel = 1, status = AMQP_STATUS_OK, cnfnlen; amqp_socket_t *socket = NULL; amqp_connection_state_t conn; amqp_rpc_reply_t ret; amqp_message_t *reply = NULL; amqp_frame_t frame; struct timeval timeout; MYSQL db_inst; char ch, *cnfname = NULL, *cnfpath = NULL; static const char* fname = "consumer.cnf"; if((c_inst = calloc(1,sizeof(CONSUMER))) == NULL){ fprintf(stderr, "Fatal Error: Cannot allocate enough memory.\n"); return 1; } if(signal(SIGINT,sighndl) == SIG_IGN){ signal(SIGINT,SIG_IGN); } while((ch = getopt(argc,argv,"c:"))!= -1){ switch(ch){ case 'c': cnfnlen = strlen(optarg); cnfpath = strdup(optarg); break; default: break; } } cnfname = calloc(cnfnlen + strlen(fname) + 1,sizeof(char)); if(cnfpath){ /**Config file path as argument*/ strcpy(cnfname,cnfpath); if(cnfpath[cnfnlen-1] != '/'){ strcat(cnfname,"/"); } } strcat(cnfname,fname); timeout.tv_sec = 1; timeout.tv_usec = 0; all_ok = 1; out_fd = NULL; /**Parse the INI file*/ if(ini_parse(cnfname,handler,NULL) < 0){ /**Try to parse a config in the same directory*/ if(ini_parse(fname,handler,NULL) < 0){ fprintf(stderr, "Fatal Error: Error parsing configuration file!\n"); goto fatal_error; } } if(out_fd == NULL){ out_fd = stdout; } fprintf(out_fd,"\n--------------------------------------------------------------\n"); /**Confirm that all parameters were in the configuration file*/ if(!c_inst->hostname||!c_inst->vhost||!c_inst->user|| !c_inst->passwd||!c_inst->dbpasswd||!c_inst->queue|| !c_inst->dbserver||!c_inst->dbname||!c_inst->dbuser){ fprintf(stderr, "Fatal Error: Inadequate configuration file!\n"); goto fatal_error; } connectToServer(&db_inst); if((conn = amqp_new_connection()) == NULL || (socket = amqp_tcp_socket_new(conn)) == NULL){ fprintf(stderr, "Fatal Error: Cannot create connection object or socket.\n"); goto fatal_error; } if(amqp_socket_open(socket, c_inst->hostname, c_inst->port)){ fprintf(stderr, "RabbitMQ Error: Cannot open socket.\n"); goto error; } ret = amqp_login(conn, c_inst->vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, c_inst->user, c_inst->passwd); if(ret.reply_type != AMQP_RESPONSE_NORMAL){ fprintf(stderr, "RabbitMQ Error: Cannot login to server.\n"); goto error; } amqp_channel_open(conn, channel); ret = amqp_get_rpc_reply(conn); if(ret.reply_type != AMQP_RESPONSE_NORMAL){ fprintf(stderr, "RabbitMQ Error: Cannot open channel.\n"); goto error; } reply = malloc(sizeof(amqp_message_t)); if(!reply){ fprintf(stderr, "Error: Cannot allocate enough memory.\n"); goto error; } amqp_basic_consume(conn,channel,amqp_cstring_bytes(c_inst->queue),amqp_empty_bytes,0,0,0,amqp_empty_table); while(all_ok){ status = amqp_simple_wait_frame_noblock(conn,&frame,&timeout); /**No frames to read from server, possibly out of messages*/ if(status == AMQP_STATUS_TIMEOUT){ sleep(timeout.tv_sec); continue; } if(frame.payload.method.id == AMQP_BASIC_DELIVER_METHOD){ amqp_basic_deliver_t* decoded = (amqp_basic_deliver_t*)frame.payload.method.decoded; amqp_read_message(conn,channel,reply,0); if(sendMessage(&db_inst,reply)){ fprintf(stderr,"RabbitMQ Error: Received malformed message.\n"); amqp_basic_reject(conn,channel,decoded->delivery_tag,0); amqp_destroy_message(reply); }else{ amqp_basic_ack(conn,channel,decoded->delivery_tag,0); amqp_destroy_message(reply); } }else{ fprintf(stderr,"RabbitMQ Error: Received method from server: %s\n",amqp_method_name(frame.payload.method.id)); all_ok = 0; goto error; } } fprintf(out_fd,"Shutting down...\n"); error: mysql_close(&db_inst); mysql_library_end(); if(c_inst && c_inst->query_stack){ while(c_inst->query_stack){ DELIVERY* d = c_inst->query_stack->next; amqp_destroy_message(c_inst->query_stack->message); free(c_inst->query_stack); c_inst->query_stack = d; } } amqp_channel_close(conn, channel, AMQP_REPLY_SUCCESS); amqp_connection_close(conn, AMQP_REPLY_SUCCESS); amqp_destroy_connection(conn); fatal_error: if(out_fd){ fclose(out_fd); } if(c_inst){ free(c_inst->hostname); free(c_inst->vhost); free(c_inst->user); free(c_inst->passwd); free(c_inst->queue); free(c_inst->dbserver); free(c_inst->dbname); free(c_inst->dbuser); free(c_inst->dbpasswd); free(c_inst); } return all_ok; }