/** GSWSessionTimeOutManager.m - GSWeb: Class GSWSessionTimeOutManager Copyright (C) 1999-2005 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: Mar 1999 $Revision$ $Date$ $Id$ This file is part of the GNUstep Web Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/ #include "config.h" RCS_ID("$Id$") #include "GSWeb.h" #include "GSWSessionTimeOut.h" #define SESSION_TIMEOUT_TIMER_INTERVAL_MIN 15 // 15s minimum #define REFUSING_NEW_SESSION_TIMER_INTERVAL 5 // 5s minimum #define REFUSING_NEW_SESSION_APPLICATION_END 10 // 10s //==================================================================== @implementation GSWSessionTimeOutManager -(id)init { //OK if ((self=[super init])) { _sessionOrderedTimeOuts=[NSMutableArray new]; NSDebugMLLog(@"sessions",@"INIT self=%p",self); NSDebugMLLog(@"sessions",@"self=%p _sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); _sessionTimeOuts=[NSMutableDictionary new]; // selfLock=[NSRecursiveLock new]; _selfLock=[NSLock new]; }; return self; }; //-------------------------------------------------------------------- -(void)dealloc { DESTROY(_sessionOrderedTimeOuts); DESTROY(_sessionTimeOuts); //Do Not Retain ! DESTROY(target); DESTROY(_timer); DESTROY(_selfLock); [super dealloc]; }; // Must be locked -(GSWSessionTimeOut*)_sessionTimeOutForSessionID:(NSString*)sessionID { GSWSessionTimeOut* sessionTimeOut=nil; LOGObjectFnStart(); sessionTimeOut=[_sessionTimeOuts objectForKey:sessionID]; if (sessionTimeOut) { // Retain/autorelease it so it won't be destroyed too soon RETAIN(sessionTimeOut); AUTORELEASE(sessionTimeOut); } else { sessionTimeOut=[GSWSessionTimeOut timeOutWithSessionID:sessionID lastAccessTime:[NSDate timeIntervalSinceReferenceDate] sessionTimeOut:[GSWApplication sessionTimeOutValue]]; [_sessionTimeOuts setObject:sessionTimeOut forKey:sessionID]; [_sessionOrderedTimeOuts addObject:sessionTimeOut]; }; LOGObjectFnStop(); return sessionTimeOut; }; // Must not be locked -(GSWSessionTimeOut*)sessionTimeOutForSessionID:(NSString*)sessionID { GSWSessionTimeOut* sessionTimeOut=nil; LOGObjectFnStart(); [self lock]; NS_DURING { sessionTimeOut=[self _sessionTimeOutForSessionID:sessionID]; } NS_HANDLER { NSLog(@"### exception ... %@", [localException reason]); LOGException(@"%@ (%@)",localException,[localException reason]); [self unlock]; [localException raise]; } NS_ENDHANDLER; [self unlock]; LOGObjectFnStop(); return sessionTimeOut; }; //-------------------------------------------------------------------- -(void)updateTimeOutForSessionWithID:(NSString*)sessionID timeOut:(NSTimeInterval)timeOut { //OK BOOL selfLocked=NO; BOOL targetLocked=NO; LOGObjectFnStart(); [self lock]; selfLocked=YES; NS_DURING { NSTimer* timer=nil; GSWSessionTimeOut* sessionTimeOut=nil; NSDebugMLLog(@"sessions",@"timeOut=%ld s", (long)timeOut); sessionTimeOut=[self _sessionTimeOutForSessionID:sessionID]; NSDebugMLLog(@"sessions",@"sessionTimeOut=%@",sessionTimeOut); NSDebugMLLog(@"sessions",@"self=%p _sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); NSAssert(sessionTimeOut,@"No sessionTimeOut"); [_sessionOrderedTimeOuts removeObject:sessionTimeOut]; [sessionTimeOut setLastAccessTime: [NSDate timeIntervalSinceReferenceDate]]; if (timeOut!=[sessionTimeOut sessionTimeOut]) [sessionTimeOut setSessionTimeOut:timeOut]; [_sessionOrderedTimeOuts addObject:sessionTimeOut]; NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); NSDebugMLLog(@"sessions",@"sessionTimeOut=%@",sessionTimeOut); timer=[self resetTimer]; NSDebugMLLog(@"sessions",@"timer=%@",timer); NSDebugMLLog(@"sessions",@"timer fireDate=%@",[timer fireDate]); if (timer) { [_target lock]; targetLocked=YES; NS_DURING { [self addTimer:timer]; } NS_HANDLER { NSLog(@"### exception from ... addTimer... %@", [localException reason]); LOGException(@"%@ (%@)",localException,[localException reason]); NSLog(@"### exception ... %@", [localException reason]); //TODO if (targetLocked) { [_target unlock]; targetLocked=NO; }; if (selfLocked) { NSDebugMLLog(@"sessions",@"Unlock self"); [self unlock]; selfLocked=NO; }; [localException raise]; } NS_ENDHANDLER; if (targetLocked) { [_target unlock]; targetLocked=NO; }; }; } NS_HANDLER { NSLog(@"### exception ... %@", [localException reason]); LOGException(@"%@ (%@)",localException,[localException reason]); //TODO if (selfLocked) { NSDebugMLLog(@"sessions",@"Unlock self"); [self unlock]; selfLocked=NO; }; [localException raise]; } NS_ENDHANDLER; if (selfLocked) { NSDebugMLLog(@"sessions",@"Unlock self"); [self unlock]; selfLocked=NO; }; LOGObjectFnStop(); }; //-------------------------------------------------------------------- -(void)handleTimer:(id)aTimer { //OK BOOL requestHandlingLocked=NO; BOOL selfLocked=NO; BOOL targetLocked=NO; [GSWApp lockRequestHandling]; requestHandlingLocked=YES; NS_DURING { [self lock]; selfLocked=YES; NS_DURING { NSEnumerator *sessionTimeOutEnum = nil; GSWSessionTimeOut* sessionTimeOut=nil; NSTimeInterval now=[NSDate timeIntervalSinceReferenceDate]; NSTimer* timer=nil; int removedNb=0; /* if ([sessionOrderedTimeOuts count]>0) _sessionTimeOut=[sessionOrderedTimeOuts objectAtIndex:0]; */ sessionTimeOutEnum = [_sessionOrderedTimeOuts objectEnumerator]; while (/*_removedNb<20 && *//*sessionTimeOut && [sessionTimeOut timeOutTime]<_now*/ (sessionTimeOut = [sessionTimeOutEnum nextObject])) { if ([sessionTimeOut timeOutTime]0) _sessionTimeOut=[sessionOrderedTimeOuts objectAtIndex:0]; else _sessionTimeOut=nil; */ } else sessionTimeOut=nil; }; }; timer=[self resetTimer]; NSDebugMLLog(@"sessions",@"timer=%@",timer); NSDebugMLLog(@"sessions",@"timer fireDate=%@",[timer fireDate]); if (timer) [self addTimer:timer]; } NS_HANDLER { LOGException(@"%@ (%@)",localException,[localException reason]); //TODO if (selfLocked) { [self unlock]; selfLocked=NO; }; if (requestHandlingLocked) { [GSWApp unlockRequestHandling]; requestHandlingLocked=NO; }; [localException raise]; }; NS_ENDHANDLER; NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); if (selfLocked) { [self unlock]; selfLocked=NO; }; } NS_HANDLER { LOGException(@"%@ (%@)",localException,[localException reason]); //TODO if (requestHandlingLocked) { [GSWApp unlockRequestHandling]; requestHandlingLocked=NO; }; [localException raise]; }; NS_ENDHANDLER; if (requestHandlingLocked) { [GSWApp unlockRequestHandling]; requestHandlingLocked=NO; }; }; //-------------------------------------------------------------------- -(NSTimer*)resetTimer { NSTimer* newTimer=nil; GSWSessionTimeOut* sessionTimeOut=nil; LOGObjectFnStart(); // [self lock]; NS_DURING { NSTimeInterval now=[NSDate timeIntervalSinceReferenceDate]; NSTimeInterval timerFireTimeInterval=[[_timer fireDate]timeIntervalSinceReferenceDate]; NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); //NSLog(@"%s %d [_sessionOrderedTimeOuts count]=%d",__FILE__,__LINE__,[_sessionOrderedTimeOuts count]); if ([_sessionOrderedTimeOuts count]>0) { NSEnumerator* sessionOrderedTimeOutsEnum = [_sessionOrderedTimeOuts objectEnumerator]; GSWSessionTimeOut* sessionTimeOutObject=nil; NSTimeInterval minTimeOut; sessionTimeOut = [_sessionOrderedTimeOuts objectAtIndex:0]; minTimeOut = [sessionTimeOut timeOutTime]; while ((sessionTimeOutObject = [sessionOrderedTimeOutsEnum nextObject])) { if ([sessionTimeOutObject timeOutTime] 0) { sessionTimeOut = [_sessionOrderedTimeOuts lastObject]; if (sessionTimeOut) { id session=nil; [_target lock]; NS_DURING { NSDebugMLLog(@"sessions",@"[sessionTimeOut sessionID]=%@",[sessionTimeOut sessionID]); session=[_target performSelector:_callback withObject:[sessionTimeOut sessionID]]; NSDebugMLLog(@"sessions",@"session=%@",session); } NS_HANDLER { NSLog(@"### exception ... %@", [localException reason]); LOGException(@"%@ (%@)",localException,[localException reason]); //TODO [_target unlock]; timer = [NSTimer scheduledTimerWithTimeInterval:REFUSING_NEW_SESSION_TIMER_INTERVAL target:self selector:@selector(handleTimerRefusingSessions:) userInfo:nil repeats:NO]; [self unlock]; //[GSWApp unlockRequestHandling]; [localException raise]; } NS_ENDHANDLER; [_target unlock]; if (session) { NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); [session terminate]; // ??? NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); //NSLog(@"GSWSessionTimeOutMananger : removeObject = %@", sessionTimeOut); [_sessionOrderedTimeOuts removeObject:sessionTimeOut]; [_sessionTimeOuts removeObjectForKey:[session sessionID]]; NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); } } } // app terminate NSLog(@"application is preparing to shut down in %d sec...", (int)REFUSING_NEW_SESSION_APPLICATION_END); timer = [NSTimer scheduledTimerWithTimeInterval:REFUSING_NEW_SESSION_APPLICATION_END target:self selector:@selector(handleTimerKillingApplication:) userInfo:nil repeats:NO]; } else { // new timer, app does not terminate timer = [NSTimer scheduledTimerWithTimeInterval:REFUSING_NEW_SESSION_TIMER_INTERVAL target:self selector:@selector(handleTimerRefusingSessions:) userInfo:nil repeats:NO]; } } NS_HANDLER { NSDebugMLLog(@"sessions",@"EXCEPTION"); LOGException(@"%@ (%@)",localException,[localException reason]); //TODO [self unlock]; //[GSWApp unlockRequestHandling]; [localException raise]; }; NS_ENDHANDLER; NSDebugMLLog(@"sessions",@"self=%p sessionOrderedTimeOuts %p=%@", self,_sessionOrderedTimeOuts,_sessionOrderedTimeOuts); [self unlock]; NSDebugMLLog(@"sessions",@"unlocked"); } else { NSTimer* newTimer = nil; //TODO //[GSWApp unlockRequestHandling]; //[localException raise]; // Can't lock, reschedule NSLog(@"Can't lock, reschedule...."); NSDebugMLLog(@"sessions",@"selfLockn=%d",_selfLockn); newTimer = [NSTimer scheduledTimerWithTimeInterval:REFUSING_NEW_SESSION_TIMER_INTERVAL target:self selector:@selector(handleTimerRefusingSessions:) userInfo:nil repeats:NO]; NSDebugMLLog(@"sessions",@"newTimer=%@",newTimer); NSDebugMLLog(@"sessions",@"newTimer fireDate=%@",[newTimer fireDate]); NSDebugMLLog(@"sessions",@"newTimer tisn=%f",[[newTimer fireDate]timeIntervalSinceNow]); NSDebugMLLog(@"sessions",@"selfLockn=%d",_selfLockn); }; //[GSWApp unlockRequestHandling]; //[GSWApplication statusLogString:@"-Stop HandleTimerRefusingSessions"]; //NSLog(@"-Stop HandleTimerRefusingSessions"); }; @end