userlibandfileserver/fileserver/sfile/sf_notifier.h
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfile\sf_notifier.h
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sf_std.h"
       
    19 #include "sf_pool.h"
       
    20 #include "e32hashtab.h" 
       
    21 #include "cl_notification.h"
       
    22 #include "f32notification.h"
       
    23 
       
    24 #ifndef SF_NOTIFIER_H
       
    25 #define SF_NOTIFIER_H
       
    26 
       
    27 /**
       
    28  * Number of notifications in TFsNotificationType that the client can set
       
    29  * @internalTechnology
       
    30  */
       
    31 const TInt KNumRegisterableFilters = 8; 
       
    32 
       
    33 /*
       
    34  * This determines the size of the CFsPool.
       
    35  * Until we have read/write locks there is no point in this being more than 1.
       
    36  * 
       
    37  * @internalTechnology
       
    38  */
       
    39 const TInt KNotificationPoolSize = 1;
       
    40 
       
    41 
       
    42 /**
       
    43  * A CFsNotificationPathFilter is a simple class containing two HBufCs of the target to be notified about:
       
    44  * 1 for the drive and path
       
    45  * 1 for the filename
       
    46  *  
       
    47  *  A CFsNotificationPathFilter has a 1 to Many relationship with TFsNotificationTypeFilter
       
    48  *  
       
    49  * @internalTechnology
       
    50  */
       
    51 class CFsNotificationPathFilter
       
    52 	{
       
    53 public:
       
    54 	static CFsNotificationPathFilter* NewL(const TDesC& aPath, const TDesC& aFilename);
       
    55 	~CFsNotificationPathFilter();
       
    56 private:
       
    57 	void ConstructL(const TDesC& aPath, const TDesC& aFilename);
       
    58 	CFsNotificationPathFilter();
       
    59 public:
       
    60 	HBufC* iPath;
       
    61 	HBufC* iFilename;
       
    62 	};
       
    63 
       
    64 /**
       
    65  * A TFsNotificationTypeFilter is a class which contains a pointer to the associated path to monitor
       
    66  * and the type of notification.
       
    67  * 
       
    68  * @internalTechnology
       
    69  */
       
    70 class TFsNotificationTypeFilter
       
    71 	{
       
    72 public:
       
    73 	CFsNotificationPathFilter* iPathFilter;
       
    74 	TFsNotification::TFsNotificationType iNotificationType; 
       
    75 	//As we are storing filters in filter-specific
       
    76 	//arrays then iNotificationType is potentially redundant.
       
    77 	};
       
    78 
       
    79 //These typedefs are to appease the compiler as it does not like
       
    80 //nested templated arguments.
       
    81  /**
       
    82   *  @internalTechnology
       
    83   */
       
    84 typedef RArray<TFsNotificationTypeFilter> TFsNotificationTypeArray;
       
    85 /**
       
    86  * @internalTechnology
       
    87  */
       
    88 typedef RArray<TFsNotificationTypeArray> TFsNotificationTypeDriveArray;
       
    89 
       
    90 class CFsNotificationBlock; //forward decl.
       
    91 
       
    92 /**
       
    93  * CFsNotifyRequest is a file-server side object representation of an RFsNotify sub-session.   
       
    94  * 
       
    95  * @internalTechnology
       
    96  */
       
    97 NONSHARABLE_CLASS(CFsNotifyRequest) : public CFsObject
       
    98 	{
       
    99 public:
       
   100 	
       
   101 	/*
       
   102 	 * Active means that the client is waiting for the first notification to be sent
       
   103 	 * The status then changes to Outstanding when further notifications are sent to the buffer
       
   104 	 * If the server overflows when in state EOutstanding then we move to state EOutstandingOverflow.
       
   105 	 * From EOutstandingOverflow after the next call to RequestNotifications from the client, we must move to state EInactive.
       
   106 	 * If we do not overflow then when RequestNotifications is called we can move back to state EActive.
       
   107 	 * EInactive is when there are no notifications outstanding and request notifications hasn't been called. 
       
   108 	 */
       
   109 	enum TNotifyRequestStatus
       
   110 		{
       
   111 		EActive,				//Server waiting for a notification (filters added, RequestNotifications called)
       
   112 		EOutstanding,			//Server waiting for client to call RequestNotifications, has notification(s) to send.
       
   113 		EOutstandingOverflow,	//Server waiting for client to call RequestNotifications, has notification(s) to send, buffer has overflowed.
       
   114 		EInactive				//Server waiting for RequestNotification, no notifications outstanding 
       
   115 		};
       
   116 	
       
   117 	static CFsNotifyRequest* NewL();
       
   118 	virtual ~CFsNotifyRequest();
       
   119 	
       
   120 	/*
       
   121 	 * Returns the RArray<TFsNotificationFilter> for an index
       
   122 	 * as returned from FsNotificationHelper::TypeToIndex()
       
   123 	 */
       
   124 	TFsNotificationTypeArray* FilterTypeList(TInt aDrive,TInt aIndex);
       
   125 	
       
   126 	//Removes all filters from iFilterList
       
   127 	TInt RemoveFilters();
       
   128 
       
   129 	//Add single filter to this request
       
   130 	TInt AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask);
       
   131 
       
   132 	//Sets filter as active/inactive
       
   133 	void SetActive(TNotifyRequestStatus aValue);
       
   134 	
       
   135 	/**
       
   136 	 *Get the status of this request.
       
   137 	 *@See TNotifyRequestStatus 
       
   138 	 */ 
       
   139 	TNotifyRequestStatus ActiveStatus();
       
   140 	
       
   141 	/*
       
   142 	 * Completes and frees notification request
       
   143 	 * 
       
   144 	 * @param aIsCancel is used to determine whether 
       
   145 	 * to write back to the client or not when aReason != KErrNone.
       
   146 	 * 
       
   147 	 * In the case of closing the subsession you shouldn't write back to the client.
       
   148 	 */
       
   149 	void CompleteClientRequest(TInt aReason,TBool aIsCancel=EFalse);
       
   150 
       
   151 	//RfsNotify::RequestNotifications has been called
       
   152 	TInt SetClientMessage(const RMessage2& aClientMsg);
       
   153 
       
   154 	/* 
       
   155 	 * Called from FsNotificationManager::HandleChange(),
       
   156 	 * this function packages the data in to a CFsNotificationBlock in preperation for 
       
   157 	 * notification of this operation to the client.
       
   158 	 * 
       
   159 	 * Calling of this function means that we are notifying about this operation. (all checks passed)
       
   160 	 * 
       
   161 	 * aRequest can be NULL when the request doesn't come from the file server 
       
   162 	 * (such as when a media card is removed)
       
   163 	 */
       
   164 	TInt NotifyChange(CFsClientMessageRequest* aRequest, const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock);
       
   165 		
       
   166 	/*
       
   167 	 * This function performs the IPC to the client's buffer.
       
   168 	 */
       
   169 	TInt SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize);
       
   170 	
       
   171 	//Closing this notification
       
   172 	void CloseNotification();
       
   173 
       
   174 	//Simple getter
       
   175 	TInt ClientMsgHandle();
       
   176 	
       
   177 private:
       
   178 	CFsNotifyRequest();
       
   179 	void ConstructL();
       
   180 	
       
   181 	//Check whether there is room for a new notification in the client's buffer
       
   182 	TBool ValidateNotification(TInt aNotificationSize, TInt& aServerTail);
       
   183 	
       
   184 	/*
       
   185 	 * The iTailSemaphore is used so that many CFsNotificationBlocks can
       
   186 	 * be processed concurrently.
       
   187 	 * This lock ensures that the iServerTail is safe.
       
   188 	 */
       
   189 	 //ToDo:  This should be a ReadWriteLock
       
   190 	RFastLock iTailSemaphore;
       
   191 	
       
   192 	/*
       
   193 	 * The iClientSyncLock is a Read/Write style lock whereby it is 
       
   194 	 * set up with the value of KNotificationPoolSize.
       
   195 	 * When a block is allocated it calls wait on this lock.
       
   196 	 * 
       
   197 	 * This lock is to ensure that all of the currently processing blocks are
       
   198 	 * written before the client is updated.
       
   199 	 * 
       
   200 	 * i.e. if two blocks are being processed concurrently and the second 
       
   201 	 * block is written we need to wait until the first one is also written
       
   202 	 * before the client receives the updated tail.
       
   203 	 */
       
   204 	//ToDo: This should be a ReadWriteLock
       
   205 	RFastLock iClientSyncLock;
       
   206 	
       
   207 
       
   208 	/*
       
   209 	 * HashMap<DriveNumber, TFsNotificationTypeDriveArray>
       
   210 	 * HashMap<DriveNumber, RArray<TFsNotificationTypeArray>>
       
   211 	 * HashMap<DriveNumber, RArray<RArray<TFsNotificationTypeFilter>>>
       
   212 	 * 
       
   213 	 * Each value of iDrivesTypesFiltersMap is of type TFsNotificationTypeDriveArray 
       
   214 	 * associated with a particular drive.
       
   215 	 * 
       
   216 	 * Each index of the TFsNotificationTypeDriveArray is a TFsNotificationTypeArray
       
   217 	 */
       
   218 	RHashMap<TInt,TFsNotificationTypeDriveArray> iDrivesTypesFiltersMap;
       
   219 	
       
   220 	/*
       
   221 	 * The iPathFilterList is an RPointerArray of CFsNotificationPathFilters.
       
   222 	 * 
       
   223 	 * These are normally only accessed via a TFsNotificationTypeFilter (via iDrivesTypesFiltersMap),
       
   224 	 * not via this array directly.
       
   225 	 */
       
   226 	RPointerArray<CFsNotificationPathFilter> iPathFilterList;
       
   227 	
       
   228 	RMessage2 iBufferMsg; //To update buffer
       
   229 	RMessage2 iClientMsg; //client notification request
       
   230 	
       
   231 	CSessionFs* iSession; //Session associated with this request (TFsSessionDisconnect::DoRequestL)
       
   232 	
       
   233 	TNotifyRequestStatus iNotifyRequestStatus;	//Current status of this request
       
   234 	
       
   235 	//The following 3 variables must be aligned when modified.
       
   236 	TInt iClientHead;	//Offset where the client should start reading from.
       
   237 						//If the server writes past this offset we must overflow the client.
       
   238 	
       
   239 	TInt iClientTail;	//The end of the client's accessible range.
       
   240 	
       
   241 	TInt iServerTail;	//The end of the server's accessible range.
       
   242 						//Overflow occurs if iServerTail becomes more than iClientHead.
       
   243 	
       
   244 	TInt iClientBufferSize;		//Buffer size is word-aligned.
       
   245 	
       
   246 	friend class TFsNotificationBuffer;	//For access to iClientBufferSize and iBufferMsg
       
   247 	friend class TFsNotificationRequest;//For access to iClientBufferSize
       
   248 	friend class FsNotificationManager; //For access to iSession
       
   249 	friend class TFsNotificationOpen; //For access to iSession
       
   250 	friend class TFsNotificationRemove; //For access to iDrivesTypesFiltersMap
       
   251 	};
       
   252 
       
   253 /**
       
   254  * A CFsNotificationBlock is a chunk of memory which is used to represent a notification
       
   255  * such that a single IPC can be performed from server to client.
       
   256  * 
       
   257  * CFsNotificationBlocks are stored in a CFsPool<CFsNotificationBlock>. 
       
   258  * 
       
   259  *@internalTechnology
       
   260  */
       
   261 class CFsNotificationBlock
       
   262 	{
       
   263 public:
       
   264 	static CFsNotificationBlock* New();
       
   265 	~CFsNotificationBlock();
       
   266 	TAny* Data();
       
   267 private:
       
   268 	CFsNotificationBlock();
       
   269 	TText8 iData[KMinNotificationBufferSize];
       
   270 	};
       
   271 
       
   272 /**
       
   273  * Helper class to get certain attributes from or about a particular operation to used in a notification
       
   274  * 
       
   275  * @internalTechnology
       
   276  */
       
   277 class FsNotificationHelper
       
   278 	{
       
   279 public:
       
   280 	static void NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType);
       
   281 	static void PathName(CFsClientMessageRequest& aRequest, TDes& aName);
       
   282 	static void NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aName);
       
   283 	static TInt NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName);
       
   284 	static TInt TypeToIndex(TFsNotification::TFsNotificationType aType);
       
   285 	static TFsNotification::TFsNotificationType NotificationType(TInt& aIndex);
       
   286 	static TInt DriveNumber(const TPtrC& aPath);
       
   287 	static void Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear);
       
   288 	};
       
   289 
       
   290 /**
       
   291  * The FsNotificationManager is a static object
       
   292  * 
       
   293  *@internalTechnology
       
   294  */
       
   295 class FsNotificationManager
       
   296 	{
       
   297 public:
       
   298 	//New notification request from client
       
   299 	static void AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest);
       
   300 
       
   301 	//Notification request cancel
       
   302 	static void RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest);
       
   303 	//Notification request cancel (session closed)
       
   304 	static void RemoveNotificationRequest(CSessionFs* aSession);
       
   305 
       
   306 	/* A change has occurred represented by this request.
       
   307 	 * Work out which CFsNotifyRequests are interested
       
   308 	 * (if any) and call CFsNotifyRequest::NotifyChange.
       
   309 	 */
       
   310 	static void HandleChange(CFsClientMessageRequest& aRequest);
       
   311 	
       
   312 	/* A change has occurred represented by this request.
       
   313 	 * Work out which CFsNotifyRequests are interested
       
   314 	 * (if any) and call CFsNotifyRequest::NotifyChange.
       
   315 	 * 
       
   316 	 * This override is used directly when we want to force a particular notification type
       
   317 	 */
       
   318 	static void HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType);
       
   319 	
       
   320 	/* 
       
   321 	 * This override is used directly when we want to specify the current operation's name (src) and notification type.
       
   322 	 * 
       
   323 	 * aRequest can be NULL when the request doesn't come from the file server 
       
   324 	 * such as when a media card is removed, see LocalDrives::CompleteDriveNotifications
       
   325 	 * 
       
   326 	 * @See LocalDrives::CompleteDriveNotifications(TInt aDrive)
       
   327 	 */
       
   328 	static void HandleChange(CFsClientMessageRequest* aRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType aType);
       
   329 
       
   330 	//Initialise iNotifyRequests and iStaticNotification
       
   331 	static void OpenL();
       
   332 	static TBool IsInitialised();
       
   333 	
       
   334 	/*
       
   335 	 * On CFsNotifyRequest closing, Close is called if this is the last request being removed.
       
   336 	 * This removes all of the managers private data.
       
   337 	 */
       
   338 	static void Close();
       
   339 
       
   340 	/*
       
   341 	 * Calls SetFilterRegister for every valid notification set in aMask.
       
   342 	 */
       
   343 	static void SetFilterRegisterMask(TUint aMask,TBool aAdd);
       
   344 	
       
   345 	/*
       
   346 	 * Adds or Removes to the count of filters set up for a particular type
       
   347 	 * This is a global count such that if there are no fiters for a particular type 
       
   348 	 * HandleChange doesn't need to do any iteration for that type.
       
   349 	 */
       
   350 	static void SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount = 1);
       
   351 	/*
       
   352 	 * Get the number of registers filters set up on a particular type.
       
   353 	 * @param aIndex the TFsNotificationType's index as determined from FsNotificationHelper::TypeToIndex
       
   354 	 */
       
   355 	static TInt& FilterRegister(TInt aIndex);
       
   356 
       
   357 	/*
       
   358 	 * Returns the number of CFsNotifyRequests set up
       
   359 	 */
       
   360 	static TInt Count();
       
   361 	
       
   362 	/*
       
   363 	 * Lock the iChainLock (currently not a ReadWriteLock)
       
   364 	 */
       
   365 	static void Lock();
       
   366 	
       
   367 	/*
       
   368 	 * Unlock iChainLock
       
   369 	 */
       
   370 	static void Unlock();
       
   371 
       
   372 private:
       
   373   
       
   374     /*
       
   375      * @internalTechnology
       
   376 	 * Used by DoMatchFilter and DoHandleChange to control the flow of 
       
   377 	 * loop execution.
       
   378      */
       
   379     enum TFsNotificationFilterMatch
       
   380         {
       
   381         EDifferent  = 0x00, //Operation and Filters do not match.
       
   382         EMatch      = 0x01, //Operation and Filters do match.
       
   383         EContinue   = 0x02  //Data caged directory - Do not notify.
       
   384         };
       
   385     
       
   386     /*
       
   387      * Checks whether aOperation matches the filter name and/or path set in aFilter. 
       
   388      */
       
   389     static TFsNotificationFilterMatch DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter);
       
   390     
       
   391 	/*
       
   392 	 * Iterates filters for a particular drive.
       
   393 	 * Called from HandleChange
       
   394 	 */
       
   395 	static void DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray, TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType);
       
   396 	
       
   397 	/*
       
   398 	 * Stores the CFsNotifyRequests
       
   399 	 */
       
   400 	static CFsObjectCon* iNotifyRequests;
       
   401 	
       
   402 	//As we are doing notifications 'in-place' which is multi-threaded
       
   403 	//we need to have locking to protect iNotifyRequests.
       
   404 	//ToDo: ReadWriteLock
       
   405 	static RFastLock iChainLock;
       
   406 	
       
   407 	/*
       
   408 	 * Global register per filter type. 
       
   409 	 * Keeps a count of the number of filters set up for a particular type
       
   410 	 * (NB: EMediaChange is reported regardless of filters set)
       
   411 	 */
       
   412 	static TInt iFilterRegister[KNumRegisterableFilters];
       
   413 	
       
   414 	/*
       
   415 	 * This is a pool of blocks which are server-side versions of TFsNotification.
       
   416 	 * They are used so that we can have a single IPC from server to client.
       
   417 	 * 
       
   418 	 * it will also be used for coalescing changes.
       
   419 	 */
       
   420 	static CFsPool<CFsNotificationBlock>* iPool;
       
   421 	
       
   422 	friend class CFsNotifyRequest;
       
   423 	friend class RequestAllocator;
       
   424 	friend class TFsNotificationSubClose;
       
   425 	};
       
   426 
       
   427 
       
   428 #endif /* SF_NOTIFIER_H */
       
   429 
       
   430