[idms-dbma-devel]: COMMIT - r92 - branches/nonblocking_auth/modules/auth/pgsql
Status: Pre-Alpha
Brought to you by:
nkukard
|
From: <sv...@li...> - 2005-04-04 08:53:28
|
Author: nkukard
Date: 2005-04-04 08:53:07 +0000 (Mon, 04 Apr 2005)
New Revision: 92
Modified:
branches/nonblocking_auth/modules/auth/pgsql/pgsql.c
Log:
* Current work on the non-blocking authentication
* THIS CODE DOES NOT BUILD!
Modified: branches/nonblocking_auth/modules/auth/pgsql/pgsql.c
===================================================================
--- branches/nonblocking_auth/modules/auth/pgsql/pgsql.c 2005-04-04 08:45:54 UTC (rev 91)
+++ branches/nonblocking_auth/modules/auth/pgsql/pgsql.c 2005-04-04 08:53:07 UTC (rev 92)
@@ -1,6 +1,6 @@
/*
* pgsql.c - PostgreSQL Database Authentication Module
- * Copyright (C) 2002-2004, Linux Based Systems Design
+ * Copyright (C) 2002-2005, Linux Based Systems Design
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,16 +17,288 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
+ * 29/03/2005 - Nigel Kukard <nk...@lb...>
+ * * Non-blocking queueable authentication added
+ *
* 24/05/2004 - Nigel Kukard <nk...@lb...>
* * Reworked design
*/
+#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "modules.h"
+#define PGSQL_STATE_CONN 1
+#define PGSQL_STATE_IDLE 2
+#define PGSQL_STATE_AUTH 3
+
+#define PGSQL_IODIR_WRITE 1
+#define PGSQL_IODIR_READ 2
+
+/* Database connection structure */
+struct dbConnection_t
+{
+ PGconn *pgConn; /* Actual pgsql connection struct */
+ int sock; /* Socket descriptor of connection */
+ int state; /* State of connection - to us */
+};
+
+
+/* User definable vars */
+unsigned int maxDBConns = 5;
+
+
+
+/*
+ * Static stuff we need
+ */
+
+static GList *authQueue = NULL; /* Queue of auth requests waiting to be processed */
+
+static GList *idleConns = NULL; /* Currently idle database connections */
+static GList *activeConns = NULL; /* Connections currently processing an auth request */
+
+static fd_set inputFDs;
+static fd_set outputFDs;
+static int workerPipe[2];
+static int pipeStatus;
+
+
+/* PGSQL authentication thread */
+static gpointer pgsql_auth_thread(gpointer data)
+{
+ struct timeval tv, tmp_tv;
+ unsigned char result = 1;
+
+
+ fprintf(stderr,"Starting authentication pipe()\n");
+ pipe(workerPipe);
+ /* Watch our file descriptor */
+ FD_ZERO(&inputFDs);
+ FD_ZERO(&outputFDs);
+ FD_SET(workerPipe[0],&inputFDs);
+ /* Set the timeout period, we use this so we can detect closed connections easily */
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ /* Loop for all our partial output */
+ while (result == 1)
+ {
+ fd_set tmp_wfds;
+ fd_set tmp_rfds;
+ int retVal;
+ GList *item;
+
+
+ /* Restore our params... */
+ tmp_wfds = outputFDs;
+ tmp_rfds = inputFDs;
+ tmp_tv = tv;
+
+ /* Do select() */
+ retVal = select(FD_SETSIZE, &tmp_rfds, &tmp_wfds, NULL, &tmp_tv);
+
+ /* And find result... */
+ switch (retVal)
+ {
+ case -1:
+ /* Check if we've been interrupted */
+ if (errno == EINTR)
+ {
+ D_PRINT(D_NOTICE,"select() interrupted by system call");
+ result = D_NOTICE;
+ }
+ else
+ {
+ D_PRINT(D_ERROR,"select() error: %s",strerror(errno));
+ result = D_ERROR;
+ }
+ break;
+
+ /* Nothing changed, so process only timeout stuff */
+ case 0:
+ // FIXME - close OLD pgsql connections which we havn't used
+ D_PRINT(D_NOTICE,"select() timeout");
+ break;
+
+
+
+ /* Something changed... process */
+ default:
+ /* Check if we were triggered to process another auth request */
+ if (FD_ISSET(workerPipe[0],&tmp_rfds))
+ {
+ char tmpBuf[SOCK_IO_BUF_LEN];
+
+
+ read(workerPipe[0],&tmpBuf,SOCK_IO_BUF_LEN);
+ D_PRINT(D_DEBUG,"Triggered request");
+
+ /* Check if we have a active free pgsql connection */
+ if (g_list_length(idleConns) > 0)
+ {
+ GList *item;
+
+ /* Grab first idle connection */
+ item = g_list_first(idleConns);
+ /* Check if its ok */
+ if ((dbConn = (struct dbConnection_t) item->data))
+ {
+ // FIXME - find an available connection that is OK
+ if (PQstatus(dbConn->pgConn) == CONNECTION_OK)
+ {
+ dbConn->state = PGSQL_STATE_AUTH;
+ dbConn->authRequest = authReq;
+ }
+ else
+ {
+ D_PRINT(D_ERROR,"Connection bad");
+ PQfinish(dbConn->pgConn);
+ }
+ }
+ else
+ D_PRINT(D_FATAL,"item->data is NULL");
+ }
+ /* We can establish another connection */
+ else if (g_list_length(activeConns) < maxDBConns)
+ {
+ /* Allocate some memory for our connection info */
+ if ((dbConn = malloc(sizeof(struct dbConnection_t))))
+ {
+ /* Connect to database */
+ if ((dbConn->pgConn = PQconnectStart("connection_info_string")))
+ {
+ int status;
+
+
+ /* Check if we connected OK */
+ if ((status = PQstatus(dbConn->pgConn)) != CONNECTION_BAD)
+ {
+ int res;
+
+
+ /* Set full non-blocking */
+ if ((res = PQsetnonblocking(dbConn->pgConn,1)) != 0)
+ {
+ // FIXME - proper error handling?
+ D_PRINT(D_ERROR,"Error setting full non-blocking on pgsql conneciton: %i",res);
+ }
+
+ /* Grab database socket & set state to connecting */
+ dbConn->sock = PQsocket(dbConn->pgConn);
+ dbConn->state = PGSQL_STATE_CONN;
+ dbConn->ioDir = PGSQL_IODIR_WRITE;
+
+ /* Assign auth request to DB connection */
+ dbConn->authRequest = authReq;
+
+ /* Add to active list */
+ activeConns = g_list_append(activeConns,dbConn);
+
+ /* Treat situation as PGRES_POLLING_WRITING */
+ FD_SET(dbConn->pgConn, &outputFDs);
+ }
+ /* If not throw an error */
+ else
+ {
+ PQfinish(dbConn->pgConn);
+
+ D_PRINT(D_ERROR,"Failed to connect to database");
+ }
+
+ {
+ else
+ {
+ free(dbConn);
+
+ D_PRINT(D_ERROR,"Failed to connect to database server");
+ }
+ }
+ else
+ {
+ /* We are overloaded, keep in queue */
+ D_PRINT(D_NOTICE,"We are overloaded");
+ }
+
+
+ break;
+ }
+
+ /* Check what changed */
+ item = g_list_first(activeQueue);
+ while (item)
+ {
+ struct dbConnection_t *dbConn;
+
+
+ /* Check if all is well */
+ if ((dbConn = item->data))
+ {
+ /* Poll connection process to database */
+ if (dbConn->state == PGSQL_STATE_CONN)
+ {
+ /* Check if our FD is in the set of changed FD's */
+ if (FD_ISSET(dbConn->fd,&tmp_wfds) || FD_ISSET(dbConn->fd,&tmp_rfds))
+ {
+ D_PRINT(D_DEBUG,"Something changed on the pgsql connection");
+
+ pgres = PQconnectPoll(dbConn->pgConn);
+
+ if (pgres == PGRES_POLLING_READING)
+ {
+ FD_CLR(dbConn->fd,outputFDs);
+ dbConn->ioDir = PGSQL_IODIR_READ;
+ }
+ else if (pgres = PGRES_POLLING_WRITING)
+ {
+ dbConn->ioDir = PGSQL_IODIR_WRITE;
+ }
+ else if (pgres = PGRES_POLLING_OK)
+ {
+ D_PRINT(D_NOTICE,"Connected");
+ dbConn->state = PGSQL_STATE_AUTH;
+ }
+ else if (pgres = PGRES_POLLING_FAILED)
+ {
+ D_PRINT(D_FATAL,"Failed to connect");
+ }
+ else
+ {
+ D_PRINT(D_FATAL,"Unknown result from PQconnectPoll(): %i",pgres);
+ }
+ }
+ }
+ }
+ else
+ {
+ D_PRINT(D_FATAL,"Invalid IO direction");
+ }
+ }
+ else
+ D_PRINT(D_FATAL,"item->data is NULL");
+
+ item = g_list_next(item);
+ }
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Queue authentication to be handled by PGSQL */
+void pgsql_queue_auth()
+{
+}
+
+
+
+
/* Authenticate user */
struct auth_info_t *pgsql_authenticate(char *hostname, char *realm, char *username, char *password)
{
|