Hi all,
While running freeradius with a sybase backend, I've found a few errors:
1. It incorrectly returns the number of rows modified by a query. This means
that a successful query from a start/stop record
always runs the alternate start/stop query also. This is generally a
waste of resources and also can bring on problem 2.
2. If a query fails (eg: an insert for a duplicate start packet fails
because the primary key already exists) then the
sql connection is not freed properly and all subsequent packets handled
by this connection also fail.
----------- The logs following the incorrectly cleaned sql connection look
like --------------
rlm_sql (sql): Reserving sql socket id: 8
UPDATE radacct SET AcctInputOctets = 11067595, AcctOutputOctets = 0,
FramedIPAddress = '10.2.0.108', LastModified=getDate() WHERE AcctUniqueId =
'a8eca4a08dd2f7c0' AND AcctSessionId = '000A013E' AND UserName = 'xxxxxxxx'
AND NASIPAddress= '192.168.1.1' AND AcctStopTime IS NULL
Client Library error:
severity(0) number(49) origin(1) layer(1)
ct_send(): user api layer: external error: This routine cannot be called
because another command structure has results pending.
rlm_sql_sybase(sql_query): Unable to send command (ct_send())
rlm_sql (sql): Couldn't update SQL accounting for ALIVE packet -
rlm_sql (sql): Released sql socket id: 8
-----------------------------------------------------
Below is a patch to fix these problems. It's a patch against v0.9.1 but it will work against the current version 0.9.3.
Out of interest does anyone else out there actually use sybase as backend
for freeradius?
If so I'd be interested to here from you.
You can email me at <myfirstname>.<mylastname>@unsw.edu.au. (I hate spam)
Regards, - Hindrik
------------------------------------------------- Hindrik Buining Senior Network Services Engineer Communications Unit University of New South Wales Sydney, Australia +61-2-9385-1144(w) +61-2-9385-1112(f) --------------------------------------------------
*** src/modules/rlm_sql/drivers/rlm_sql_sybase/sql_sybase.c Thu Jul 17 00:35:31 2003 --- sql_sybase.c Thu Dec 4 14:39:07 2003 *************** *** 26,31 **** --- 26,32 ---- char **results; int id; int in_use; + int lastcmd_row_count; struct timeval tv; } rlm_sql_sybase_sock;
***************
*** 169,175 ****
/* Allocate a CS context structure. This should really only be done once,
but because of
the connection pooling design of rlm_sql, we'll have to go with one
context per connection */
! if (cs_ctx_alloc(CS_VERSION_100, &sybase_sock->context) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate CS
context structure (cs_ctx_alloc())");
return -1;
}
--- 170,176 ----
/* Allocate a CS context structure. This should really only be done once,
but because of
the connection pooling design of rlm_sql, we'll have to go with one
context per connection */
! if (cs_ctx_alloc(CS_CURRENT_VERSION, &sybase_sock->context) !=
CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to allocate CS
context structure (cs_ctx_alloc())");
return -1;
}
***************
*** 176,182 ****/* Initialize ctlib */
! if (ct_init(sybase_sock->context, CS_VERSION_100) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize
Client-Library (ct_init())");
if (sybase_sock->context != (CS_CONTEXT *)NULL) {
cs_ctx_drop(sybase_sock->context);
--- 177,184 ----/* Initialize ctlib */
!
! if (ct_init(sybase_sock->context, CS_CURRENT_VERSION) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_init_socket): Unable to initialize
Client-Library (ct_init())");
if (sybase_sock->context != (CS_CONTEXT *)NULL) {
cs_ctx_drop(sybase_sock->context);
***************
*** 302,308 ****
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
! CS_RETCODE ret, results_ret; CS_INT result_type;
if (config->sqltrace) --- 304,310 ----
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
! CS_RETCODE ret, results_ret, retcode; CS_INT result_type;
if (config->sqltrace) *************** *** 320,326 ****
if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM,
CS_UNUSED) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to initiate command
structure (ct_command())\n%s",
! sql_error(sqlsocket, config));
return -1;
}
--- 322,332 ----
if (ct_command(sybase_sock->command, CS_LANG_CMD, querystr, CS_NULLTERM,
CS_UNUSED) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to initiate command
structure (ct_command())\n%s",
! sql_error(sqlsocket, config));
! retcode = ct_cmd_drop(sybase_sock->command);
! if( retcode != CS_SUCCEED) {
! radlog(L_ERR, "rlm_sql_sybase(sql_query): Error droping command. code
[%d]", retcode);
! }
return -1;
}
***************
*** 327,332 ****
--- 333,343 ----
if (ct_send(sybase_sock->command) != CS_SUCCEED) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Unable to send command
(ct_send())\n%s",
sql_error(sqlsocket, config));
+
+ retcode = ct_cmd_drop(sybase_sock->command);
+ if( retcode != CS_SUCCEED) {
+ radlog(L_ERR, "rlm_sql_sybase(sql_query): Error droping command. code
[%d]", retcode);
+ }
return -1;
}
*************** *** 335,340 **** --- 346,359 ---- ** thirdly to get a "nothing left to handle" status. */
+ /* Hindrik - Sept 03
+ * According to Sybase Open Client Client-Library C Ref Manual (pg497)
+ * we should call ct_res_info to get the the row count
+ * straight after we call ct_results the 1st time for insert/update
queries.
+ * If we try to get the row count after a result_type CS_CMD_DONE
+ * then we get an error.
+ */
+
/*
** First call to ct_results,
** we need returncode CS_SUCCEED
***************
*** 348,353 ****
--- 367,378 ----
}
radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected
result type from query\n%s",
sql_error(sqlsocket, config));
+ retcode = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
+ if( retcode != CS_SUCCEED ) {
+ radlog(L_ERR,"rlm_sql_sybase(sql_query): ct_cancel() failed! Closing
connection.");
+ ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
+ sql_close(sqlsocket, config);
+ }
return -1;
}
}
***************
*** 363,368 ****
--- 388,394 ----
ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
sql_close(sqlsocket, config);
}
+
return -1;
break;
***************
*** 384,391 ****
--- 410,433 ----
if (result_type != CS_CMD_DONE) {
radlog(L_ERR,"rlm_sql_sybase(sql_query): Result failure or unexpected
result type from query\n%s",
sql_error(sqlsocket, config));
+ retcode = ct_cancel(NULL, sybase_sock->command, CS_CANCEL_ALL);
+ if( retcode != CS_SUCCEED ) {
+ radlog(L_ERR,"rlm_sql_sybase(sql_query): ct_cancel() failed! Closing
connection.");
+ ct_close(sybase_sock->connection, CS_FORCE_CLOSE);
+ sql_close(sqlsocket, config);
+ }
return -1;
}
+ /* We need to get the row count now, before we call ct_results again.
+ * So we store the value inside the sybase_sock structure.
+ */
+ if (ct_res_info(sybase_sock->command, CS_ROW_COUNT,
+ (CS_INT *)&sybase_sock->lastcmd_row_count,
+ CS_UNUSED, NULL) != CS_SUCCEED) {
+ radlog(L_ERR,"rlm_sql_sybase(sql_query): error retrieving row count:
%s",
+ sql_error(sqlsocket, config));
+ return -1;
+ }
}
else {
switch ((int) results_ret)
***************
*** 644,655 ****
rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn;
int num;
! if (ct_res_info(sybase_sock->command, CS_ROW_COUNT, (CS_INT *)&num,
CS_UNUSED, NULL) != CS_SUCCEED) {
! radlog(L_ERR,"rlm_sql_sybase(sql_num_rows): error retrieving row count:
%s",
! sql_error(sqlsocket, config));
! return -1;
}
return num;
}
--- 686,709 ---- rlm_sql_sybase_sock *sybase_sock = sqlsocket->conn; int num;
! /* We can't call ct_res_info now, because we've already finished with
! * the results in sql_query (ie: called ct_results and got back
CS_END_RESULTS
! */
! /* if (ct_res_info(sybase_sock->command, CS_ROW_COUNT, (CS_INT *)&num,
CS_UNUSED, NULL) != CS_SUCCEED) { */
! /* radlog(L_ERR,"rlm_sql_sybase(sql_num_rows): error retrieving row
count: %s", */
! /* sql_error(sqlsocket, config)); */
! /* return -1; */
! /* } */
!
! if( sybase_sock->lastcmd_row_count == CS_NO_COUNT ) {
! radlog(L_ERR, "rlm_sql_sybase(sql_num_rows): No row count data
available");
! return -1;
}
+
+ num = sybase_sock->lastcmd_row_count;
+ sybase_sock->lastcmd_row_count = CS_NO_COUNT;
return num;
+
}
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
