/** * Internal function used to initialize the connection to * the RabbitMQ server. Also used to reconnect to the server * in case the connection fails and to redeclare exchanges * and queues if they are lost * */ static int init_conn(MQ_INSTANCE *my_instance) { int rval = 0; int amqp_ok = AMQP_STATUS_OK; if(my_instance->use_ssl){ if((my_instance->sock = amqp_ssl_socket_new(my_instance->conn)) != NULL){ if((amqp_ok = amqp_ssl_socket_set_cacert(my_instance->sock,my_instance->ssl_CA_cert)) != AMQP_STATUS_OK){ skygw_log_write(LOGFILE_ERROR, "Error : Failed to set CA certificate: %s", amqp_error_string2(amqp_ok)); goto cleanup; } if((amqp_ok = amqp_ssl_socket_set_key(my_instance->sock, my_instance->ssl_client_cert, my_instance->ssl_client_key)) != AMQP_STATUS_OK){ skygw_log_write(LOGFILE_ERROR, "Error : Failed to set client certificate and key: %s", amqp_error_string2(amqp_ok)); goto cleanup; } }else{ amqp_ok = AMQP_STATUS_SSL_CONNECTION_FAILED; skygw_log_write(LOGFILE_ERROR, "Error : SSL socket creation failed."); goto cleanup; } /**SSL is not used, falling back to TCP*/ }else if((my_instance->sock = amqp_tcp_socket_new(my_instance->conn)) == NULL){ skygw_log_write(LOGFILE_ERROR, "Error : TCP socket creation failed."); goto cleanup; } /**Socket creation was successful, trying to open the socket*/ if((amqp_ok = amqp_socket_open(my_instance->sock,my_instance->hostname,my_instance->port)) != AMQP_STATUS_OK){ skygw_log_write(LOGFILE_ERROR, "Error : Failed to open socket: %s", amqp_error_string2(amqp_ok)); goto cleanup; } amqp_rpc_reply_t reply; reply = amqp_login(my_instance->conn,my_instance->vhost,0,AMQP_DEFAULT_FRAME_SIZE,0,AMQP_SASL_METHOD_PLAIN,my_instance->username,my_instance->password); if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Login to RabbitMQ server failed."); goto cleanup; } amqp_channel_open(my_instance->conn,my_instance->channel); reply = amqp_get_rpc_reply(my_instance->conn); if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Channel creation failed."); goto cleanup; } amqp_exchange_declare(my_instance->conn,my_instance->channel, amqp_cstring_bytes(my_instance->exchange), amqp_cstring_bytes(my_instance->exchange_type), 0, 1, amqp_empty_table); reply = amqp_get_rpc_reply(my_instance->conn); if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Exchange declaration failed,trying to redeclare the exchange."); if(reply.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION){ if(reply.reply.id == AMQP_CHANNEL_CLOSE_METHOD){ amqp_send_method(my_instance->conn,my_instance->channel,AMQP_CHANNEL_CLOSE_OK_METHOD,NULL); }else if(reply.reply.id == AMQP_CONNECTION_CLOSE_METHOD){ amqp_send_method(my_instance->conn,my_instance->channel,AMQP_CONNECTION_CLOSE_OK_METHOD,NULL); } my_instance->channel++; amqp_channel_open(my_instance->conn,my_instance->channel); amqp_exchange_delete(my_instance->conn,my_instance->channel,amqp_cstring_bytes(my_instance->exchange),0); amqp_exchange_declare(my_instance->conn,my_instance->channel, amqp_cstring_bytes(my_instance->exchange), amqp_cstring_bytes(my_instance->exchange_type), 0, 1, amqp_empty_table); reply = amqp_get_rpc_reply(my_instance->conn); } if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Exchange redeclaration failed."); goto cleanup; } } if(my_instance->queue){ amqp_queue_declare(my_instance->conn,my_instance->channel, amqp_cstring_bytes(my_instance->queue), 0, 1, 0, 0, amqp_empty_table); reply = amqp_get_rpc_reply(my_instance->conn); if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Queue declaration failed."); goto cleanup; } amqp_queue_bind(my_instance->conn,my_instance->channel, amqp_cstring_bytes(my_instance->queue), amqp_cstring_bytes(my_instance->exchange), amqp_cstring_bytes(my_instance->key), amqp_empty_table); reply = amqp_get_rpc_reply(my_instance->conn); if(reply.reply_type != AMQP_RESPONSE_NORMAL){ skygw_log_write(LOGFILE_ERROR, "Error : Failed to bind queue to exchange."); goto cleanup; } } rval = 1; cleanup: return rval; }
/************************************************************************* ************************************************************************** * * Namn : rmq_connect * * Typ : int * * Typ Parameter IOGF Beskrivning * * Beskrivning : Connect to RabbitMQ broker. * ************************************************************************** **************************************************************************/ int rmq_connect() { int sts; amqp_rpc_reply_t rep; amqp_channel_open_ok_t* co; if (!ctx->conn) { ctx->conn = amqp_new_connection(); // printf( "Connection : %u\n", (unsigned int)ctx->conn); } if (!ctx->socket) { ctx->socket = (amqp_socket_t*)amqp_tcp_socket_new(ctx->conn); if (!ctx->socket) { printf("Socket error\n"); return 0; } sts = amqp_socket_open(ctx->socket, ctx->op->Server, ctx->op->Port); if (sts) { printf("Socket open error %d\n", sts); ctx->socket = 0; return 0; } } rep = amqp_login(ctx->conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, ctx->op->User, ctx->op->Password); if (rep.reply_type != AMQP_RESPONSE_NORMAL) { if (rep.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION) printf("Login failure, not authorized? %d\n", rep.reply_type); else printf("Login failure: %d\n", rep.reply_type); return 0; } if (!ctx->channel) { if (ctx->op->Channel == 0) ctx->channel = 1; else ctx->channel = ctx->op->Channel; co = amqp_channel_open(ctx->conn, ctx->channel); if (!co) { printf("Channel not open\n"); ctx->channel = 0; } else { printf("Channel open %s\n", (char*)co->channel_id.bytes); } } /* Declare send queue */ if (ctx->is_producer) { // 0 passive 0 durable 0 exclusive 0 auto-delete amqp_queue_declare_ok_t* qd = amqp_queue_declare(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->SendQueue), 0, ctx->op->Durable, 0, 0, amqp_empty_table); if (!qd) { printf("SendQueue not declared\n"); } else { printf("SendQueue %s message cnt %d, consumer cnt %d\n", (char*)qd->queue.bytes, qd->message_count, qd->consumer_count); } } /* Declare receive queue */ if (ctx->is_consumer) { // 0 passive 0 durable 0 exclusive 0 auto-delete amqp_queue_declare_ok_t* qd = amqp_queue_declare(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->ReceiveQueue), 0, ctx->op->Durable, 0, 0, amqp_empty_table); if (!qd) { printf("ReceiveQueue not declared\n"); } else { printf("ReceiveQueue %s message cnt %d, consumer cnt %d\n", (char*)qd->queue.bytes, qd->message_count, qd->consumer_count); } } if (ctx->is_producer && !streq(ctx->op->Exchange, "")) #if AMQP_VERSION_MAJOR == 0 && AMQP_VERSION_MINOR < 6 amqp_exchange_declare(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->Exchange), amqp_cstring_bytes("fanout"), 0, ctx->op->Durable, amqp_empty_table); #else amqp_exchange_declare(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->Exchange), amqp_cstring_bytes("fanout"), 0, ctx->op->Durable, 0, 0, amqp_empty_table); #endif if (ctx->is_producer && !streq(ctx->op->Exchange, "")) amqp_queue_bind(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->SendQueue), amqp_cstring_bytes(ctx->op->Exchange), amqp_cstring_bytes("exchange-key"), amqp_empty_table); amqp_basic_consume_ok_t* bc; // 0 no-local 1 no-ack 0 exclusive if (ctx->is_consumer) { bc = amqp_basic_consume(ctx->conn, ctx->channel, amqp_cstring_bytes(ctx->op->ReceiveQueue), amqp_empty_bytes, 0, !ctx->op->Acknowledge, 0, amqp_empty_table); if (!bc) printf("Consumer error\n"); else printf("Consumer tag: %s\n", (char*)bc->consumer_tag.bytes); } return 1; }
int main ( int argc, char const *const *argv ) { if ( argc != 3 ) { printf ( "usage: %s CFG_FILE LOG_FILE\n", argv[0] ); return -1; } const char *log_filename = argv[2]; int flags = O_CREAT | O_APPEND | O_RDWR; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; int log_fd = open ( log_filename, flags, mode ); if ( log_fd < 0 ) { fprintf ( stderr, "ERROR: Falied to open the log file '%s'\n", log_filename ); exit ( 1 ); } /* Read the configuration file. */ struct lcfg *cfg = lcfg_new ( argv[1] ); if ( lcfg_parse ( cfg ) != lcfg_status_ok ) { printf ( "lcfg error: %s\n", lcfg_error_get ( cfg ) ); return -1; } /* Read all the configuration parameters. */ fprintf ( stdout, "Starting Murano agent with the following configuration:\n\n" ); const char *host = get_config_value ( cfg, "RABBITMQ_HOST" , 1 ); int port = atoi ( get_config_value ( cfg, "RABBITMQ_PORT" , 1 ) ); const char *vhost = get_config_value ( cfg, "RABBITMQ_VHOST" , 1 ); const char *username = get_config_value ( cfg, "RABBITMQ_USERNAME" , 1 ); const char *password = get_config_value ( cfg, "RABBITMQ_PASSWORD" , 1 ); const char *queuename = get_config_value ( cfg, "RABBITMQ_INPUT_QUEUE" , 1 ); const char *result_routing_key = get_config_value ( cfg, "RABBITMQ_RESULT_ROUTING_KEY", 1 ); amqp_connection_state_t conn = amqp_new_connection(); amqp_socket_t *socket = NULL; amqp_bytes_t queuename_bytes = amqp_cstring_bytes ( queuename ); socket = amqp_tcp_socket_new ( conn ); if ( !socket ) { die ( "creating TCP socket" ); } if ( amqp_socket_open ( socket, host, port ) ) { die ( "opening TCP socket" ); } die_on_amqp_error ( amqp_login ( conn, vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, username, password ), "Logging in" ); amqp_channel_open ( conn, 1 ); die_on_amqp_error ( amqp_get_rpc_reply ( conn ), "Opening channel" ); amqp_basic_consume ( conn, 1, queuename_bytes, amqp_empty_bytes, 0, 1, 0, amqp_empty_table ); die_on_amqp_error ( amqp_get_rpc_reply ( conn ), "Consuming" ); puts ( "\nSuccessfully connected to Rabbit MQ server! Ready for messages..." ); run ( conn, log_fd , result_routing_key ); close ( log_fd ); lcfg_delete ( cfg ); 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 amqpsend(const char *msg) { int amqp_channel = 1; // TODO: handle dynamic channel number int status; amqp_socket_t *socket = NULL; amqp_connection_state_t conn; amqp_bytes_t messagebody; // build the message body messagebody = amqp_cstring_bytes(msg); // open a connection to the server debug_print(2, "Connecting to AMQP Broker"); conn = amqp_new_connection(); socket = amqp_tcp_socket_new(conn); if (!socket) { debug_print(2, "ERROR creating TCP socket"); return 1; } status = amqp_socket_open(socket, amqp_hostname, amqp_port); if (status) { debug_print(2, "ERROR opening TCP socket"); return 1; } // authenticate debug_print(2, "Authenticating"); die_on_amqp_error( amqp_login( conn, amqp_vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, amqp_username, amqp_password ), "Authenticating"); // open a channel debug_print(3, "Opening a channel"); amqp_channel_open(conn, amqp_channel); die_on_amqp_error(amqp_get_rpc_reply(conn), "Opening channel"); // build the message frame debug_print(3, "Building AMQP Message Frame"); amqp_basic_properties_t props; props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG; props.content_type = amqp_cstring_bytes("text/plain"); props.delivery_mode = AMQP_PERSISTENT; // send the message frame debug_print(2, "Publishing message to exchange/routing key"); debug_print(2, amqp_exchange); debug_print(2, amqp_routingkey); die_on_error(amqp_basic_publish(conn, amqp_channel, amqp_cstring_bytes(amqp_exchange), amqp_cstring_bytes(amqp_routingkey), 0, 0, &props, messagebody), "Sending message"); // cleanup by closing all our connections debug_print(4, "Cleaning up AMQP Connection"); //debug_print(5, "Closing connection"); //die_on_amqp_error( // amqp_connection_close(conn, AMQP_REPLY_SUCCESS), // "Closing connection"); debug_print(5, "Ending connection"); die_on_error( amqp_destroy_connection(conn), "Ending connection"); return 0; }
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; }
static int camqp_connect (camqp_config_t *conf) /* {{{ */ { static time_t last_connect_time = 0; amqp_rpc_reply_t reply; int status; #ifdef HAVE_AMQP_TCP_SOCKET amqp_socket_t *socket; #else int sockfd; #endif if (conf->connection != NULL) return (0); time_t now = time(NULL); if (now < (last_connect_time + conf->connection_retry_delay)) { DEBUG("amqp plugin: skipping connection retry, " "ConnectionRetryDelay: %d", conf->connection_retry_delay); return(1); } else { DEBUG ("amqp plugin: retrying connection"); last_connect_time = now; } conf->connection = amqp_new_connection (); if (conf->connection == NULL) { ERROR ("amqp plugin: amqp_new_connection failed."); return (ENOMEM); } #ifdef HAVE_AMQP_TCP_SOCKET # define CLOSE_SOCKET() /* amqp_destroy_connection() closes the socket for us */ /* TODO: add support for SSL using amqp_ssl_socket_new * and related functions */ socket = amqp_tcp_socket_new (conf->connection); if (! socket) { ERROR ("amqp plugin: amqp_tcp_socket_new failed."); amqp_destroy_connection (conf->connection); conf->connection = NULL; return (ENOMEM); } status = amqp_socket_open (socket, CONF(conf, host), conf->port); if (status < 0) { char errbuf[1024]; status *= -1; ERROR ("amqp plugin: amqp_socket_open failed: %s", sstrerror (status, errbuf, sizeof (errbuf))); amqp_destroy_connection (conf->connection); conf->connection = NULL; return (status); } #else /* HAVE_AMQP_TCP_SOCKET */ # define CLOSE_SOCKET() close(sockfd) /* this interface is deprecated as of rabbitmq-c 0.4 */ sockfd = amqp_open_socket (CONF(conf, host), conf->port); if (sockfd < 0) { char errbuf[1024]; status = (-1) * sockfd; ERROR ("amqp plugin: amqp_open_socket failed: %s", sstrerror (status, errbuf, sizeof (errbuf))); amqp_destroy_connection (conf->connection); conf->connection = NULL; return (status); } amqp_set_sockfd (conf->connection, sockfd); #endif reply = amqp_login (conf->connection, CONF(conf, vhost), /* channel max = */ 0, /* frame max = */ 131072, /* heartbeat = */ 0, /* authentication = */ AMQP_SASL_METHOD_PLAIN, CONF(conf, user), CONF(conf, password)); if (reply.reply_type != AMQP_RESPONSE_NORMAL) { ERROR ("amqp plugin: amqp_login (vhost = %s, user = %s) failed.", CONF(conf, vhost), CONF(conf, user)); amqp_destroy_connection (conf->connection); CLOSE_SOCKET (); conf->connection = NULL; return (1); } amqp_channel_open (conf->connection, /* channel = */ 1); /* FIXME: Is checking "reply.reply_type" really correct here? How does * it get set? --octo */ if (reply.reply_type != AMQP_RESPONSE_NORMAL) { ERROR ("amqp plugin: amqp_channel_open failed."); amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS); amqp_destroy_connection (conf->connection); CLOSE_SOCKET (); conf->connection = NULL; return (1); } INFO ("amqp plugin: Successfully opened connection to vhost \"%s\" " "on %s:%i.", CONF(conf, vhost), CONF(conf, host), conf->port); status = camqp_create_exchange (conf); if (status != 0) return (status); if (!conf->publish) return (camqp_setup_queue (conf)); return (0); } /* }}} int camqp_connect */
eSquere* eSquere::NewSocket(amqp_connection_state_t conn){ this->socket = amqp_tcp_socket_new(conn); if(!this->socket) return this->ErrorOn("Error creating TCP socket"); if(amqp_socket_open(this->socket, this->hostname.c_str(), this->port)) return this->ErrorOn("Error opening TCP socket"); return this; }
int createMsgClient(MsgServerConf_t *conf, MsgReceiver_t **receiver) { int status = 0; MsgReceiver_t *handle; amqp_rpc_reply_t reply; amqp_queue_declare_ok_t *queue_status; char queue_name[CREDENTIAL_MAX_LEN]; status = _checkConf(conf); if(status != 0) { LOG4CXX_ERROR(logger, "createMsgClient: connection configuration check failed"); return status; } if(receiver == NULL) { LOG4CXX_ERROR(logger, "createMsgClient: receiver is null"); return EINVAL; } *receiver = NULL; handle = (MsgReceiver_t *)calloc(1, sizeof(MsgReceiver_t)); if(handle == NULL) { LOG4CXX_ERROR(logger, "createMsgClient: not enough memory to allocate"); return ENOMEM; } memcpy(&handle->conf, conf, sizeof(MsgServerConf_t)); handle->thread_run = false; LOG4CXX_DEBUG(logger, "createMsgClient: creating a TCP connection to " << conf->hostname); // create a TCP connection handle->conn_state = amqp_new_connection(); handle->socket = amqp_tcp_socket_new(handle->conn_state); if(handle->socket == NULL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to create a connection"); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } // open a socket status = amqp_socket_open(handle->socket, conf->hostname, conf->port); if(status != 0) { LOG4CXX_ERROR(logger, "createMsgClient: unable to create a TCP connection to " << conf->hostname); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } LOG4CXX_DEBUG(logger, "createMsgClient: logging in with " << conf->user_id); // login reply = amqp_login(handle->conn_state, conf->vhost, 0, AMQP_DEFAULT_FRAME_SIZE, 0, AMQP_SASL_METHOD_PLAIN, conf->user_id, conf->user_pwd); if(reply.reply_type != AMQP_RESPONSE_NORMAL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to login with " << conf->user_id << " - " << reply.reply_type); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } LOG4CXX_DEBUG(logger, "createMsgClient: opening a channel"); // open a channel handle->channel = 1; amqp_channel_open(handle->conn_state, handle->channel); reply = amqp_get_rpc_reply(handle->conn_state); if(reply.reply_type != AMQP_RESPONSE_NORMAL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to open a channel - " << reply.reply_type); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } LOG4CXX_DEBUG(logger, "createMsgClient: declaring and binding a queue"); // declare a queue memset(queue_name, 0, CREDENTIAL_MAX_LEN); sprintf(queue_name, "%s/%s", conf->user_id, conf->app_id); queue_status = amqp_queue_declare(handle->conn_state, handle->channel, amqp_cstring_bytes(queue_name), 0, 0, 1, 1, amqp_empty_table); reply = amqp_get_rpc_reply(handle->conn_state); if(reply.reply_type != AMQP_RESPONSE_NORMAL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to declare a queue - " << reply.reply_type); amqp_channel_close(handle->conn_state, handle->channel, AMQP_REPLY_SUCCESS); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } handle->queuename = amqp_bytes_malloc_dup(queue_status->queue); if(handle->queuename.bytes == NULL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to get a queue name"); amqp_channel_close(handle->conn_state, handle->channel, AMQP_REPLY_SUCCESS); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } /* * no need to bind it when we use default exchange amqp_queue_bind(handle->conn_state, handle->channel, handle->queuename, amqp_cstring_bytes(conf->exchange), amqp_cstring_bytes("#"), amqp_empty_table); reply = amqp_get_rpc_reply(handle->conn_state); if(reply.reply_type != AMQP_RESPONSE_NORMAL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to bind a queue"); amqp_channel_close(handle->conn_state, handle->channel, AMQP_REPLY_SUCCESS); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } */ LOG4CXX_DEBUG(logger, "createMsgClient: starting consuming"); // start consume amqp_basic_consume(handle->conn_state, handle->channel, handle->queuename, amqp_empty_bytes, 0, 0, 0, amqp_empty_table); reply = amqp_get_rpc_reply(handle->conn_state); if(reply.reply_type != AMQP_RESPONSE_NORMAL) { LOG4CXX_ERROR(logger, "createMsgClient: unable to start consuming - " << reply.reply_type); amqp_channel_close(handle->conn_state, handle->channel, AMQP_REPLY_SUCCESS); amqp_connection_close(handle->conn_state, AMQP_REPLY_SUCCESS); amqp_destroy_connection(handle->conn_state); free(handle); return EIO; } *receiver = handle; return 0; }
/* Transport implementation */ int janus_rabbitmq_init(janus_transport_callbacks *callback, const char *config_path) { if(g_atomic_int_get(&stopping)) { /* Still stopping from before */ return -1; } if(callback == NULL || config_path == NULL) { /* Invalid arguments */ return -1; } /* This is the callback we'll need to invoke to contact the Janus core */ gateway = callback; /* Read configuration */ char filename[255]; g_snprintf(filename, 255, "%s/%s.jcfg", config_path, JANUS_RABBITMQ_PACKAGE); JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename); janus_config *config = janus_config_parse(filename); if(config == NULL) { JANUS_LOG(LOG_WARN, "Couldn't find .jcfg configuration file (%s), trying .cfg\n", JANUS_RABBITMQ_PACKAGE); g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_RABBITMQ_PACKAGE); JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename); config = janus_config_parse(filename); } if(config != NULL) janus_config_print(config); janus_config_category *config_general = janus_config_get_create(config, NULL, janus_config_type_category, "general"); janus_config_category *config_admin = janus_config_get_create(config, NULL, janus_config_type_category, "admin"); janus_config_item *item = janus_config_get(config, config_general, janus_config_type_item, "json"); if(item && item->value) { /* Check how we need to format/serialize the JSON output */ if(!strcasecmp(item->value, "indented")) { /* Default: indented, we use three spaces for that */ json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER; } else if(!strcasecmp(item->value, "plain")) { /* Not indented and no new lines, but still readable */ json_format = JSON_INDENT(0) | JSON_PRESERVE_ORDER; } else if(!strcasecmp(item->value, "compact")) { /* Compact, so no spaces between separators */ json_format = JSON_COMPACT | JSON_PRESERVE_ORDER; } else { JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", item->value); json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER; } } /* Check if we need to send events to handlers */ janus_config_item *events = janus_config_get(config, config_general, janus_config_type_item, "events"); if(events != NULL && events->value != NULL) notify_events = janus_is_true(events->value); if(!notify_events && callback->events_is_enabled()) { JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_RABBITMQ_NAME); } /* Handle configuration, starting from the server details */ item = janus_config_get(config, config_general, janus_config_type_item, "host"); if(item && item->value) rmqhost = g_strdup(item->value); else rmqhost = g_strdup("localhost"); int rmqport = AMQP_PROTOCOL_PORT; item = janus_config_get(config, config_general, janus_config_type_item, "port"); if(item && item->value) rmqport = atoi(item->value); /* Credentials and Virtual Host */ item = janus_config_get(config, config_general, janus_config_type_item, "vhost"); if(item && item->value) vhost = g_strdup(item->value); else vhost = g_strdup("/"); item = janus_config_get(config, config_general, janus_config_type_item, "username"); if(item && item->value) username = g_strdup(item->value); else username = g_strdup("guest"); item = janus_config_get(config, config_general, janus_config_type_item, "password"); if(item && item->value) password = g_strdup(item->value); else password = g_strdup("guest"); /* SSL config*/ gboolean ssl_enabled = FALSE; gboolean ssl_verify_peer = FALSE; gboolean ssl_verify_hostname = FALSE; item = janus_config_get(config, config_general, janus_config_type_item, "ssl_enabled"); if(item == NULL) { /* Try legacy property */ item = janus_config_get(config, config_general, janus_config_type_item, "ssl_enable"); if (item && item->value) { JANUS_LOG(LOG_WARN, "Found deprecated 'ssl_enable' property, please update it to 'ssl_enabled' instead\n"); } } if(!item || !item->value || !janus_is_true(item->value)) { JANUS_LOG(LOG_INFO, "RabbitMQ SSL support disabled\n"); } else { ssl_enabled = TRUE; item = janus_config_get(config, config_general, janus_config_type_item, "ssl_cacert"); if(item && item->value) ssl_cacert_file = g_strdup(item->value); item = janus_config_get(config, config_general, janus_config_type_item, "ssl_cert"); if(item && item->value) ssl_cert_file = g_strdup(item->value); item = janus_config_get(config, config_general, janus_config_type_item, "ssl_key"); if(item && item->value) ssl_key_file = g_strdup(item->value); item = janus_config_get(config, config_general, janus_config_type_item, "ssl_verify_peer"); if(item && item->value && janus_is_true(item->value)) ssl_verify_peer = TRUE; item = janus_config_get(config, config_general, janus_config_type_item, "ssl_verify_hostname"); if(item && item->value && janus_is_true(item->value)) ssl_verify_hostname = TRUE; } /* Now check if the Janus API must be supported */ item = janus_config_get(config, config_general, janus_config_type_item, "enabled"); if(item == NULL) { /* Try legacy property */ item = janus_config_get(config, config_general, janus_config_type_item, "enable"); if (item && item->value) { JANUS_LOG(LOG_WARN, "Found deprecated 'enable' property, please update it to 'enabled' instead\n"); } } if(!item || !item->value || !janus_is_true(item->value)) { JANUS_LOG(LOG_WARN, "RabbitMQ support disabled (Janus API)\n"); } else { /* Parse configuration */ item = janus_config_get(config, config_general, janus_config_type_item, "to_janus"); if(!item || !item->value) { JANUS_LOG(LOG_FATAL, "Missing name of incoming queue for RabbitMQ integration...\n"); goto error; } to_janus = g_strdup(item->value); item = janus_config_get(config, config_general, janus_config_type_item, "from_janus"); if(!item || !item->value) { JANUS_LOG(LOG_FATAL, "Missing name of outgoing queue for RabbitMQ integration...\n"); goto error; } from_janus = g_strdup(item->value); item = janus_config_get(config, config_general, janus_config_type_item, "janus_exchange"); if(!item || !item->value) { JANUS_LOG(LOG_INFO, "Missing name of outgoing exchange for RabbitMQ integration, using default\n"); } else { janus_exchange = g_strdup(item->value); } if (janus_exchange == NULL) { JANUS_LOG(LOG_INFO, "RabbitMQ support for Janus API enabled, %s:%d (%s/%s)\n", rmqhost, rmqport, to_janus, from_janus); } else { JANUS_LOG(LOG_INFO, "RabbitMQ support for Janus API enabled, %s:%d (%s/%s) exch: (%s)\n", rmqhost, rmqport, to_janus, from_janus, janus_exchange); } rmq_janus_api_enabled = TRUE; } /* Do the same for the admin API */ item = janus_config_get(config, config_admin, janus_config_type_item, "admin_enabled"); if(item == NULL) { /* Try legacy property */ item = janus_config_get(config, config_general, janus_config_type_item, "admin_enable"); if (item && item->value) { JANUS_LOG(LOG_WARN, "Found deprecated 'admin_enable' property, please update it to 'admin_enabled' instead\n"); } } if(!item || !item->value || !janus_is_true(item->value)) { JANUS_LOG(LOG_WARN, "RabbitMQ support disabled (Admin API)\n"); } else { /* Parse configuration */ item = janus_config_get(config, config_admin, janus_config_type_item, "to_janus_admin"); if(!item || !item->value) { JANUS_LOG(LOG_FATAL, "Missing name of incoming queue for RabbitMQ integration...\n"); goto error; } to_janus_admin = g_strdup(item->value); item = janus_config_get(config, config_admin, janus_config_type_item, "from_janus_admin"); if(!item || !item->value) { JANUS_LOG(LOG_FATAL, "Missing name of outgoing queue for RabbitMQ integration...\n"); goto error; } from_janus_admin = g_strdup(item->value); JANUS_LOG(LOG_INFO, "RabbitMQ support for Admin API enabled, %s:%d (%s/%s)\n", rmqhost, rmqport, to_janus_admin, from_janus_admin); rmq_admin_api_enabled = TRUE; } if(!rmq_janus_api_enabled && !rmq_admin_api_enabled) { JANUS_LOG(LOG_WARN, "RabbitMQ support disabled for both Janus and Admin API, giving up\n"); goto error; } else { /* FIXME We currently support a single application, create a new janus_rabbitmq_client instance */ rmq_client = g_malloc0(sizeof(janus_rabbitmq_client)); /* Connect */ rmq_client->rmq_conn = amqp_new_connection(); amqp_socket_t *socket = NULL; int status; JANUS_LOG(LOG_VERB, "Creating RabbitMQ socket...\n"); if (ssl_enabled) { socket = amqp_ssl_socket_new(rmq_client->rmq_conn); if(socket == NULL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error creating socket...\n"); goto error; } if(ssl_verify_peer) { amqp_ssl_socket_set_verify_peer(socket, 1); } else { amqp_ssl_socket_set_verify_peer(socket, 0); } if(ssl_verify_hostname) { amqp_ssl_socket_set_verify_hostname(socket, 1); } else { amqp_ssl_socket_set_verify_hostname(socket, 0); } if(ssl_cacert_file) { status = amqp_ssl_socket_set_cacert(socket, ssl_cacert_file); if(status != AMQP_STATUS_OK) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error setting CA certificate... (%s)\n", amqp_error_string2(status)); goto error; } } if(ssl_cert_file && ssl_key_file) { status = amqp_ssl_socket_set_key(socket, ssl_cert_file, ssl_key_file); if(status != AMQP_STATUS_OK) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error setting key... (%s)\n", amqp_error_string2(status)); goto error; } } } else { socket = amqp_tcp_socket_new(rmq_client->rmq_conn); if(socket == NULL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error creating socket...\n"); goto error; } } JANUS_LOG(LOG_VERB, "Connecting to RabbitMQ server...\n"); status = amqp_socket_open(socket, rmqhost, rmqport); if(status != AMQP_STATUS_OK) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error opening socket... (%s)\n", amqp_error_string2(status)); goto error; } JANUS_LOG(LOG_VERB, "Logging in...\n"); amqp_rpc_reply_t result = amqp_login(rmq_client->rmq_conn, vhost, 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, username, password); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error logging in... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } rmq_client->rmq_channel = 1; JANUS_LOG(LOG_VERB, "Opening channel...\n"); amqp_channel_open(rmq_client->rmq_conn, rmq_client->rmq_channel); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error opening channel... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } rmq_client->janus_exchange = amqp_empty_bytes; if(janus_exchange != NULL) { JANUS_LOG(LOG_VERB, "Declaring exchange...\n"); rmq_client->janus_exchange = amqp_cstring_bytes(janus_exchange); amqp_exchange_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->janus_exchange, amqp_cstring_bytes(JANUS_RABBITMQ_EXCHANGE_TYPE), 0, 0, 0, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error diclaring exchange... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } } rmq_client->janus_api_enabled = FALSE; if(rmq_janus_api_enabled) { rmq_client->janus_api_enabled = TRUE; JANUS_LOG(LOG_VERB, "Declaring incoming queue... (%s)\n", to_janus); rmq_client->to_janus_queue = amqp_cstring_bytes(to_janus); amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_queue, 0, 0, 0, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } JANUS_LOG(LOG_VERB, "Declaring outgoing queue... (%s)\n", from_janus); rmq_client->from_janus_queue = amqp_cstring_bytes(from_janus); amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->from_janus_queue, 0, 0, 0, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } amqp_basic_consume(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_queue, amqp_empty_bytes, 0, 1, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error consuming... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } } rmq_client->admin_api_enabled = FALSE; if(rmq_admin_api_enabled) { rmq_client->admin_api_enabled = TRUE; JANUS_LOG(LOG_VERB, "Declaring incoming queue... (%s)\n", to_janus_admin); rmq_client->to_janus_admin_queue = amqp_cstring_bytes(to_janus_admin); amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_admin_queue, 0, 0, 0, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } JANUS_LOG(LOG_VERB, "Declaring outgoing queue... (%s)\n", from_janus_admin); rmq_client->from_janus_admin_queue = amqp_cstring_bytes(from_janus_admin); amqp_queue_declare(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->from_janus_admin_queue, 0, 0, 0, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error declaring queue... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } amqp_basic_consume(rmq_client->rmq_conn, rmq_client->rmq_channel, rmq_client->to_janus_admin_queue, amqp_empty_bytes, 0, 1, 0, amqp_empty_table); result = amqp_get_rpc_reply(rmq_client->rmq_conn); if(result.reply_type != AMQP_RESPONSE_NORMAL) { JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error consuming... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id)); goto error; } } rmq_client->messages = g_async_queue_new(); rmq_client->destroy = 0; /* Prepare the transport session (again, just one) */ rmq_session = janus_transport_session_create(rmq_client, NULL); /* Start the threads */ GError *error = NULL; rmq_client->in_thread = g_thread_try_new("rmq_in_thread", &janus_rmq_in_thread, rmq_client, &error); if(error != NULL) { /* Something went wrong... */ JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQ incoming thread...\n", error->code, error->message ? error->message : "??"); janus_transport_session_destroy(rmq_session); g_free(rmq_client); janus_config_destroy(config); return -1; } rmq_client->out_thread = g_thread_try_new("rmq_out_thread", &janus_rmq_out_thread, rmq_client, &error); if(error != NULL) { /* Something went wrong... */ JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQ outgoing thread...\n", error->code, error->message ? error->message : "??"); janus_transport_session_destroy(rmq_session); g_free(rmq_client); janus_config_destroy(config); return -1; } janus_mutex_init(&rmq_client->mutex); /* Done */ JANUS_LOG(LOG_INFO, "Setup of RabbitMQ integration completed\n"); /* Notify handlers about this new transport */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("connected")); gateway->notify_event(&janus_rabbitmq_transport, rmq_session, info); } } janus_config_destroy(config); config = NULL; /* Done */ g_atomic_int_set(&initialized, 1); JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_RABBITMQ_NAME); return 0; error: /* If we got here, something went wrong */ g_free(rmq_client); g_free(rmqhost); g_free(vhost); g_free(username); g_free(password); g_free(janus_exchange); g_free(to_janus); g_free(from_janus); g_free(to_janus_admin); g_free(from_janus_admin); g_free(ssl_cacert_file); g_free(ssl_cert_file); g_free(ssl_key_file); if(config) janus_config_destroy(config); return -1; }