Description:
The connection is open and working between a client program and a remote mysql server.
When the server is down, mysql_ping is called every seconds in order to try to re-establish the connection (called lauched by an interruption).
After a random number of unsuccessfull tries (it could take 30 minutes), the client hangs up.
It seems to be a problem only while accessing a remote server. Valgrind 1.0.2 return some memory management errors in calls to libmysqlclient:
==22617== Invalid read of size 4
==22617== at 0x40269180: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x40264362: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin)
==22617== Address 0x42C394BC is 12 bytes inside a block of size 84 free'd
==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so)
==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026900D: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026449A: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617==
==22617== Invalid write of size 1
==22617== at 0x4003BF30: memcpy (vg_clientfuncs.c:509)
==22617== by 0x40264394: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin)
==22617== Address 0x42C39A80 is 0 bytes inside a block of size 8192 free'd
==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so)
==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x402687F5: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x402644B1: (within /usr/lib/libmysqlclient.so.10.0.0)
How to repeat:
here is my test program (adapt the sql server/table/fields in order to match your installation):
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include "/usr/include/mysql/mysql.h"
#define SQL_QUERY_LENGHT 256
/* global variables */
/*the declaration order is important, for data alignement issues */
FILE *std_msg;
FILE *std_err;
int flag_alrm;
/*************************************************/
/* global variables */
char sql_buf1[SQL_QUERY_LENGHT],sql_buf2[SQL_QUERY_LENGHT],sql_query[SQL_QUERY_LENGHT]; /* in case of an SQL logging, we will need some buffers */
MYSQL mysql;
/*************************************************/
/* functions */
int sql_init() {
/* initialization of the sql database connection */
/* return EXIT_SUCCESS or EXIT_FAILURE */
mysql_init(&mysql);
if (!mysql_real_connect(&mysql,"bicron","test","test","test",0,NULL,0)) {
fprintf(stderr, "sql_init: Failed to connect to database: Error: %s\n", mysql_error(&mysql));
}
if (mysql_select_db(&mysql,"test")) {
fprintf(stderr,"sql_init: Couldn't select database %s!\n%s\n","test", mysql_error(&mysql));
}
return EXIT_SUCCESS;
}
int sql_query_log() {
/* build and send an sql query to the sql server in order to log data fro ALL probes */
/* return EXIT_SUCCESS or EXIT_FAILURE */
/* we need to build a string like 'INSERT into table (field1,field2) values (value1,value2)' */
int number,probe_index;
sql_buf1[0]='\0';
sql_buf2[0]='\0';
number=snprintf(sql_query,(size_t)(SQL_QUERY_LENGHT*sizeof(char)),"INSERT into test (timestamps) values (now())");
if(number <= -1 || number >= (int)(SQL_QUERY_LENGHT*sizeof(char))) {
perror("sql_query: final query string building failure\n");
return EXIT_FAILURE;
}
fprintf(stdout,"Query=%s\n",sql_query);
fprintf(stderr,"mysql=%ld\n",mysql);
/* checking that the database is still there and if not, trying to reconnect */
if(mysql_ping(&mysql)){
//fprintf(std_err,"Trying to reconnect to the database...\n");
if(sql_init()== EXIT_FAILURE) {
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
if(mysql_query(&mysql,sql_query))
{
fprintf(stderr,"Query \"%s\" failed for %s@%s (%s)\n",sql_query,"test","localhost",mysql_error(&mysql));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void sig_alrm(void) {
/* function called when a SIGALRM signal is catched */
flag_alrm=1;
}
int timer_init(long write_timer_duration) {
/* this is the initialization of signal catching and timer */
/* return EXIT_SUCCES or EXIT_FAILURE */
struct itimerval timer_parameters; /* parameters for the timer, in order to calculate cpm, dose... */
struct sigaction timer_act; /* for signal catching (for the timer) */
/* we want to catch the signal SIGALRM in order to use it as a timer */
timer_act.sa_handler=(void *)sig_alrm;
/* We don't want to block any other signals */
sigemptyset(&timer_act.sa_mask);
if (sigaction(SIGALRM,&timer_act,NULL) != EXIT_SUCCESS) {
perror("timer_init: signal catching failed for SIGALRM");
return EXIT_FAILURE;
}
/* setting up a timer, which is going to send SIGALRM every average_length seconds */
timer_parameters.it_value.tv_sec=0;
timer_parameters.it_value.tv_usec=write_timer_duration;
timer_parameters.it_interval.tv_sec=0;
timer_parameters.it_interval.tv_usec=write_timer_duration;
flag_alrm=0;
if((setitimer (ITIMER_REAL,&timer_parameters,NULL)) != EXIT_SUCCESS) {
perror("timer_init: timer setup failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int sequencer_init(void) {
/* starting signal catching and timer */
/* return EXIT_SUCCESS or EXIT_FAILURE */
struct timeval timeout; /* time out structure for "select" */
if(timer_init(10000) == EXIT_FAILURE) {
perror("sequencer_init: Timer initialization failure");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/* ******************************************************************************************* */
main(int argn,char *argv[]){
int flag_stop;
/* initializations */
std_msg=stdout;
std_err=stderr;
flag_stop=0;
/* MySQL initialization if necessary */
if(sql_init()== EXIT_FAILURE) return EXIT_FAILURE;
/* launching sequencer (timer+signal catching) */
if(sequencer_init()== EXIT_FAILURE) return EXIT_FAILURE;
do {
if(flag_alrm==1) {
sql_query_log();
flag_alrm=0;
}
} while (!flag_stop);
/* stopping MySQL if necessary */
//mysql_close(&settings.mysql);
/*****************************************************************************************************/
/* ending the program */
return EXIT_SUCCESS;
}
Suggested fix:
Check memory access in mysql_ping/mysql_real_connect/mysql_select_db !