Mon Apr 30 07:36:36 2007

Asterisk developer's documentation


res_config_mysql.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Copyright (C) 1999-2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>  - Asterisk Author
00007  * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
00008  *
00009  * res_config_mysql.c <mysql plugin for RealTime configuration engine>
00010  *
00011  * v2.0   - (10-07-05) - mutex_lock fixes (bug #4973, comment #0034602)
00012  *
00013  * v1.9   - (08-19-05) - Added support to correctly honor the family database specified
00014  *                       in extconfig.conf (bug #4973)
00015  *
00016  * v1.8   - (04-21-05) - Modified return values of update_mysql to better indicate
00017  *                       what really happened.
00018  *
00019  * v1.7   - (01-28-05) - Fixed non-initialization of ast_category struct
00020  *                       in realtime_multi_mysql function which caused segfault. 
00021  *
00022  * v1.6   - (00-00-00) - Skipped to bring comments into sync with version number in CVS.
00023  *
00024  * v1.5.1 - (01-26-05) - Added better(?) locking stuff
00025  *
00026  * v1.5   - (01-26-05) - Brought up to date with new config.h changes (bug #3406)
00027  *                     - Added in extra locking provided by georg (bug #3248)
00028  *
00029  * v1.4   - (12-02-04) - Added realtime_multi_mysql function
00030  *                        This function will return an ast_config with categories,
00031  *                        unlike standard realtime_mysql which only returns
00032  *                        a linked list of ast_variables
00033  *
00034  * v1.3   - (12-01-04) - Added support other operators
00035  *                       Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
00036  *
00037  * v1.2   - (11-DD-04) - Added reload. Updated load and unload.
00038  *                       Code beautification (doc/CODING-GUIDELINES)
00039  */
00040 /*** MODULEINFO
00041    <depend>mysqlclient</depend>
00042  ***/
00043 
00044 #include <asterisk.h>
00045 
00046 #include <asterisk/channel.h>
00047 #include <asterisk/logger.h>
00048 #include <asterisk/config.h>
00049 #include <asterisk/module.h>
00050 #include <asterisk/lock.h>
00051 #include <asterisk/options.h>
00052 #include <asterisk/cli.h>
00053 #include <asterisk/utils.h>
00054 #include <stdlib.h>
00055 #include <stdio.h>
00056 #include <string.h>
00057 #include <stdio.h>
00058 #include <mysql/mysql.h>
00059 #include <mysql/mysql_version.h>
00060 #include <mysql/errmsg.h>
00061 
00062 #define AST_MODULE "res_config_mysql"
00063 
00064 AST_MUTEX_DEFINE_STATIC(mysql_lock);
00065 #define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
00066 MYSQL         mysql;
00067 static char   dbhost[50];
00068 static char   dbuser[50];
00069 static char   dbpass[50];
00070 static char   dbname[50];
00071 static char   dbsock[50];
00072 static int    dbport;
00073 static int    connected;
00074 static time_t connect_time;
00075 
00076 static int parse_config(void);
00077 static int mysql_reconnect(const char *database);
00078 static int realtime_mysql_status(int fd, int argc, char **argv);
00079 
00080 static char cli_realtime_mysql_status_usage[] =
00081 "Usage: realtime mysql status\n"
00082 "       Shows connection information for the MySQL RealTime driver\n";
00083 
00084 static struct ast_cli_entry cli_realtime_mysql_status = {
00085         { "realtime", "mysql", "status", NULL }, realtime_mysql_status,
00086         "Shows connection information for the MySQL RealTime driver", cli_realtime_mysql_status_usage, NULL };
00087 
00088 static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
00089 {
00090    MYSQL_RES *result;
00091    MYSQL_ROW row;
00092    MYSQL_FIELD *fields;
00093    int numFields, i, valsz;
00094    char sql[512];
00095    char buf[511]; /* Keep this size uneven as it is 2n+1. */
00096    char *stringp;
00097    char *chunk;
00098    char *op;
00099    const char *newparam, *newval;
00100    struct ast_variable *var=NULL, *prev=NULL;
00101 
00102    if(!table) {
00103       ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
00104       return NULL;
00105    }
00106 
00107    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00108    newparam = va_arg(ap, const char *);
00109    newval = va_arg(ap, const char *);
00110    if(!newparam || !newval)  {
00111       ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00112       mysql_close(&mysql);
00113       return NULL;
00114    }
00115 
00116    /* Must connect to the server before anything else, as the escape function requires the mysql handle. */
00117    ast_mutex_lock(&mysql_lock);
00118    if (!mysql_reconnect(database)) {
00119       ast_mutex_unlock(&mysql_lock);
00120       return NULL;
00121    }
00122 
00123    /* Create the first part of the query using the first parameter/value pairs we just extracted
00124       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00125 
00126    if(!strchr(newparam, ' ')) op = " ="; else op = "";
00127 
00128    if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
00129       valsz = (sizeof(buf) - 1) / 2;
00130    mysql_real_escape_string(&mysql, buf, newval, valsz);
00131    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
00132    while((newparam = va_arg(ap, const char *))) {
00133       newval = va_arg(ap, const char *);
00134       if(!strchr(newparam, ' ')) op = " ="; else op = "";
00135       if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
00136          valsz = (sizeof(buf) - 1) / 2;
00137       mysql_real_escape_string(&mysql, buf, newval, valsz);
00138       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
00139    }
00140    va_end(ap);
00141 
00142    ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
00143 
00144    /* Execution. */
00145    if(mysql_real_query(&mysql, sql, strlen(sql))) {
00146       ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
00147       ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
00148       ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
00149       ast_mutex_unlock(&mysql_lock);
00150       return NULL;
00151    }
00152 
00153    if((result = mysql_store_result(&mysql))) {
00154       numFields = mysql_num_fields(result);
00155       fields = mysql_fetch_fields(result);
00156 
00157       while((row = mysql_fetch_row(result))) {
00158          for(i = 0; i < numFields; i++) {
00159             stringp = row[i];
00160             while(stringp) {
00161                chunk = strsep(&stringp, ";");
00162                if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
00163                   if(prev) {
00164                      prev->next = ast_variable_new(fields[i].name, chunk);
00165                      if (prev->next) {
00166                         prev = prev->next;
00167                      }
00168                   } else {
00169                      prev = var = ast_variable_new(fields[i].name, chunk);
00170                   }
00171                }
00172             }
00173          }
00174       }
00175    } else {                                
00176       ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
00177    }
00178 
00179    ast_mutex_unlock(&mysql_lock);
00180    mysql_free_result(result);
00181 
00182    return var;
00183 }
00184 
00185 static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
00186 {
00187    MYSQL_RES *result;
00188    MYSQL_ROW row;
00189    MYSQL_FIELD *fields;
00190    int numFields, i, valsz;
00191    char sql[512];
00192    char buf[511]; /* Keep this size uneven as it is 2n+1. */
00193    const char *initfield = NULL;
00194    char *stringp;
00195    char *chunk;
00196    char *op;
00197    const char *newparam, *newval;
00198    struct ast_realloca ra;
00199    struct ast_variable *var=NULL;
00200    struct ast_config *cfg = NULL;
00201    struct ast_category *cat = NULL;
00202 
00203    if(!table) {
00204       ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
00205       return NULL;
00206    }
00207    
00208    memset(&ra, 0, sizeof(ra));
00209 
00210    cfg = ast_config_new();
00211    if (!cfg) {
00212       /* If I can't alloc memory at this point, why bother doing anything else? */
00213       ast_log(LOG_WARNING, "Out of memory!\n");
00214       return NULL;
00215    }
00216 
00217    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00218    newparam = va_arg(ap, const char *);
00219    newval = va_arg(ap, const char *);
00220    if(!newparam || !newval)  {
00221       ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00222       mysql_close(&mysql);
00223       return NULL;
00224    }
00225 
00226    initfield = ast_strdupa(newparam);
00227    if(initfield && (op = strchr(initfield, ' '))) {
00228       *op = '\0';
00229    }
00230 
00231    /* Must connect to the server before anything else, as the escape function requires the mysql handle. */
00232    ast_mutex_lock(&mysql_lock);
00233    if (!mysql_reconnect(database)) {
00234       ast_mutex_unlock(&mysql_lock);
00235       return NULL;
00236    }
00237 
00238    /* Create the first part of the query using the first parameter/value pairs we just extracted
00239       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00240 
00241    if(!strchr(newparam, ' ')) op = " ="; else op = "";
00242 
00243    if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
00244       valsz = (sizeof(buf) - 1) / 2;
00245    mysql_real_escape_string(&mysql, buf, newval, valsz);
00246    snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, buf);
00247    while((newparam = va_arg(ap, const char *))) {
00248       newval = va_arg(ap, const char *);
00249       if(!strchr(newparam, ' ')) op = " ="; else op = "";
00250       if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
00251          valsz = (sizeof(buf) - 1) / 2;
00252       mysql_real_escape_string(&mysql, buf, newval, valsz);
00253       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, buf);
00254    }
00255 
00256    if(initfield) {
00257       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
00258    }
00259 
00260    va_end(ap);
00261 
00262    ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
00263 
00264    /* Execution. */
00265    if(mysql_real_query(&mysql, sql, strlen(sql))) {
00266       ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
00267       ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
00268       ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
00269       ast_mutex_unlock(&mysql_lock);
00270       return NULL;
00271    }
00272 
00273    if((result = mysql_store_result(&mysql))) {
00274       numFields = mysql_num_fields(result);
00275       fields = mysql_fetch_fields(result);
00276 
00277       while((row = mysql_fetch_row(result))) {
00278          var = NULL;
00279          cat = ast_category_new("");
00280          if(!cat) {
00281             ast_log(LOG_WARNING, "Out of memory!\n");
00282             continue;
00283          }
00284          for(i = 0; i < numFields; i++) {
00285             stringp = row[i];
00286             while(stringp) {
00287                chunk = strsep(&stringp, ";");
00288                if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
00289                   if(initfield && !strcmp(initfield, fields[i].name)) {
00290                      ast_category_rename(cat, chunk);
00291                   }
00292                   var = ast_variable_new(fields[i].name, chunk);
00293                   ast_variable_append(cat, var);
00294                }
00295             }
00296          }
00297          ast_category_append(cfg, cat);
00298       }
00299    } else {
00300       ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
00301    }
00302 
00303    ast_mutex_unlock(&mysql_lock);
00304    mysql_free_result(result);
00305 
00306    return cfg;
00307 }
00308 
00309 static int update_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
00310 {
00311    my_ulonglong numrows;
00312    char sql[512];
00313    char buf[511]; /* Keep this size uneven as it is 2n+1. */
00314    int valsz;
00315    const char *newparam, *newval;
00316 
00317    if(!table) {
00318       ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
00319                return -1;
00320    }
00321 
00322    /* Get the first parameter and first value in our list of passed paramater/value pairs */
00323    newparam = va_arg(ap, const char *);
00324    newval = va_arg(ap, const char *);
00325    if(!newparam || !newval)  {
00326       ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00327       mysql_close(&mysql);
00328                return -1;
00329    }
00330 
00331    /* Must connect to the server before anything else, as the escape function requires the mysql handle. */
00332    ast_mutex_lock(&mysql_lock);
00333    if (!mysql_reconnect(database)) {
00334       ast_mutex_unlock(&mysql_lock);
00335       return -1;
00336    }
00337 
00338    /* Create the first part of the query using the first parameter/value pairs we just extracted
00339       If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
00340 
00341    if ((valsz = strlen (newval)) * 1 + 1 > sizeof(buf))
00342       valsz = (sizeof(buf) - 1) / 2;
00343    mysql_real_escape_string(&mysql, buf, newval, valsz);
00344    snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, buf);
00345    while((newparam = va_arg(ap, const char *))) {
00346       newval = va_arg(ap, const char *);
00347       if ((valsz = strlen (newval)) * 2 + 1 > sizeof(buf))
00348          valsz = (sizeof(buf) - 1) / 2;
00349       mysql_real_escape_string(&mysql, buf, newval, valsz);
00350       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam, buf);
00351    }
00352    va_end(ap);
00353    if ((valsz = strlen (lookup)) * 1 + 1 > sizeof(buf))
00354       valsz = (sizeof(buf) - 1) / 2;
00355    mysql_real_escape_string(&mysql, buf, lookup, valsz);
00356    snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, buf);
00357 
00358    ast_log(LOG_DEBUG,"MySQL RealTime: Update SQL: %s\n", sql);
00359 
00360    /* Execution. */
00361    if(mysql_real_query(&mysql, sql, strlen(sql))) {
00362       ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
00363       ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
00364       ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
00365       ast_mutex_unlock(&mysql_lock);
00366       return -1;
00367    }
00368 
00369    numrows = mysql_affected_rows(&mysql);
00370    ast_mutex_unlock(&mysql_lock);
00371 
00372    ast_log(LOG_DEBUG,"MySQL RealTime: Updated %llu rows on table: %s\n", numrows, table);
00373 
00374    /* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
00375     * An integer greater than zero indicates the number of rows affected
00376     * Zero indicates that no records were updated
00377     * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
00378    */
00379 
00380    if(numrows >= 0)
00381       return (int)numrows;
00382 
00383    return -1;
00384 }
00385 
00386 static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg, int withcomments)
00387 {
00388    MYSQL_RES *result;
00389    MYSQL_ROW row;
00390    my_ulonglong num_rows;
00391    struct ast_variable *new_v;
00392    struct ast_category *cur_cat;
00393    char sql[250] = "";
00394    char last[80] = "";
00395    int last_cat_metric = 0;
00396 
00397    last[0] = '\0';
00398 
00399    if(!file || !strcmp(file, RES_CONFIG_MYSQL_CONF)) {
00400       ast_log(LOG_WARNING, "MySQL RealTime: Cannot configure myself.\n");
00401       return NULL;
00402    }
00403 
00404    snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
00405 
00406    ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
00407 
00408    /* We now have our complete statement; Lets connect to the server and execute it. */
00409    ast_mutex_lock(&mysql_lock);
00410    if(!mysql_reconnect(database)) {
00411       ast_mutex_unlock(&mysql_lock);
00412       return NULL;
00413    }
00414 
00415    if(mysql_real_query(&mysql, sql, strlen(sql))) {
00416       ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
00417       ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
00418       ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
00419       ast_mutex_unlock(&mysql_lock);
00420       return NULL;
00421    }
00422 
00423    if((result = mysql_store_result(&mysql))) {
00424       num_rows = mysql_num_rows(result);
00425       ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
00426 
00427       /* There might exist a better way to access the column names other than counting,
00428                    but I believe that would require another loop that we don't need. */
00429 
00430       while((row = mysql_fetch_row(result))) {
00431          if(!strcmp(row[1], "#include")) {
00432             if (!ast_config_internal_load(row[2], cfg, 0)) {
00433                mysql_free_result(result);
00434                ast_mutex_unlock(&mysql_lock);
00435                return NULL;
00436             }
00437             continue;
00438          }
00439 
00440          if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
00441             cur_cat = ast_category_new(row[0]);
00442             if (!cur_cat) {
00443                ast_log(LOG_WARNING, "Out of memory!\n");
00444                break;
00445             }
00446             strcpy(last, row[0]);
00447             last_cat_metric = atoi(row[3]);
00448             ast_category_append(cfg, cur_cat);
00449          }
00450          new_v = ast_variable_new(row[1], row[2]);
00451          ast_variable_append(cur_cat, new_v);
00452       }
00453    } else {
00454       ast_log(LOG_WARNING, "MySQL RealTime: Could not find config '%s' in database.\n", file);
00455    }
00456 
00457    mysql_free_result(result);
00458    ast_mutex_unlock(&mysql_lock);
00459 
00460    return cfg;
00461 }
00462 
00463 static struct ast_config_engine mysql_engine = {
00464    .name = "mysql",
00465    .load_func = config_mysql,
00466    .realtime_func = realtime_mysql,
00467    .realtime_multi_func = realtime_multi_mysql,
00468    .update_func = update_mysql
00469 };
00470 
00471 static int load_module(void)
00472 {
00473    parse_config();
00474 
00475    ast_mutex_lock(&mysql_lock);
00476 
00477    if(!mysql_reconnect(NULL)) {
00478       ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
00479       ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
00480    }
00481 
00482    ast_config_engine_register(&mysql_engine);
00483    if(option_verbose) {
00484       ast_verbose("MySQL RealTime driver loaded.\n");
00485    }
00486    ast_cli_register(&cli_realtime_mysql_status);
00487 
00488    ast_mutex_unlock(&mysql_lock);
00489 
00490    return 0;
00491 }
00492 
00493 static int unload_module(void)
00494 {
00495    /* Aquire control before doing anything to the module itself. */
00496    ast_mutex_lock(&mysql_lock);
00497 
00498    mysql_close(&mysql);
00499    ast_cli_unregister(&cli_realtime_mysql_status);
00500    ast_config_engine_deregister(&mysql_engine);
00501    if(option_verbose) {
00502       ast_verbose("MySQL RealTime unloaded.\n");
00503    }
00504 
00505    ast_module_user_hangup_all();
00506 
00507    /* Unlock so something else can destroy the lock. */
00508    ast_mutex_unlock(&mysql_lock);
00509 
00510    return 0;
00511 }
00512 
00513 static int reload(void)
00514 {
00515    /* Aquire control before doing anything to the module itself. */
00516    ast_mutex_lock(&mysql_lock);
00517 
00518    mysql_close(&mysql);
00519    connected = 0;
00520    parse_config();
00521 
00522    if(!mysql_reconnect(NULL)) {
00523       ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
00524       ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
00525    }
00526 
00527    ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
00528 
00529    /* Done reloading. Release lock so others can now use driver. */
00530    ast_mutex_unlock(&mysql_lock);
00531 
00532    return 0;
00533 }
00534 
00535 static int parse_config (void)
00536 {
00537    struct ast_config *config;
00538    const char *s;
00539 
00540    config = ast_config_load(RES_CONFIG_MYSQL_CONF);
00541 
00542    if(config) {
00543       if(!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
00544          ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
00545          strncpy(dbuser, "asterisk", sizeof(dbuser) - 1);
00546       } else {
00547          strncpy(dbuser, s, sizeof(dbuser) - 1);
00548       }
00549 
00550       if(!(s=ast_variable_retrieve(config, "general", "dbpass"))) {
00551                         ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
00552                         strncpy(dbpass, "asterisk", sizeof(dbpass) - 1);
00553                 } else {
00554                         strncpy(dbpass, s, sizeof(dbpass) - 1);
00555                 }
00556 
00557       if(!(s=ast_variable_retrieve(config, "general", "dbhost"))) {
00558                         ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
00559          dbhost[0] = '\0';
00560                 } else {
00561                         strncpy(dbhost, s, sizeof(dbhost) - 1);
00562                 }
00563 
00564       if(!(s=ast_variable_retrieve(config, "general", "dbname"))) {
00565                         ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
00566          strncpy(dbname, "asterisk", sizeof(dbname) - 1);
00567                 } else {
00568                         strncpy(dbname, s, sizeof(dbname) - 1);
00569                 }
00570 
00571       if(!(s=ast_variable_retrieve(config, "general", "dbport"))) {
00572                         ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
00573          dbport = 3306;
00574                 } else {
00575          dbport = atoi(s);
00576                 }
00577 
00578       if(dbhost && !(s=ast_variable_retrieve(config, "general", "dbsock"))) {
00579                         ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
00580                         strncpy(dbsock, "/tmp/mysql.sock", sizeof(dbsock) - 1);
00581                 } else {
00582                         strncpy(dbsock, s, sizeof(dbsock) - 1);
00583                 }
00584    }
00585    ast_config_destroy(config);
00586 
00587    if(dbhost) {
00588       ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
00589       ast_log(LOG_DEBUG, "MySQL RealTime Port: %i\n", dbport);
00590    } else {
00591       ast_log(LOG_DEBUG, "MySQL RealTime Socket: %s\n", dbsock);
00592    }
00593    ast_log(LOG_DEBUG, "MySQL RealTime User: %s\n", dbuser);
00594    ast_log(LOG_DEBUG, "MySQL RealTime Password: %s\n", dbpass);
00595 
00596    return 1;
00597 }
00598 
00599 static int mysql_reconnect(const char *database)
00600 {
00601    char my_database[50];
00602 #ifdef MYSQL_OPT_RECONNECT
00603    my_bool trueval = 1;
00604 #endif
00605 
00606    if(!database || ast_strlen_zero(database))
00607       ast_copy_string(my_database, dbname, sizeof(my_database));
00608    else
00609       ast_copy_string(my_database, database, sizeof(my_database));
00610 
00611    /* mutex lock should have been locked before calling this function. */
00612 
00613 reconnect_tryagain:
00614    if((!connected) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
00615       if(!mysql_init(&mysql)) {
00616          ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n");
00617          connected = 0;
00618          return 0;
00619       }
00620       if(mysql_real_connect(&mysql, dbhost, dbuser, dbpass, my_database, dbport, dbsock, 0)) {
00621 #ifdef MYSQL_OPT_RECONNECT
00622          /* The default is no longer to automatically reconnect on failure,
00623           * (as of 5.0.3) so we have to set that option here. */
00624          mysql_options(&mysql, MYSQL_OPT_RECONNECT, &trueval);
00625 #endif
00626          ast_log(LOG_DEBUG, "MySQL RealTime: Successfully connected to database.\n");
00627          connected = 1;
00628          connect_time = time(NULL);
00629          return 1;
00630       } else {
00631          ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s (err %d). Check debug for more info.\n", dbname, dbhost, mysql_errno(&mysql));
00632          ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect (%d): %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00633          connected = 0;
00634          return 0;
00635       }
00636    } else {
00637       /* MySQL likes to return an error, even if it reconnects successfully.
00638        * So the postman pings twice. */
00639       if (mysql_ping(&mysql) != 0 && mysql_ping(&mysql) != 0) {
00640          connected = 0;
00641          ast_log(LOG_ERROR, "MySQL RealTime: Ping failed (%d).  Trying an explicit reconnect.\n", mysql_errno(&mysql));
00642          ast_log(LOG_DEBUG, "MySQL RealTime: Server Error (%d): %s\n", mysql_errno(&mysql), mysql_error(&mysql));
00643          goto reconnect_tryagain;
00644       }
00645 
00646       connected = 1;
00647 
00648       if(mysql_select_db(&mysql, my_database) != 0) {
00649          ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected (%d).\n", my_database, mysql_errno(&mysql));
00650          ast_log(LOG_DEBUG, "MySQL RealTime: Database Select Failed (%d): %s\n", mysql_error(&mysql), mysql_errno(&mysql));
00651          return 0;
00652       }
00653 
00654       ast_log(LOG_DEBUG, "MySQL RealTime: Everything is fine.\n");
00655       return 1;
00656    }
00657 }
00658 
00659 static int realtime_mysql_status(int fd, int argc, char **argv)
00660 {
00661    char status[256], status2[100] = "";
00662    int ctime = time(NULL) - connect_time;
00663 
00664    if(mysql_reconnect(NULL)) {
00665       if(dbhost) {
00666          snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
00667       } else if(dbsock) {
00668          snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
00669       } else {
00670          snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
00671       }
00672 
00673       if(dbuser && *dbuser) {
00674          snprintf(status2, 99, " with username %s", dbuser);
00675       }
00676 
00677       if (ctime > 31536000) {
00678          ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00679       } else if (ctime > 86400) {
00680          ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
00681       } else if (ctime > 3600) {
00682          ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
00683       } else if (ctime > 60) {
00684          ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
00685       } else {
00686          ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
00687       }
00688 
00689       return RESULT_SUCCESS;
00690    } else {
00691       return RESULT_FAILURE;
00692    }
00693 }
00694 
00695 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MySQL RealTime Configuration Driver");

Generated on Mon Apr 30 07:36:36 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1