Implement timeout, caching (for OpenLDAP) and sorting during searches.

Known bug: cache enabled is known to cause Tcl to abort upon exit.
This commit is contained in:
Randy Kunkee 1999-10-26 22:13:08 +00:00
parent 3261f219a3
commit f4f48b1a80

View File

@ -23,7 +23,7 @@
* Requests for permission may be sent to NeoSoft Inc, 1770 St. James Place,
* Suite 500, Houston, TX, 77056.
*
* $Id: neoXldap.c,v 1.4 1999/07/27 05:29:27 kunkee Exp $
* $Id: neoXldap.c,v 1.5 1999/08/03 05:23:03 kunkee Exp $
*
*/
@ -107,9 +107,13 @@
typedef struct ldaptclobj {
LDAP *ldap;
int flags
int caching; /* flag 1/0 if caching is enabled */
long timeout; /* timeout from last cache enable */
long maxmem; /* maxmem from last cache enable */
int flags;
} LDAPTCL;
#define LDAPTCL_INTERRCODES 0x001
#include "ldaptclerr.h"
@ -149,7 +153,7 @@ LDAP_SetErrorCode(LDAPTCL *ldaptcl, int code, Tcl_Interp *interp)
* o TCL_ERROR if an error occured, with error message in interp.
*-----------------------------------------------------------------------------
*/
static int
int
LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
Tcl_Interp *interp;
LDAP *ldap;
@ -244,8 +248,9 @@ LDAP_ProcessOneSearchResult (interp, ldap, entry, destArrayNameObj, evalCodeObj)
* o TCL_ERROR if an error occured, with error message in interp.
*-----------------------------------------------------------------------------
*/
static int
LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destArrayNameObj, evalCodeObj, timeout_p)
int
LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value,
destArrayNameObj, evalCodeObj, timeout_p, all, sortattr)
Tcl_Interp *interp;
LDAPTCL *ldaptcl;
char *base;
@ -256,6 +261,8 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destAr
Tcl_Obj *destArrayNameObj;
Tcl_Obj *evalCodeObj;
struct timeval *timeout_p;
int all;
char *sortattr;
{
LDAP *ldap = ldaptcl->ldap;
char filter[BUFSIZ];
@ -266,6 +273,7 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destAr
int msgid;
LDAPMessage *resultMessage;
LDAPMessage *entryMessage;
char *sortKey;
Tcl_Obj *resultObj;
int lderrno;
@ -274,6 +282,7 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destAr
sprintf(filter, filtpatt, value);
fflush(stderr);
if ((msgid = ldap_search (ldap, base, scope, filter, attrs, 0)) == -1) {
Tcl_AppendStringsToObj (resultObj,
"LDAP start search error: ",
@ -284,73 +293,87 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destAr
}
abandon = 0;
while ((resultCode = ldap_result (ldap,
msgid,
0,
timeout_p,
&resultMessage)) == LDAP_RES_SEARCH_ENTRY) {
if (sortattr)
all = 1;
tclResult = TCL_OK;
while (!abandon) {
resultCode = ldap_result (ldap, msgid, all, timeout_p, &resultMessage);
if (resultCode != LDAP_RES_SEARCH_RESULT &&
resultCode != LDAP_RES_SEARCH_ENTRY)
break;
if (sortattr) {
sortKey = (strcasecmp(sortattr, "dn") == 0) ? NULL : sortattr;
ldap_sort_entries(ldap, &resultMessage, sortKey, strcasecmp);
}
entryMessage = ldap_first_entry(ldap, resultMessage);
tclResult = LDAP_ProcessOneSearchResult (interp,
ldap,
entryMessage,
destArrayNameObj,
evalCodeObj);
while (entryMessage) {
tclResult = LDAP_ProcessOneSearchResult (interp,
ldap,
entryMessage,
destArrayNameObj,
evalCodeObj);
if (tclResult != TCL_OK) {
if (tclResult == TCL_CONTINUE) {
tclResult = TCL_OK;
} else if (tclResult == TCL_BREAK) {
tclResult = TCL_OK;
abandon = 1;
break;
} else if (tclResult == TCL_ERROR) {
char msg[100];
sprintf(msg, "\n (\"search\" body line %d)",
interp->errorLine);
Tcl_AddObjErrorInfo(interp, msg, -1);
abandon = 1;
break;
} else {
abandon = 1;
break;
}
}
entryMessage = ldap_next_entry(ldap, entryMessage);
}
if (resultCode == LDAP_RES_SEARCH_RESULT || all)
break;
ldap_msgfree(resultMessage);
}
if (abandon) {
ldap_msgfree(resultMessage);
if (tclResult != TCL_OK) {
if (tclResult == TCL_CONTINUE) {
tclResult = TCL_OK;
} else if (tclResult == TCL_BREAK) {
tclResult = TCL_OK;
abandon = 1;
break;
} else if (tclResult == TCL_ERROR) {
char msg[100];
sprintf(msg, "\n (\"search\" body line %d)",
interp->errorLine);
Tcl_AddObjErrorInfo(interp, msg, -1);
abandon = 1;
break;
} else {
abandon = 1;
break;
}
}
if (resultCode == LDAP_RES_SEARCH_ENTRY)
ldap_abandon(ldap, msgid);
return tclResult;
}
if (abandon || resultCode == 0) {
ldap_abandon(ldap, msgid);
if (resultCode == 0) {
Tcl_SetErrorCode (interp, "TIMEOUT", (char*) NULL);
Tcl_SetStringObj (resultObj, "LDAP timeout retrieving results", -1);
return TCL_ERROR;
}
} else {
if (resultCode == LDAP_RES_SEARCH_RESULT) {
if ((errorCode = ldap_result2error (ldap, resultMessage, 0))
!= LDAP_SUCCESS) {
Tcl_AppendStringsToObj (resultObj,
"LDAP search error: ",
ldap_err2string(errorCode),
(char *)NULL);
ldap_msgfree(resultMessage);
LDAP_SetErrorCode(ldaptcl, errorCode, interp);
return TCL_ERROR;
}
}
if (resultCode == -1) {
Tcl_AppendStringsToObj (resultObj,
"LDAP result search error: ",
LDAP_ERR_STRING(ldap),
(char *)NULL);
LDAP_SetErrorCode(ldaptcl, -1, interp);
return TCL_ERROR;
} else
ldap_msgfree(resultMessage);
if (resultCode == -1) {
Tcl_AppendStringsToObj (resultObj,
"LDAP result search error: ",
LDAP_ERR_STRING(ldap),
(char *)NULL);
LDAP_SetErrorCode(ldaptcl, -1, interp);
return TCL_ERROR;
}
if (resultCode == 0) {
Tcl_SetErrorCode (interp, "TIMEOUT", (char*) NULL);
Tcl_SetStringObj (resultObj, "LDAP timeout retrieving results", -1);
return TCL_ERROR;
}
/*
if (resultCode == LDAP_RES_SEARCH_RESULT ||
(all && resultCode == LDAP_RES_SEARCH_ENTRY))
return tclResult;
*/
if ((errorCode = ldap_result2error (ldap, resultMessage, 0))
!= LDAP_SUCCESS) {
Tcl_AppendStringsToObj (resultObj,
"LDAP search error: ",
ldap_err2string(errorCode),
(char *)NULL);
ldap_msgfree(resultMessage);
LDAP_SetErrorCode(ldaptcl, errorCode, interp);
return TCL_ERROR;
}
return tclResult;
}
@ -366,7 +389,7 @@ LDAP_PerformSearch (interp, ldaptcl, base, scope, attrs, filtpatt, value, destAr
* See the user documentation.
*-----------------------------------------------------------------------------
*/
static int
int
NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
ClientData clientData;
Tcl_Interp *interp;
@ -383,6 +406,7 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
int mod_op = 0;
char *m, *s, *errmsg;
int errcode;
int tclResult;
Tcl_Obj *resultObj = Tcl_GetObjResult (interp);
@ -620,6 +644,8 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
result = ldap_add_s (ldap, dn, modArray);
} else {
result = ldap_modify_s (ldap, dn, modArray);
if (ldaptcl->caching)
ldap_uncache_entry (ldap, dn);
}
/* free the modArray elements, then the modArray itself. */
@ -666,6 +692,12 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
double timeoutTime;
struct timeval timeout, *timeout_p;
char *paramString;
int cacheThis = -1;
int all = 0;
char *sortattr;
Tcl_Obj *destArrayNameObj;
Tcl_Obj *evalCodeObj;
@ -795,6 +827,20 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
timeout_p = &timeout;
}
paramString = Tcl_GetVar2 (interp, controlArrayName, "cache", 0);
if (paramString) {
if (Tcl_GetInt(interp, paramString, &cacheThis) == TCL_ERROR)
return TCL_ERROR;
}
paramString = Tcl_GetVar2 (interp, controlArrayName, "all", 0);
if (paramString) {
if (Tcl_GetInt(interp, paramString, &all) == TCL_ERROR)
return TCL_ERROR;
}
sortattr = Tcl_GetVar2 (interp, controlArrayName, "sort", 0);
#ifdef UMICH_LDAP
ldap->ld_deref = deref;
ldap->ld_timelimit = 0;
@ -802,7 +848,21 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
ldap->ld_options = 0;
#endif
return LDAP_PerformSearch (interp,
/* Caching control within the search: if the "cache" control array */
/* value is set, disable/enable caching accordingly */
if (cacheThis >= 0 && ldaptcl->caching != cacheThis) {
if (cacheThis) {
if (ldaptcl->timeout == 0) {
Tcl_SetStringObj(resultObj, "Caching never before enabled, I have no timeout value to use", -1);
return TCL_ERROR;
}
ldap_enable_cache(ldap, ldaptcl->timeout, ldaptcl->maxmem);
}
else
ldap_disable_cache(ldap);
}
tclResult = LDAP_PerformSearch (interp,
ldaptcl,
baseString,
scope,
@ -811,7 +871,18 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
"",
destArrayNameObj,
evalCodeObj,
timeout_p);
timeout_p,
all,
sortattr);
/* Following the search, if we changed the caching behavior, change */
/* it back. */
if (cacheThis >= 0 && ldaptcl->caching != cacheThis) {
if (cacheThis)
ldap_disable_cache(ldap);
else
ldap_enable_cache(ldap, ldaptcl->timeout, ldaptcl->maxmem);
}
return tclResult;
}
#if defined(UMICH_LDAP) || (defined(OPEN_LDAP) && !defined(LDAP_API_VERSION))
@ -840,19 +911,28 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
}
if (STREQU (cacheCommand, "enable")) {
long timeout;
long maxmem;
long timeout = ldaptcl->timeout;
long maxmem = ldaptcl->maxmem;
if (objc != 5)
if (objc > 5)
return TclX_WrongArgs (interp,
objv [0],
"cache enable timeout maxmem");
"cache enable ?timeout? ?maxmem?");
if (Tcl_GetLongFromObj (interp, objv [3], &timeout) == TCL_ERROR)
if (objc > 3) {
if (Tcl_GetLongFromObj (interp, objv [3], &timeout) == TCL_ERROR)
return TCL_ERROR;
}
if (timeout == 0) {
Tcl_SetStringObj(resultObj,
objc > 3 ? "timeouts must be greater than 0" :
"no previous timeout to reference", -1);
return TCL_ERROR;
}
if (Tcl_GetLongFromObj (interp, objv [4], &maxmem) == TCL_ERROR)
return TCL_ERROR;
if (objc > 4)
if (Tcl_GetLongFromObj (interp, objv [4], &maxmem) == TCL_ERROR)
return TCL_ERROR;
if (ldap_enable_cache (ldap, timeout, maxmem) == -1) {
Tcl_AppendStringsToObj (resultObj,
@ -862,6 +942,9 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
LDAP_SetErrorCode(ldaptcl, -1, interp);
return TCL_ERROR;
}
ldaptcl->caching = 1;
ldaptcl->timeout = timeout;
ldaptcl->maxmem = maxmem;
return TCL_OK;
}
@ -869,11 +952,13 @@ NeoX_LdapTargetObjCmd (clientData, interp, objc, objv)
if (STREQU (cacheCommand, "disable")) {
ldap_disable_cache (ldap);
ldaptcl->caching = 0;
return TCL_OK;
}
if (STREQU (cacheCommand, "destroy")) {
ldap_destroy_cache (ldap);
ldaptcl->caching = 0;
return TCL_OK;
}
@ -1083,6 +1168,9 @@ NeoX_LdapObjCmd (clientData, interp, objc, objv)
ldaptcl = (LDAPTCL *) ckalloc(sizeof(LDAPTCL));
ldaptcl->ldap = ldap;
ldaptcl->caching = 0;
ldaptcl->timeout = 0;
ldaptcl->maxmem = 0;
ldaptcl->flags = 0;
Tcl_CreateObjCommand (interp,