int amqp_basic_publish(amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_boolean_t mandatory, amqp_boolean_t immediate, amqp_basic_properties_t const *properties, amqp_bytes_t body) { amqp_frame_t f; size_t body_offset; size_t usable_body_payload_size = state->frame_max - (HEADER_SIZE + FOOTER_SIZE); amqp_basic_publish_t m = (amqp_basic_publish_t) { .exchange = exchange, .routing_key = routing_key, .mandatory = mandatory, .immediate = immediate }; amqp_basic_properties_t default_properties; AMQP_CHECK_RESULT(amqp_send_method(state, channel, AMQP_BASIC_PUBLISH_METHOD, &m)); if (properties == NULL) { memset(&default_properties, 0, sizeof(default_properties)); properties = &default_properties; } f.frame_type = AMQP_FRAME_HEADER; f.channel = channel; f.payload.properties.class_id = AMQP_BASIC_CLASS; f.payload.properties.body_size = body.len; f.payload.properties.decoded = (void *) properties; AMQP_CHECK_RESULT(amqp_send_frame(state, &f)); body_offset = 0; while (1) { int remaining = body.len - body_offset; assert(remaining >= 0); if (remaining == 0) break; f.frame_type = AMQP_FRAME_BODY; f.channel = channel; f.payload.body_fragment.bytes = BUF_AT(body, body_offset); if (remaining >= usable_body_payload_size) { f.payload.body_fragment.len = usable_body_payload_size; } else { f.payload.body_fragment.len = remaining; } body_offset += f.payload.body_fragment.len; AMQP_CHECK_RESULT(amqp_send_frame(state, &f)); } return 0; }
int amqp_send_method(amqp_connection_state_t state, amqp_channel_t channel, amqp_method_number_t id, void *decoded) { amqp_frame_t frame; frame.frame_type = AMQP_FRAME_METHOD; frame.channel = channel; frame.payload.method.id = id; frame.payload.method.decoded = decoded; return amqp_send_frame(state, &frame); }
static void noit_rabbitmq_heartbeat(struct amqp_driver *dr) { struct timeval n, d; if(!dr->connection) return; mtev_gettimeofday(&n, NULL); sub_timeval(n, dr->last_hb, &d); if(d.tv_sec >= dr->heartbeat) { amqp_frame_t f; f.frame_type = AMQP_FRAME_HEARTBEAT; f.channel = 0; amqp_send_frame(dr->connection, &f); mtevL(mtev_debug, "amqp -> hearbeat\n"); memcpy(&dr->last_hb, &n, sizeof(n)); } }
int amqp_basic_publish(amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_boolean_t mandatory, amqp_boolean_t immediate, amqp_basic_properties_t const *properties, amqp_bytes_t body) { amqp_frame_t f; size_t body_offset; size_t usable_body_payload_size = state->frame_max - (HEADER_SIZE + FOOTER_SIZE); int res; amqp_basic_publish_t m; amqp_basic_properties_t default_properties; m.exchange = exchange; m.routing_key = routing_key; m.mandatory = mandatory; m.immediate = immediate; m.ticket = 0; res = amqp_send_method(state, channel, AMQP_BASIC_PUBLISH_METHOD, &m); if (res < 0) { return res; } if (properties == NULL) { memset(&default_properties, 0, sizeof(default_properties)); properties = &default_properties; } f.frame_type = AMQP_FRAME_HEADER; f.channel = channel; f.payload.properties.class_id = AMQP_BASIC_CLASS; f.payload.properties.body_size = body.len; f.payload.properties.decoded = (void *) properties; res = amqp_send_frame(state, &f); if (res < 0) { return res; } body_offset = 0; while (body_offset < body.len) { size_t remaining = body.len - body_offset; if (remaining == 0) { break; } f.frame_type = AMQP_FRAME_BODY; f.channel = channel; f.payload.body_fragment.bytes = amqp_offset(body.bytes, body_offset); if (remaining >= usable_body_payload_size) { f.payload.body_fragment.len = usable_body_payload_size; } else { f.payload.body_fragment.len = remaining; } body_offset += f.payload.body_fragment.len; res = amqp_send_frame(state, &f); if (res < 0) { return res; } } return 0; }
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; }