Skip to Content.
Sympa Menu

freetds - tds_process_login_tokens()

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "Coleman, Dave" <DColeman AT US.TIAuto.com>
  • To: 'TDS Development Group' <freetds AT franklin.oit.unc.edu>
  • Subject: tds_process_login_tokens()
  • Date: Mon, 5 Aug 2002 16:22:44 -0400

Hello. For some time, I have been tracing a memory leak in my software.
Now don't delete or ignore this message, because I'll just send another one.
Now that you've gotten to this point, I appologize for the snappy nature of
that last sentence, but I've been ignored, and I get the feeling no one
believes me that you guys are leaking.

This leak occurs when the TDS API is used to log in and out multiple times.
I was informed some time ago that this leak was none of your concern and was
an artifact of gethostbyname(), which is obviously outside of your pervue.
I hate to inform you that this is not the case. If tds_process_login_tokens
is commented out of the login sequence, then the leak will not occur.
(obviously, no connection will be made properly either, this is the
problem). I am implementing this library for data collection on
manufacturing equipment. This requires a non-persistant connection as a
result of this environment. I have attatched a dump file. I have also
added a few messages in your code, just for my own debugging, they were
memory allocation type messages, and I swear that I have not modified any
functional code.

I have broken my connection method into two functions so that it may be
compatible with tds_connect when it is fixed. tdsDB::connectSock() is my
function. tdsDB::openDB() is an attempt to create a clean version of
tds_connect(). Here is where I have isolated the memory leak to
tds_process_login_tokens(). I do not want to mess around with your code
more than adding tdsdump_log calls for my own FYI. I would appreciate
someone with intimate knowledge of the inner workings of this part of the
API to attempt to prove or disprove this by making these modifications.

1) make t0001 in src/tds/unittests loop multiple times around the log
in/out commands.
2) comment out the if( !tds_process_login_tokens) statement.
3) do whatever is needed for t0001 to successfully run even though the
login tokens will not be processed and the connection will most likely not
be actively established. (I'd imagine that at some point a TDS_FAIL will
end up surfacing as a result of not processing tokens properly)
4) run the program, and watch it leak.

I am aware that gethostbyname() does leak. My application leaks ~3.1K the
first time the connectSock() method is called. This is avoided in the
future, because the TDSSOCKET, TDSCONFIGINFO, and TDSLOGIN are cached w/in
the class and re-used with new calls to socket() and connect().

A bunch of the extra 'free' stuff at the end of openDB() is not necessary,
it was just a vain attempt to chase the leak in places it did not exist.

Please respond with your thoughts and suggestions.

Dave Coleman
Software Engineer
TI Automotive - Meriden, CT
(203) 427-2285
dColeman AT us.tiauto.com



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
// -|> Mrdegdc 7/26/2001 1:43pm
//
// use this function to open a connection to your
// data source.
//--------------------------------------------------
int tdsDB::connectSock( void )
{
rows = 0;
if ( !initialized )
{
LOG((10,"allocating login structure\n"));
sqlLogin = tds_alloc_login();
}
if ( !sqlLogin )
{
return TDS_FAIL;
}
tds_set_version(sqlLogin,(short)4,(short)2);
tds_set_passwd(sqlLogin, pwd);
tds_set_user(sqlLogin, user);
tds_set_app(sqlLogin, hostName);
tds_set_host(sqlLogin, hostName );
tds_set_library(sqlLogin, "TDS-Library");
tds_set_server(sqlLogin, server );
tds_set_charset(sqlLogin, "iso_1");
tds_set_language(sqlLogin, "us_english");
tds_set_packet(sqlLogin, 512);
if ( !isConnected() )
{
sqlSock = openDB(sqlLogin);
}
if ( ! sqlSock )
{
loggedIn = 0;
offLine = 1;
LOG((10,"no socket found\n"));
return SQL_NO_SOCKET;
}
loggedIn = 1;
offLine = 0;
return TDS_SUCCEED;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
// -|> Mrdegdc 7/26/2001 1:52pm
//
// this function sets the state tags for the
// class object to indicate an active dababase
// connection in addition to opening a socket
// to the server.
//----------------------------------------------
TDSSOCKET* tdsDB::openDB(TDSLOGIN *login)
{
int i,j;
TDSDYNAMIC *dyn;
TDSSOCKET *tds = NULL;
static struct sockaddr_in sin;
int addrLen;

if ( !connected )
{
if ( !initialized )
{
LOG((10,"creating socket\n"));
tds = tds_alloc_socket(512);
locale = tds_get_locale();
config = tds_get_config(tds, sqlLogin,locale);
tds->major_version=config->major_version;
tds->minor_version=config->minor_version;
tds->emul_little_endian=config->emul_little_endian;
/* Jeff's hack - begin */
tds->timeout = (login->connect_timeout) ? login->query_timeout :
0;
tds->longquery_timeout = (login->connect_timeout) ?
login->longquery_timeout : 0;
tds->longquery_func = login->longquery_func;
tds->longquery_param = login->longquery_param;
/* end */
sin.sin_addr.s_addr = inet_addr(config->ip_addr);
addrLen = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(config->port);

memcpy(tds->capabilities,login->capabilities,TDS_MAX_CAPABILITY);
initialized = 1;
}
else
{
LOG((10,"re-using socket\n"));
tds = sqlSock;
tds_reset_msg_info(tds);
tds_free_all_results(tds);
}
tds->s = socket (AF_INET, SOCK_STREAM, 0);
if ( tds->s < 0 )
{
perror ("socket");
return NULL;
}
if ( connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)) < 0 )
{
perror("connect");
return NULL;
}

tds->out_flag=0x02;
tds_send_login(tds,config);

if ( !tds_process_login_tokens(tds) )
{
LOG((10,"tds_process_login_tokens failed\n"));
if ( locale->language )
{
free(locale->language);
}
if ( locale->char_set )
{
free(locale->char_set);
}
if ( locale->date_fmt )
{
free(locale->date_fmt);
}
TDS_ZERO_FREE(locale);
tds_free_config(config);
tds_free_socket(tds);
free(sqlLogin);
tds = NULL;
offLine = 1;
initialized = 0;
}
tds_reset_msg_info(tds);
tds_free_all_results(tds);
for ( i=0;i<tds->num_dyns;i++ )
{
dyn = tds->dyns[i];
if ( dyn->num_params )
{
for ( j=0;j<dyn->num_params;j++ )
{
free(dyn->params[j]);
}
free(dyn->params);
dyn->num_params = 0;
}
free(dyn);
}
if ( tds->dyns ) TDS_ZERO_FREE(tds->dyns);
tds->num_dyns = 0;
}
if ( tds )
{
loggedIn = 1;
offLine = 0;
connected = 1;
}
return tds;
}


<<tds.dump>>

Attachment: tds.dump
Description: Binary data




Archive powered by MHonArc 2.6.24.

Top of Page