diff --git a/CHANGES b/CHANGES index a6d3a6b989..ef2ff2200a 100644 --- a/CHANGES +++ b/CHANGES @@ -50,6 +50,20 @@ cdr_sqlite * This module was deprecated and has been removed. Users of cdr_sqlite should use cdr_sqlite3_custom. +cdr_pgsql +------------------ + * Added the ability to support PostgreSQL application_name on connections. + This allows PostgreSQL to display the configured name in the + pg_stat_activity view and CSV log entries. This setting is configurable + for cdr_pgsql via the appname configuration setting in cdr_pgsql.conf. + +cel_pgsql +------------------ + * Added the ability to support PostgreSQL application_name on connections. + This allows PostgreSQL to display the configured name in the + pg_stat_activity view and CSV log entries. This setting is configurable + for cel_pgsql via the appname configuration setting in cel_pgsql.conf. + CEL ------------------ * The "bridge_technology" extra field key has been added to BRIDGE_ENTER @@ -156,6 +170,14 @@ VoiceMail - jb-wa: article wa - jb-wo: article wo +res_config_pgsql +------------------ + * Added the ability to support PostgreSQL application_name on connections. + This allows PostgreSQL to display the configured name in the + pg_stat_activity view and CSV log entries. This setting is configurable + for res_config_pgsql via the dbappname configuration setting in + res_pgsql.conf. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 12.3.0 to Asterisk 12.4.0 ------------ ------------------------------------------------------------------------------ diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index 8322da9b55..815bb6a7de 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -63,7 +63,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static const char name[] = "pgsql"; static const char config[] = "cdr_pgsql.conf"; -static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL, *encoding = NULL, *tz = NULL; + +static char *pghostname; +static char *pgdbname; +static char *pgdbuser; +static char *pgpassword; +static char *pgappname; +static char *pgdbport; +static char *table; +static char *encoding; +static char *tz; + static int connected = 0; static int maxsize = 512, maxsize2 = 512; static time_t connect_time = 0; @@ -174,6 +184,34 @@ static char *handle_cdr_pgsql_status(struct ast_cli_entry *e, int cmd, struct as return CLI_SUCCESS; } +static void pgsql_reconnect(void) +{ + struct ast_str *conn_info = ast_str_create(128); + if (!conn_info) { + ast_log(LOG_ERROR, "Failed to allocate memory for connection string.\n"); + return; + } + + if (conn) { + PQfinish(conn); + conn = NULL; + } + + ast_str_set(&conn_info, 0, "host=%s port=%s dbname=%s user=%s", + pghostname, pgdbport, pgdbname, pgdbuser); + + if (!ast_strlen_zero(pgappname)) { + ast_str_append(&conn_info, 0, " application_name=%s", pgappname); + } + + if (!ast_strlen_zero(pgpassword)) { + ast_str_append(&conn_info, 0, " password=%s", pgpassword); + } + + conn = PQconnectdb(ast_str_buffer(conn_info)); + ast_free(conn_info); +} + static int pgsql_log(struct ast_cdr *cdr) { struct ast_tm tm; @@ -183,7 +221,8 @@ static int pgsql_log(struct ast_cdr *cdr) ast_mutex_lock(&pgsql_lock); if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); + pgsql_reconnect(); + if (PQstatus(conn) != CONNECTION_BAD) { connected = 1; connect_time = time(NULL); @@ -441,12 +480,15 @@ static int unload_module(void) ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli)); - PQfinish(conn); - + if (conn) { + PQfinish(conn); + conn = NULL; + } ast_free(pghostname); ast_free(pgdbname); ast_free(pgdbuser); ast_free(pgpassword); + ast_free(pgappname); ast_free(pgdbport); ast_free(table); ast_free(encoding); @@ -519,6 +561,18 @@ static int config_module(int reload) return -1; } + if (!(tmp = ast_variable_retrieve(cfg, "global", "appname"))) { + tmp = ""; + } + + ast_free(pgappname); + if (!(pgappname = ast_strdup(tmp))) { + ast_config_destroy(cfg); + ast_mutex_unlock(&pgsql_lock); + return -1; + } + + if (!(tmp = ast_variable_retrieve(cfg, "global", "password"))) { ast_log(LOG_WARNING, "PostgreSQL database password not specified. Assuming blank\n"); tmp = ""; @@ -590,12 +644,14 @@ static int config_module(int reload) ast_debug(1, "got user of %s\n", pgdbuser); ast_debug(1, "got dbname of %s\n", pgdbname); ast_debug(1, "got password of %s\n", pgpassword); + ast_debug(1, "got application name of %s\n", pgappname); ast_debug(1, "got sql table name of %s\n", table); ast_debug(1, "got encoding of %s\n", encoding); ast_debug(1, "got timezone of %s\n", tz); } - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); + pgsql_reconnect(); + if (PQstatus(conn) != CONNECTION_BAD) { char sqlcmd[768]; char *fname, *ftype, *flen, *fnotnull, *fdef; @@ -719,6 +775,8 @@ static int config_module(int reload) ast_log(LOG_ERROR, "Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); ast_log(LOG_ERROR, "Reason: %s\n", pgerror); connected = 0; + PQfinish(conn); + conn = NULL; } ast_config_destroy(cfg); diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index cd50af0e51..f673ceb357 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -4,8 +4,8 @@ * Copyright (C) 2008 * * Steve Murphy - adapted to CEL, from: - * Matthew D. Hardeman - * Adapted from the MySQL CDR logger originally by James Sharp + * Matthew D. Hardeman + * Adapted from the MySQL CDR logger originally by James Sharp * * Modified April, 2007; Dec, 2008 * Steve Murphy @@ -26,8 +26,8 @@ /*! \file * - * \brief PostgreSQL CEL logger - * + * \brief PostgreSQL CEL logger + * * \author Steve Murphy * PostgreSQL http://www.postgresql.org/ * @@ -61,7 +61,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define PGSQL_BACKEND_NAME "CEL PGSQL backend" static char *config = "cel_pgsql.conf"; -static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL; + +static char *pghostname; +static char *pgdbname; +static char *pgdbuser; +static char *pgpassword; +static char *pgappname; +static char *pgdbport; +static char *table; + static int connected = 0; static int maxsize = 512, maxsize2 = 512; @@ -114,6 +122,35 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns); } \ } while (0) +static void pgsql_reconnect(void) +{ + struct ast_str *conn_info = ast_str_create(128); + if (!conn_info) { + ast_log(LOG_ERROR, "Failed to allocate memory for connection string.\n"); + return; + } + + if (conn) { + PQfinish(conn); + conn = NULL; + } + + ast_str_set(&conn_info, 0, "host=%s port=%s dbname=%s user=%s", + pghostname, pgdbport, pgdbname, pgdbuser); + + if (!ast_strlen_zero(pgappname)) { + ast_str_append(&conn_info, 0, " application_name=%s", pgappname); + } + + if (!ast_strlen_zero(pgpassword)) { + ast_str_append(&conn_info, 0, " password=%s", pgpassword); + } + + conn = PQconnectdb(ast_str_buffer(conn_info)); + ast_free(conn_info); +} + + static void pgsql_log(struct ast_event *event) { struct ast_tm tm; @@ -133,7 +170,7 @@ static void pgsql_log(struct ast_event *event) ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); if ((!connected) && pghostname && pgdbuser && pgpassword && pgdbname) { - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); + pgsql_reconnect(); if (PQstatus(conn) != CONNECTION_BAD) { connected = 1; } else { @@ -368,6 +405,10 @@ static int my_unload_module(void) ast_free(pgpassword); pgpassword = NULL; } + if (pgappname) { + ast_free(pgappname); + pgappname = NULL; + } if (pgdbport) { ast_free(pgdbport); pgdbport = NULL; @@ -440,6 +481,17 @@ static int process_my_load_module(struct ast_config *cfg) ast_log(LOG_WARNING,"PostgreSQL Ran out of memory copying password info\n"); return AST_MODULE_LOAD_DECLINE; } + if (!(tmp = ast_variable_retrieve(cfg, "global", "appname"))) { + tmp = ""; + } + if (pgappname) { + ast_free(pgappname); + } + if (!(pgappname = ast_strdup(tmp))) { + ast_log(LOG_WARNING,"PostgreSQL Ran out of memory copying appname info\n"); + return AST_MODULE_LOAD_DECLINE; + } + if (!(tmp = ast_variable_retrieve(cfg,"global","port"))) { ast_log(LOG_WARNING,"PostgreSQL database port not specified. Using default 5432.\n"); tmp = "5432"; @@ -478,7 +530,7 @@ static int process_my_load_module(struct ast_config *cfg) cel_show_user_def ? "Yes" : "No"); } - conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword); + pgsql_reconnect(); if (PQstatus(conn) != CONNECTION_BAD) { char sqlcmd[512]; char *fname, *ftype, *flen, *fnotnull, *fdef; @@ -540,6 +592,8 @@ static int process_my_load_module(struct ast_config *cfg) ast_log(LOG_ERROR, "cel_pgsql: Unable to connect to database server %s. CALLS WILL NOT BE LOGGED!!\n", pghostname); ast_log(LOG_ERROR, "cel_pgsql: Reason: %s\n", pgerror); connected = 0; + PQfinish(conn); + conn = NULL; } return AST_MODULE_LOAD_SUCCESS; } diff --git a/configs/cdr_pgsql.conf.sample b/configs/cdr_pgsql.conf.sample index 7a909105fe..286baab42f 100644 --- a/configs/cdr_pgsql.conf.sample +++ b/configs/cdr_pgsql.conf.sample @@ -10,6 +10,7 @@ ;dbname=asterisk ;password=password ;user=postgres -;table=cdr ;SQL table where CDRs will be inserted -;encoding=LATIN9 ; Encoding of logged characters in Asterisk -;timezone=UTC ; Uncomment if you want datetime fields in UTC/GMT +;appname=asterisk ; Postgres application_name support (optional). Whitespace not allowed. +;table=cdr ; SQL table where CDRs will be inserted +;encoding=LATIN9 ; Encoding of logged characters in Asterisk +;timezone=UTC ; Uncomment if you want datetime fields in UTC/GMT diff --git a/configs/cel_pgsql.conf.sample b/configs/cel_pgsql.conf.sample index cc9b9ff91a..10e3285ecb 100644 --- a/configs/cel_pgsql.conf.sample +++ b/configs/cel_pgsql.conf.sample @@ -64,4 +64,5 @@ ;dbname=asterisk ;password=password ;user=postgres -;table=cel ;SQL table where CEL's will be inserted +;table=cel ; SQL table where CEL's will be inserted +;appname=asterisk ; Postgres application_name support (optional). Whitespace not allowed. diff --git a/configs/res_pgsql.conf.sample b/configs/res_pgsql.conf.sample index b889244a7e..015d68c13c 100644 --- a/configs/res_pgsql.conf.sample +++ b/configs/res_pgsql.conf.sample @@ -12,12 +12,13 @@ dbport=5432 dbname=asterisk dbuser=asterisk dbpass=password +;dbappname=asterisk ; Postgres application_name support (optional). Whitespace not allowed. ; ; dbsock is specified as the directory where the socket file may be found. The ; actual socket is constructed as a combination of dbsock and dbport. For ; example, the values of '/tmp' and '5432', respectively, will specify a socket ; file of '/tmp/.s.PGSQL.5432'. -; +; ;dbsock=/tmp ; ; requirements - At startup, each realtime family will make requirements diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index b8ab994a70..3ee5e4e78c 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -79,6 +79,7 @@ static char dbhost[MAX_DB_OPTION_SIZE] = ""; static char dbuser[MAX_DB_OPTION_SIZE] = ""; static char dbpass[MAX_DB_OPTION_SIZE] = ""; static char dbname[MAX_DB_OPTION_SIZE] = ""; +static char dbappname[MAX_DB_OPTION_SIZE] = ""; static char dbsock[MAX_DB_OPTION_SIZE] = ""; static int dbport = 5432; static time_t connect_time = 0; @@ -1436,6 +1437,12 @@ static int parse_config(int is_reload) dbport = atoi(s); } + if (!(s = ast_variable_retrieve(config, "general", "dbappname"))) { + dbappname[0] = '\0'; + } else { + ast_copy_string(dbappname, s, sizeof(dbappname)); + } + if (!ast_strlen_zero(dbhost)) { /* No socket needed */ } else if (!(s = ast_variable_retrieve(config, "general", "dbsock"))) { @@ -1499,18 +1506,27 @@ static int pgsql_reconnect(const char *database) /* DB password can legitimately be 0-length */ if ((!pgsqlConn) && (!ast_strlen_zero(dbhost) || !ast_strlen_zero(dbsock)) && !ast_strlen_zero(dbuser) && !ast_strlen_zero(my_database)) { - struct ast_str *connInfo = ast_str_create(128); + struct ast_str *conn_info = ast_str_create(128); + + if (!conn_info) { + ast_log(LOG_ERROR, "PostgreSQL RealTime: Failed to allocate memory for connection string.\n"); + return 0; + } - ast_str_set(&connInfo, 0, "host=%s port=%d dbname=%s user=%s", + ast_str_set(&conn_info, 0, "host=%s port=%d dbname=%s user=%s", S_OR(dbhost, dbsock), dbport, my_database, dbuser); - if (!ast_strlen_zero(dbpass)) - ast_str_append(&connInfo, 0, " password=%s", dbpass); - - ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); - pgsqlConn = PQconnectdb(ast_str_buffer(connInfo)); - ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo)); - ast_free(connInfo); - connInfo = NULL; + + if (!ast_strlen_zero(dbappname)) { + ast_str_append(&conn_info, 0, " application_name=%s", dbappname); + } + + if (!ast_strlen_zero(dbpass)) { + ast_str_append(&conn_info, 0, " password=%s", dbpass); + } + + pgsqlConn = PQconnectdb(ast_str_buffer(conn_info)); + ast_free(conn_info); + conn_info = NULL; ast_debug(1, "pgsqlConn=%p\n", pgsqlConn); if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {