void copy_body(amqp_connection_state_t conn, int fd) { size_t body_remaining; amqp_frame_t frame; int res = amqp_simple_wait_frame(conn, &frame); die_amqp_error(res, "waiting for header frame"); if (frame.frame_type != AMQP_FRAME_HEADER) { die("expected header, got frame type 0x%X", frame.frame_type); } body_remaining = frame.payload.properties.body_size; while (body_remaining) { res = amqp_simple_wait_frame(conn, &frame); die_amqp_error(res, "waiting for body frame"); if (frame.frame_type != AMQP_FRAME_BODY) { die("expected body, got frame type 0x%X", frame.frame_type); } write_all(fd, frame.payload.body_fragment); body_remaining -= frame.payload.body_fragment.len; } }
int amqp_simple_wait_method(amqp_connection_state_t state, amqp_channel_t expected_channel, amqp_method_number_t expected_method, amqp_method_t *output) { amqp_frame_t frame; int res = amqp_simple_wait_frame(state, &frame); if (res < 0) return res; if (frame.channel != expected_channel) amqp_abort("Expected 0x%08X method frame on channel %d, got frame on channel %d", expected_method, expected_channel, frame.channel); if (frame.frame_type != AMQP_FRAME_METHOD) amqp_abort("Expected 0x%08X method frame on channel %d, got frame type %d", expected_method, expected_channel, frame.frame_type); if (frame.payload.method.id != expected_method) amqp_abort("Expected method ID 0x%08X on channel %d, got ID 0x%08X", expected_method, expected_channel, frame.payload.method.id); *output = frame.payload.method; return 0; }
int amqp_simple_wait_method(amqp_connection_state_t state, amqp_channel_t expected_channel, amqp_method_number_t expected_method, amqp_method_t *output) { amqp_frame_t frame; (void)AMQP_CHECK_EOF_RESULT(amqp_simple_wait_frame(state, &frame)); amqp_assert(frame.channel == expected_channel, "Expected 0x%08X method frame on channel %d, got frame on channel %d", expected_method, expected_channel, frame.channel); amqp_assert(frame.frame_type == AMQP_FRAME_METHOD, "Expected 0x%08X method frame on channel %d, got frame type %d", expected_method, expected_channel, frame.frame_type); amqp_assert(frame.payload.method.id == expected_method, "Expected method ID 0x%08X on channel %d, got ID 0x%08X", expected_method, expected_channel, frame.payload.method.id); *output = frame.payload.method; return 1; }
static int camqp_read_header(camqp_config_t *conf) /* {{{ */ { int status; amqp_frame_t frame; amqp_basic_properties_t *properties; char *content_type; status = amqp_simple_wait_frame(conf->connection, &frame); if (status < 0) { status = (-1) * status; ERROR("amqp plugin: amqp_simple_wait_frame failed: %s", STRERROR(status)); camqp_close_connection(conf); return status; } if (frame.frame_type != AMQP_FRAME_HEADER) { NOTICE("amqp plugin: Unexpected frame type: %#" PRIx8, frame.frame_type); return -1; } properties = frame.payload.properties.decoded; content_type = camqp_bytes_cstring(&properties->content_type); if (content_type == NULL) { ERROR("amqp plugin: Unable to determine content type."); return -1; } status = camqp_read_body(conf, (size_t)frame.payload.properties.body_size, content_type); sfree(content_type); return status; } /* }}} int camqp_read_header */
static void *camqp_subscribe_thread (void *user_data) /* {{{ */ { camqp_config_t *conf = user_data; int status; cdtime_t interval = plugin_get_interval (); while (subscriber_threads_running) { amqp_frame_t frame; status = camqp_connect (conf); if (status != 0) { struct timespec ts_interval; ERROR ("amqp plugin: camqp_connect failed. " "Will sleep for %.3f seconds.", CDTIME_T_TO_DOUBLE (interval)); CDTIME_T_TO_TIMESPEC (interval, &ts_interval); nanosleep (&ts_interval, /* remaining = */ NULL); continue; } status = amqp_simple_wait_frame (conf->connection, &frame); if (status < 0) { struct timespec ts_interval; ERROR ("amqp plugin: amqp_simple_wait_frame failed. " "Will sleep for %.3f seconds.", CDTIME_T_TO_DOUBLE (interval)); camqp_close_connection (conf); CDTIME_T_TO_TIMESPEC (interval, &ts_interval); nanosleep (&ts_interval, /* remaining = */ NULL); continue; } if (frame.frame_type != AMQP_FRAME_METHOD) { DEBUG ("amqp plugin: Unexpected frame type: %#"PRIx8, frame.frame_type); continue; } if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) { DEBUG ("amqp plugin: Unexpected method id: %#"PRIx32, frame.payload.method.id); continue; } camqp_read_header (conf); amqp_maybe_release_buffers (conf->connection); } /* while (subscriber_threads_running) */ camqp_config_free (conf); pthread_exit (NULL); return (NULL); } /* }}} void *camqp_subscribe_thread */
/* * Subscribing code */ static int camqp_read_body(camqp_config_t *conf, /* {{{ */ size_t body_size, const char *content_type) { char body[body_size + 1]; char *body_ptr; size_t received; amqp_frame_t frame; int status; memset(body, 0, sizeof(body)); body_ptr = &body[0]; received = 0; while (received < body_size) { status = amqp_simple_wait_frame(conf->connection, &frame); if (status < 0) { status = (-1) * status; ERROR("amqp plugin: amqp_simple_wait_frame failed: %s", STRERROR(status)); camqp_close_connection(conf); return status; } if (frame.frame_type != AMQP_FRAME_BODY) { NOTICE("amqp plugin: Unexpected frame type: %#" PRIx8, frame.frame_type); return -1; } if ((body_size - received) < frame.payload.body_fragment.len) { WARNING("amqp plugin: Body is larger than indicated by header."); return -1; } memcpy(body_ptr, frame.payload.body_fragment.bytes, frame.payload.body_fragment.len); body_ptr += frame.payload.body_fragment.len; received += frame.payload.body_fragment.len; } /* while (received < body_size) */ if (strcasecmp("text/collectd", content_type) == 0) { status = cmd_handle_putval(stderr, body); if (status != 0) ERROR("amqp plugin: cmd_handle_putval failed with status %i.", status); return status; } else if (strcasecmp("application/json", content_type) == 0) { ERROR("amqp plugin: camqp_read_body: Parsing JSON data has not " "been implemented yet. FIXME!"); return 0; } else { ERROR("amqp plugin: camqp_read_body: Unknown content type \"%s\".", content_type); return EINVAL; } /* not reached */ return 0; } /* }}} int camqp_read_body */
static void *camqp_subscribe_thread (void *user_data) /* {{{ */ { camqp_config_t *conf = user_data; int status; while (subscriber_threads_running) { amqp_frame_t frame; status = camqp_connect (conf); if (status != 0) { ERROR ("amqp plugin: camqp_connect failed. " "Will sleep for %i seconds.", interval_g); sleep (interval_g); continue; } status = amqp_simple_wait_frame (conf->connection, &frame); if (status < 0) { ERROR ("amqp plugin: amqp_simple_wait_frame failed. " "Will sleep for %i seconds.", interval_g); camqp_close_connection (conf); sleep (interval_g); continue; } if (frame.frame_type != AMQP_FRAME_METHOD) { DEBUG ("amqp plugin: Unexpected frame type: %#"PRIx8, frame.frame_type); continue; } if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) { DEBUG ("amqp plugin: Unexpected method id: %#"PRIx32, frame.payload.method.id); continue; } status = camqp_read_header (conf); amqp_maybe_release_buffers (conf->connection); } /* while (subscriber_threads_running) */ camqp_config_free (conf); pthread_exit (NULL); } /* }}} void *camqp_subscribe_thread */
static void noit_rabbitmq_read_frame(struct amqp_driver *dr) { struct pollfd p; if(!dr->connection) return; while(1) { memset(&p, 0, sizeof(p)); p.fd = dr->sockfd; p.events = POLLIN; if(poll(&p, 1, 0)) { int rv; amqp_frame_t f; rv = amqp_simple_wait_frame(dr->connection, &f); if(rv > 0) { if(f.frame_type == AMQP_FRAME_HEARTBEAT) { BUMPSTAT(inbound_heartbeats); mtevL(mtev_debug, "amqp <- hearbeat\n"); } else if(f.frame_type == AMQP_FRAME_METHOD) { BUMPSTAT(inbound_methods); mtevL(mtev_error, "amqp <- method [%s]\n", amqp_method_name(f.payload.method.id)); dr->has_error = 1; switch(f.payload.method.id) { case AMQP_CHANNEL_CLOSE_METHOD: { amqp_channel_close_t *m = (amqp_channel_close_t *) f.payload.method.decoded; mtevL(mtev_error, "AMQP channel close error %d: %s\n", m->reply_code, (char *)m->reply_text.bytes); } break; case AMQP_CONNECTION_CLOSE_METHOD: { amqp_connection_close_t *m = (amqp_connection_close_t *) f.payload.method.decoded; mtevL(mtev_error, "AMQP connection close error %d: %s\n", m->reply_code, (char *)m->reply_text.bytes); } break; } } else { mtevL(mtev_error, "amqp <- frame [%d]\n", f.frame_type); } } else break; } else break; } }
/* taken from rabbbitmq-c */ static int amqp_simple_wait_method_list(amqp_connection_state_t state, amqp_channel_t expected_channel, amqp_method_number_t *expected_methods, amqp_method_t *output) { amqp_frame_t frame; int res = amqp_simple_wait_frame(state, &frame); if (AMQP_STATUS_OK != res) { return res; } if (AMQP_FRAME_METHOD != frame.frame_type || expected_channel != frame.channel || !amqp_id_in_reply_list(frame.payload.method.id, expected_methods)) { return AMQP_STATUS_WRONG_METHOD; } *output = frame.payload.method; return AMQP_STATUS_OK; }
int main(int argc, char const *const *argv) { char const *hostname; int port, status; char const *queuename; amqp_socket_t *socket; amqp_connection_state_t conn; if (argc < 4) { fprintf(stderr, "Usage: amqps_listenq host port queuename " "[cacert.pem [key.pem cert.pem]]\n"); return 1; } hostname = argv[1]; port = atoi(argv[2]); queuename = argv[3]; conn = amqp_new_connection(); socket = amqp_ssl_socket_new(); if (!socket) { die("creating SSL/TLS socket"); } if (argc > 4) { status = amqp_ssl_socket_set_cacert(socket, argv[4]); if (status) { die("setting CA certificate"); } } if (argc > 6) { status = amqp_ssl_socket_set_key(socket, argv[6], argv[5]); if (status) { die("setting client cert"); } } status = amqp_socket_open(socket, hostname, port); if (status) { die("opening SSL/TLS connection"); } amqp_set_socket(conn, 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_basic_consume(conn, 1, amqp_cstring_bytes(queuename), amqp_empty_bytes, 0, 0, 0, amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); { amqp_frame_t frame; int result; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; while (1) { amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); printf("Result %d\n", result); if (result < 0) { break; } printf("Frame type %d, channel %d\n", frame.frame_type, frame.channel); if (frame.frame_type != AMQP_FRAME_METHOD) { continue; } printf("Method %s\n", amqp_method_name(frame.payload.method.id)); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) { continue; } d = (amqp_basic_deliver_t *) frame.payload.method.decoded; printf("Delivery %u, exchange %.*s routingkey %.*s\n", (unsigned) d->delivery_tag, (int) d->exchange.len, (char *) d->exchange.bytes, (int) d->routing_key.len, (char *) d->routing_key.bytes); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) { break; } if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } printf("----\n"); body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) { break; } if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); amqp_dump(frame.payload.body_fragment.bytes, frame.payload.body_fragment.len); } if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ break; } amqp_basic_ack(conn, 1, d->delivery_tag, 0); } } 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; }
int main(int argc,const char *argv[]) { const char *hostName; int port; const char *queueName; int prefetchCount; int noAck = 1; if (argc < 6) { fprintf(stderr,"Usage: consumer host port queuename prefetch_count no_ack\n"); exit(1); } hostName = argv[1]; port = atoi(argv[2]); queueName = argv[3]; prefetchCount = atoi(argv[4]); if(strcmp(argv[5],"false")==0) noAck = 0; int sockfd; int channelId = 1; amqp_connection_state_t conn; conn = amqp_new_connection(); die_on_error(sockfd = amqp_open_socket(hostName, port), "Opening socket"); amqp_set_sockfd(conn, sockfd); die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest"),"Logging in"); amqp_channel_open(conn, channelId); die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); amqp_basic_qos(conn,channelId,0,prefetchCount,0); amqp_basic_consume(conn,channelId,amqp_cstring_bytes(queueName),amqp_empty_bytes,0,noAck,0,amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); int count = 0; amqp_frame_t frame; int result; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; long long start = timeInMilliseconds(); while(1){ { amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_METHOD) continue; if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) continue; d = (amqp_basic_deliver_t *) frame.payload.method.decoded; result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); } if (body_received != body_target) { break; } if(!noAck) amqp_basic_ack(conn,channelId,d->delivery_tag,0); } count++; if(count%10000 == 0) { long long end = timeInMilliseconds(); fprintf(stderr,"round %d takes %lld millseconds(10000 messages consumed every round)\n",count/10000-1,end-start); start = timeInMilliseconds(); } } 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++; } }
int main(int argc, const char **argv) { const char *hostname; int port; const char *exchange; const char *routingkey; const char *exchangetype = "direct"; if (argc < 5) { fprintf(stderr, "Usage: receive_logs_direct host port exchange routingkeys...\n"); return 1; } hostname = argv[1]; port = atoi(argv[2]); exchange = argv[3]; int sockfd; int channelid = 1; amqp_connection_state_t conn; conn = amqp_new_connection(); die_on_error(sockfd = amqp_open_socket(hostname, port), "Opening socket"); amqp_set_sockfd(conn, sockfd); die_on_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest"),"Logging in"); amqp_channel_open(conn, channelid); die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); amqp_exchange_declare(conn,channelid,amqp_cstring_bytes(exchange),amqp_cstring_bytes(exchangetype),0,1, amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn),"Declaring exchange"); amqp_queue_declare_ok_t *r = amqp_queue_declare(conn,channelid,amqp_empty_bytes,0,0,1,0,amqp_empty_table); int i; for(i = 4;i < argc;i++) { routingkey = argv[i]; amqp_queue_bind(conn,channelid,amqp_bytes_malloc_dup(r->queue),amqp_cstring_bytes(exchange), amqp_cstring_bytes(routingkey),amqp_empty_table); } amqp_basic_qos(conn,channelid,0,1,0); amqp_basic_consume(conn,channelid,amqp_bytes_malloc_dup(r->queue),amqp_empty_bytes,0,0,0,amqp_empty_table); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); { amqp_frame_t frame; int result; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; while (1) { amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); printf("Result %d\n", result); if (result < 0) break; printf("Frame type %d, channel %d\n", frame.frame_type, frame.channel); if (frame.frame_type != AMQP_FRAME_METHOD) continue; printf("Method %s\n", amqp_method_name(frame.payload.method.id)); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) continue; d = (amqp_basic_deliver_t *) frame.payload.method.decoded; printf("Delivery %u, exchange %.*s routingkey %.*s\n",(unsigned) d->delivery_tag, (int) d->exchange.len, (char *) d->exchange.bytes, (int) d->routing_key.len, (char *) d->routing_key.bytes); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } body_target = frame.payload.properties.body_size; body_received = 0; int sleep_seconds = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); int i; for(i = 0; i<frame.payload.body_fragment.len; i++) { printf("%c",*((char*)frame.payload.body_fragment.bytes+i)); if(*((char*)frame.payload.body_fragment.bytes+i) == '.') sleep_seconds++; } printf("\n"); } if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ break; } /* do something */ sleep(sleep_seconds); amqp_basic_ack(conn,channelid,d->delivery_tag,0); } } 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; int result; size_t body_received; size_t body_target; uint64_t now; while (1) { 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); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) return; if (frame.frame_type != AMQP_FRAME_METHOD) continue; if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) continue; result = amqp_simple_wait_frame(conn, &frame); if (result < 0) return; if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) return; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); } received++; } }
int main(int argc, char **argv) { char const *hostname = "amqpbroker"; // amqp hostname int port = 5672; // amqp port static int verbose_flag = 0; // be verbose? static int foreground_flag = 0; static int passive = 0; // declare queue passively? static int exclusive = 0; // declare queue as exclusive? static int durable = 0; // decalre queue as durable? static int no_ack = 0; static int msg_limit = 0; // maxiumum number of messages to retrieve int const no_local = 1; // we never want to see messages we publish int c; // for option parsing char const *exchange = ""; char const *bindingkey = ""; char const *vhost = "/"; char const *username = "******"; char const *password = "******"; char const *program = NULL; char const *program_args = NULL; amqp_bytes_t queue = AMQP_EMPTY_BYTES; int sockfd; amqp_connection_state_t conn; amqp_bytes_t queuename; if (NULL != getenv("AMQP_HOST")) hostname = getenv("AMQP_HOST"); if (NULL != getenv("AMQP_PORT")) port = atoi(getenv("AMQP_PORT")); port = port > 0 ? port : 5672; // 5672 is the default amqp port if (NULL != getenv("AMQP_VHOST")) vhost = getenv("AMQP_VHOST"); if (NULL != getenv("AMQP_USER")) username = getenv("AMQP_USER"); if (NULL != getenv("AMQP_PASSWORD")) password = getenv("AMQP_PASSWORD"); if (NULL != getenv("AMQP_QUEUE")) queue = amqp_cstring_bytes(getenv("AMQP_QUEUE")); if (NULL != getenv("AMQP_QUEUE_PASSIVE")) passive = atoi(getenv("AMQP_QUEUE_PASSIVE")); if (NULL != getenv("AMQP_QUEUE_EXCLUSIVE")) exclusive = atoi(getenv("AMQP_QUEUE_EXCLUSIVE")); if (NULL != getenv("AMQP_QUEUE_DURABLE")) durable = atoi(getenv("AMQP_QUEUE_DURABLE")); if (NULL != getenv("AMQP_MSG_LIMIT")) msg_limit = atoi(getenv("AMQP_MSG_LIMIT")); msg_limit = msg_limit > 0 ? msg_limit : 0; // default to unlimited while(1) { static struct option long_options[] = { {"verbose", no_argument, &verbose_flag, 1}, {"user", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"vhost", required_argument, 0, 'v'}, {"host", required_argument, 0, 'h'}, {"port", required_argument, 0, 'P'}, {"number", required_argument, 0, 'n'}, {"foreground", no_argument, 0, 'f'}, {"passive", no_argument, &passive, 1}, {"exclusive", no_argument, &exclusive, 1}, {"durable", no_argument, &durable, 1}, {"no-ack", no_argument, &no_ack, 1}, {"execute", required_argument, 0, 'e'}, {"queue", required_argument, 0, 'q'}, {"help", no_argument, 0, '?'}, {0, 0, 0, 0} }; int option_index = 0; c = getopt_long(argc, argv, "v:h:P:u:p:n:fe:q:?", long_options, &option_index); if(c == -1) break; switch(c) { case 0: // no_argument break; case 'v': vhost = optarg; break; case 'h': hostname = optarg; break; case 'P': port = atoi(optarg); port = port > 0 ? port : 5672; // 5672 is the default amqp port break; case 'f': foreground_flag = 1; case 'n': msg_limit = atoi(optarg); msg_limit = msg_limit > 0 ? msg_limit : 0; // deafult to unlimited break; case 'e': program = optarg; break; case 'u': username = optarg; break; case 'p': password = optarg; break; case 'q': queue = amqp_cstring_bytes(optarg); break; case '?': default: print_help(argv[0]); exit(1); } } if ((argc-optind) < 2) { print_help(argv[0]); return 1; } exchange = argv[optind]; bindingkey = argv[optind+1]; if (NULL != program) { // check that the program is executable char *wend; wend = strchr(program, ' '); if(wend){ *wend = '\0'; program_args = wend+1; } if (0 != access(program, X_OK)) { fprintf(stderr, "Program doesn't have execute permission, aborting: %s\n", program); exit(-1); } if(wend){ *wend = ' '; } } if ((passive != 0) && (passive != 1)) { fprintf(stderr, "Queue option 'passive' must be 0 or 1: %u\n", passive); exit(-1); } if ((exclusive != 0) && (exclusive != 1)) { fprintf(stderr, "Queue option 'exclusive' must be 0 or 1: %u\n", exclusive); exit(-1); } if ((durable != 0) && (durable != 1)) { fprintf(stderr, "Queue option 'durable' must be 0 or 1: %u\n", durable); exit(-1); } conn = amqp_new_connection(); die_on_error(sockfd = amqp_open_socket(hostname, port), "Opening socket"); amqp_set_sockfd(conn, sockfd); die_on_amqp_error(amqp_login(conn, vhost, 0, /* channel_max */ 10485760, /* max frame size, 10MB */ 30, /* heartbeat, 30 secs */ AMQP_SASL_METHOD_PLAIN, username, password), "Logging in"); amqp_channel_open(conn, AMQP_CHANNEL); die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); { int optval = 1; socklen_t optlen = sizeof(optlen); setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); } { amqp_queue_declare_ok_t *r = amqp_queue_declare(conn, AMQP_CHANNEL, queue, passive, durable, exclusive, 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\n"); return 1; } } amqp_queue_bind(conn, AMQP_CHANNEL, queuename, amqp_cstring_bytes(exchange), amqp_cstring_bytes(bindingkey), AMQP_EMPTY_TABLE); die_on_amqp_error(amqp_get_rpc_reply(conn), "Binding queue"); /* Set our prefetch to the maximum number of messages we want to ensure we * don't take more than we want according to --number option from user */ int prefetch_limit = DEFAULT_PREFETCH; if (msg_limit > 0 && msg_limit <= 65535) prefetch_limit = msg_limit; amqp_basic_qos(conn, AMQP_CHANNEL, 0, prefetch_limit, 0); die_on_amqp_error(amqp_get_rpc_reply(conn), "Setting Basic QOS (prefetch limit)"); amqp_basic_consume(conn, AMQP_CHANNEL, queuename, AMQP_EMPTY_BYTES, no_local, no_ack, exclusive, AMQP_EMPTY_TABLE); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); // If executing a program, daemonise if(NULL != program && 0 == foreground_flag) { pid_t pid, sid; pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } else if(pid > 0) { exit(EXIT_SUCCESS); } umask(0); sid = setsid(); if (sid < 0) exit(EXIT_FAILURE); } { amqp_frame_t frame; int result; int status = 0; /* wait() status, used whether to send ACK */ amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; install_term_handler(SIGINT); install_term_handler(SIGTERM); install_term_handler(SIGHUP); int msg_count = 0; while (1) { char tempfile[] = "/tmp/amqp.XXXXXX"; int tempfd; // exit if we've reached our maximum message count if((0 != msg_limit) && (msg_limit == msg_count)) break; // we haven't reached our limit; move on to the next msg_count++; if(g_shutdown == 1) break; amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); //printf("Result %d\n", result); if (result < 0) break; //printf("Frame type %d, channel %d\n", frame.frame_type, frame.channel); if (frame.frame_type == AMQP_FRAME_HEARTBEAT) { // send the same heartbeat frame back amqp_send_frame(conn, &frame); continue; } else if (frame.frame_type != AMQP_FRAME_METHOD) continue; //printf("Method %s\n", amqp_method_name(frame.payload.method.id)); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) continue; d = (amqp_basic_deliver_t *) frame.payload.method.decoded; /* printf("Delivery %u, exchange %.*s routingkey %.*s\n", (unsigned) d->delivery_tag, (int) d->exchange.len, (char *) d->exchange.bytes, (int) d->routing_key.len, (char *) d->routing_key.bytes); */ result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; /* if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } printf("----\n"); */ body_target = frame.payload.properties.body_size; body_received = 0; tempfd = mkstemp(tempfile); //tempfd = open(tempfile, O_WRONLY | O_CREAT | O_EXCL, 660); while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); if (write(tempfd, frame.payload.body_fragment.bytes, frame.payload.body_fragment.len) < 0) { perror("Error while writing received message to temp file"); } } close(tempfd); { char *routekey = (char *)calloc(1, d->routing_key.len + 1); strncpy(routekey, (char *)d->routing_key.bytes, d->routing_key.len); if(NULL != program) { // fork and run the program in the background pid_t pid = fork(); if (pid == 0) { if(execl(program, program, program_args, routekey, tempfile, NULL) == -1) { perror("Could not execute program"); exit(EXIT_FAILURE); } } else { status = 0; wait(&status); } } else { // print to stdout & flush. printf("%s %s\n", routekey, tempfile); fflush(stdout); } free(routekey); } // send ack on successful processing of the frame if((0 == status) && (0 == no_ack)) amqp_basic_ack(conn, frame.channel, d->delivery_tag, 0); if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ break; } } } die_on_amqp_error(amqp_channel_close(conn, AMQP_CHANNEL, 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; }
int main(int argc, char const * const *argv) { char const *hostname; int port; char const *queuename; char const *amqp_user; char const *amqp_passwd; amqp_frame_t frame; int result; char *ret = NULL; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; int sockfd; amqp_connection_state_t conn; if (argc < 6) { fprintf(stderr, "Usage: amqp_listenq host port queuename user password\n"); return 1; } hostname = argv[1]; port = atoi(argv[2]); queuename = argv[3]; amqp_user = argv[4]; amqp_passwd = argv[5]; conn = amqp_new_connection(); ads_utils_error(sockfd = amqp_open_socket(hostname, port), "Opening socket"); amqp_set_sockfd(conn, sockfd); ads_utils_amqp_error(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, amqp_user, amqp_passwd), "Logging in"); amqp_channel_open(conn, 1); ads_utils_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); amqp_basic_consume(conn, 1, amqp_cstring_bytes(queuename), AMQP_EMPTY_BYTES, 0, 0, 0, AMQP_EMPTY_TABLE); ads_utils_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) exit(0); if (frame.frame_type != AMQP_FRAME_METHOD) exit(0); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) exit(0); d = (amqp_basic_deliver_t *) frame.payload.method.decoded; result = amqp_simple_wait_frame(conn, &frame); if (result < 0) exit(0); if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); return 1; } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) break; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); return 1; } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); ret = ads_utils_amqp_dump(frame.payload.body_fragment.bytes, frame.payload.body_fragment.len); printf("%s\n", ret); free(ret); } if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ exit(0); } amqp_basic_ack(conn, 1, d->delivery_tag, 0); ads_utils_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), "Closing channel"); ads_utils_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS), "Closing connection"); ads_utils_error(amqp_destroy_connection(conn), "Ending connection"); return 0; }
int main(int argc, char *argv[]) { char const *hostname; int port, status; char const *exchange; char const *routingkey; char const *messagebody; amqp_socket_t *socket = NULL; amqp_connection_state_t conn; amqp_bytes_t reply_to_queue; if (argc < 6) { /* minimum number of mandatory arguments */ fprintf(stderr, "usage:\namqp_rpc_sendstring_client host port exchange routingkey messagebody\n"); return 1; } hostname = argv[1]; port = atoi(argv[2]); exchange = argv[3]; routingkey = argv[4]; messagebody = argv[5]; /* establish a channel that is used to connect RabbitMQ server */ conn = amqp_new_connection(); socket = amqp_tcp_socket_new(conn); if (!socket) { printf("creating TCP socket"); } status = amqp_socket_open(socket, hostname, port); if (status) { printf("opening TCP socket"); } printf("established connection!\n"); amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, "guest", "guest");// "Logging in"); amqp_channel_open(conn, 1); amqp_get_rpc_reply(conn);//, "Opening channel"); printf("open channel!\n"); /* create private reply_to queue */ { amqp_queue_declare_ok_t *r = amqp_queue_declare(conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table); amqp_get_rpc_reply(conn);//, "Declaring queue"); printf("declare queue!\n"); reply_to_queue = amqp_bytes_malloc_dup(r->queue); if (reply_to_queue.bytes == NULL) { fprintf(stderr, "Out of memory while copying queue name"); return 1; } } /* send the message */ { /* set properties */ amqp_basic_properties_t props; props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_REPLY_TO_FLAG | AMQP_BASIC_CORRELATION_ID_FLAG; props.content_type = amqp_cstring_bytes("text/plain"); props.delivery_mode = 2; /* persistent delivery mode */ props.reply_to = amqp_bytes_malloc_dup(reply_to_queue); if (props.reply_to.bytes == NULL) { fprintf(stderr, "Out of memory while copying queue name"); return 1; } props.correlation_id = amqp_cstring_bytes("1"); /* publish */ amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange), amqp_cstring_bytes(routingkey), 0, 0, &props, amqp_cstring_bytes(messagebody)); // "Publishing"); amqp_bytes_free(props.reply_to); } /* wait an answer */ printf("waiting answer!\n"); { amqp_basic_consume(conn, 1, reply_to_queue, amqp_empty_bytes, 0, 1, 0, amqp_empty_table); amqp_get_rpc_reply(conn);//, "Consuming"); amqp_bytes_free(reply_to_queue); { amqp_frame_t frame; int result; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; while (1) { amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); printf("Result: %d\n", result); if (result < 0) { break; } printf("Frame type: %d channel: %d\n", frame.frame_type, frame.channel); if (frame.frame_type != AMQP_FRAME_METHOD) { continue; } printf("Method: %s\n", amqp_method_name(frame.payload.method.id)); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) { continue; } d = (amqp_basic_deliver_t *) frame.payload.method.decoded; printf("Delivery: %u exchange: %.*s routingkey: %.*s\n", (unsigned) d->delivery_tag, (int) d->exchange.len, (char *) d->exchange.bytes, (int) d->routing_key.len, (char *) d->routing_key.bytes); result = amqp_simple_wait_frame(conn, &frame); if (result < 0) { break; } if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } printf("----\n"); body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result < 0) { break; } if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; printf("len -> %d \n",frame.payload.body_fragment.len); assert(body_received <= body_target); amqp_dump(frame.payload.body_fragment.bytes, frame.payload.body_fragment.len); } if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ break; } /* everything was fine, we can quit now because we received the reply */ break; } } } /* closing */ amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);//, "Closing channel"); amqp_connection_close(conn, AMQP_REPLY_SUCCESS);//, "Closing connection"); amqp_destroy_connection(conn);//, "Ending connection"); return 0; }
/* Threads */ void *janus_rmq_in_thread(void *data) { if(rmq_client == NULL) { JANUS_LOG(LOG_ERR, "No RabbitMQ connection??\n"); return NULL; } JANUS_LOG(LOG_VERB, "Joining RabbitMQ in thread\n"); struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 20000; amqp_frame_t frame; while(!rmq_client->destroy && !g_atomic_int_get(&stopping)) { amqp_maybe_release_buffers(rmq_client->rmq_conn); /* Wait for a frame */ int res = amqp_simple_wait_frame_noblock(rmq_client->rmq_conn, &frame, &timeout); if(res != AMQP_STATUS_OK) { /* No data */ if(res == AMQP_STATUS_TIMEOUT) continue; JANUS_LOG(LOG_VERB, "Error on amqp_simple_wait_frame_noblock: %d (%s)\n", res, amqp_error_string2(res)); break; } /* We expect method first */ JANUS_LOG(LOG_VERB, "Frame type %d, channel %d\n", frame.frame_type, frame.channel); if(frame.frame_type != AMQP_FRAME_METHOD) continue; JANUS_LOG(LOG_VERB, "Method %s\n", amqp_method_name(frame.payload.method.id)); gboolean admin = FALSE; if(frame.payload.method.id == AMQP_BASIC_DELIVER_METHOD) { amqp_basic_deliver_t *d = (amqp_basic_deliver_t *)frame.payload.method.decoded; JANUS_LOG(LOG_VERB, "Delivery #%u, %.*s\n", (unsigned) d->delivery_tag, (int) d->routing_key.len, (char *) d->routing_key.bytes); /* Check if this is a Janus or Admin API request */ if(rmq_client->admin_api_enabled) { if(d->routing_key.len == rmq_client->to_janus_admin_queue.len) { size_t i=0; admin = TRUE; char *inq = (char *)d->routing_key.bytes; char *expq = (char *)rmq_client->to_janus_admin_queue.bytes; for(i=0; i< d->routing_key.len; i++) { if(inq[i] != expq[i]) { admin = FALSE; break; } } } } JANUS_LOG(LOG_VERB, " -- This is %s API request\n", admin ? "an admin" : "a Janus"); } /* Then the header */ amqp_simple_wait_frame(rmq_client->rmq_conn, &frame); JANUS_LOG(LOG_VERB, "Frame type %d, channel %d\n", frame.frame_type, frame.channel); if(frame.frame_type != AMQP_FRAME_HEADER) continue; amqp_basic_properties_t *p = (amqp_basic_properties_t *)frame.payload.properties.decoded; if(p->_flags & AMQP_BASIC_REPLY_TO_FLAG) { JANUS_LOG(LOG_VERB, " -- Reply-to: %.*s\n", (int) p->reply_to.len, (char *) p->reply_to.bytes); } char *correlation = NULL; if(p->_flags & AMQP_BASIC_CORRELATION_ID_FLAG) { correlation = g_malloc0(p->correlation_id.len+1); sprintf(correlation, "%.*s", (int) p->correlation_id.len, (char *) p->correlation_id.bytes); JANUS_LOG(LOG_VERB, " -- Correlation-id: %s\n", correlation); } if(p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { JANUS_LOG(LOG_VERB, " -- Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } /* And the body */ uint64_t total = frame.payload.properties.body_size, received = 0; char *payload = g_malloc0(total+1), *index = payload; while(received < total) { amqp_simple_wait_frame(rmq_client->rmq_conn, &frame); JANUS_LOG(LOG_VERB, "Frame type %d, channel %d\n", frame.frame_type, frame.channel); if(frame.frame_type != AMQP_FRAME_BODY) break; sprintf(index, "%.*s", (int) frame.payload.body_fragment.len, (char *) frame.payload.body_fragment.bytes); received += frame.payload.body_fragment.len; index = payload+received; } JANUS_LOG(LOG_VERB, "Got %"SCNu64"/%"SCNu64" bytes from the %s queue (%"SCNu64")\n", received, total, admin ? "admin API" : "Janus API", frame.payload.body_fragment.len); JANUS_LOG(LOG_VERB, "%s\n", payload); /* Parse the JSON payload */ json_error_t error; json_t *root = json_loads(payload, 0, &error); g_free(payload); /* Notify the core, passing both the object and, since it may be needed, the error * We also specify the correlation ID as an opaque request identifier: we'll need it later */ gateway->incoming_request(&janus_rabbitmq_transport, rmq_session, correlation, admin, root, &error); } JANUS_LOG(LOG_INFO, "Leaving RabbitMQ in thread\n"); return 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); }
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++; } }
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; }
int main(int argc, char const * const *argv) { char const *hostname; int port; char const *exchange; char const *bindingkey; int sockfd; 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(); die_on_error(sockfd = amqp_open_socket(hostname, port), "Opening socket"); amqp_set_sockfd(conn, sockfd); 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) { die_on_error(-ENOMEM, "Copying queue name"); } } 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); die_on_amqp_error(amqp_get_rpc_reply(conn), "Consuming"); { amqp_frame_t frame; int result; amqp_basic_deliver_t *d; amqp_basic_properties_t *p; size_t body_target; size_t body_received; while (1) { amqp_maybe_release_buffers(conn); result = amqp_simple_wait_frame(conn, &frame); printf("Result %d\n", result); if (result <= 0) break; printf("Frame type %d, channel %d\n", frame.frame_type, frame.channel); if (frame.frame_type != AMQP_FRAME_METHOD) continue; printf("Method %s\n", amqp_method_name(frame.payload.method.id)); if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD) continue; d = (amqp_basic_deliver_t *) frame.payload.method.decoded; printf("Delivery %u, exchange %.*s routingkey %.*s\n", (unsigned) d->delivery_tag, (int) d->exchange.len, (char *) d->exchange.bytes, (int) d->routing_key.len, (char *) d->routing_key.bytes); result = amqp_simple_wait_frame(conn, &frame); if (result <= 0) break; if (frame.frame_type != AMQP_FRAME_HEADER) { fprintf(stderr, "Expected header!"); abort(); } p = (amqp_basic_properties_t *) frame.payload.properties.decoded; if (p->_flags & AMQP_BASIC_CONTENT_TYPE_FLAG) { printf("Content-type: %.*s\n", (int) p->content_type.len, (char *) p->content_type.bytes); } printf("----\n"); body_target = frame.payload.properties.body_size; body_received = 0; while (body_received < body_target) { result = amqp_simple_wait_frame(conn, &frame); if (result <= 0) break; if (frame.frame_type != AMQP_FRAME_BODY) { fprintf(stderr, "Expected body!"); abort(); } body_received += frame.payload.body_fragment.len; assert(body_received <= body_target); amqp_dump(frame.payload.body_fragment.bytes, frame.payload.body_fragment.len); } if (body_received != body_target) { /* Can only happen when amqp_simple_wait_frame returns <= 0 */ /* We break here to close the connection */ break; } } } 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"); amqp_destroy_connection(conn); die_on_error(close(sockfd), "Closing socket"); return 0; }
bool ChannelImpl::GetNextFrameFromBroker(amqp_frame_t& frame, boost::chrono::microseconds timeout) { int socketno = amqp_get_sockfd(m_connection); start: // Possibly set a timeout on receiving if (timeout != boost::chrono::microseconds::max() && !amqp_frames_enqueued(m_connection) && !amqp_data_in_buffer(m_connection)) { struct timeval tv_timeout; memset(&tv_timeout, 0, sizeof(tv_timeout)); // boost::chrono::seconds.count() returns boost::int_atleast64_t, // long can be 32 or 64 bit depending on the platform/arch // unless the timeout is something absurd cast to long will be ok, but // lets guard against the case where someone does something silly assert(boost::chrono::duration_cast<boost::chrono::seconds>(timeout).count() < static_cast<boost::chrono::seconds::rep>(std::numeric_limits<long>::max())); tv_timeout.tv_sec = static_cast<long>(boost::chrono::duration_cast<boost::chrono::seconds>(timeout).count()); tv_timeout.tv_usec = static_cast<long>((timeout - boost::chrono::seconds(tv_timeout.tv_sec)).count()); fd_set fds; FD_ZERO(&fds); FD_SET(static_cast<unsigned int>(socketno), &fds); int select_return = select(socketno + 1, &fds, NULL, &fds, &tv_timeout); if (select_return == 0) // If it times out, return { return false; } else if (select_return == -1) { // If its an interupted system call just try again if (errno == EINTR) { goto start; } else { std::string error_string("error calling select on socket: "); #ifdef HAVE_STRERROR_S const int BUFFER_LENGTH = 256; char error_string_buffer[BUFFER_LENGTH] = {0}; strerror_s(error_string_buffer, errno); error_string += error_string_buffer; #elif defined(HAVE_STRERROR_R) const int BUFFER_LENGTH = 256; char error_string_buffer[BUFFER_LENGTH] = {0}; strerror_r(errno, error_string_buffer, BUFFER_LENGTH); error_string += error_string_buffer; #else error_string += strerror(errno); #endif throw std::runtime_error(error_string.c_str()); } } } CheckForError(amqp_simple_wait_frame(m_connection, &frame)); return true; }