/* * Copyright (C) 2006-2008 Alfresco Software Limited. * * 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 the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.jlan.oncrpc.nfs; import java.net.InetAddress; import java.util.Enumeration; import org.alfresco.jlan.debug.Debug; import org.alfresco.jlan.oncrpc.Rpc; import org.alfresco.jlan.server.NetworkServer; import org.alfresco.jlan.server.SrvSession; import org.alfresco.jlan.server.auth.ClientInfo; import org.alfresco.jlan.server.core.DeviceInterface; import org.alfresco.jlan.server.filesys.SearchContext; import org.alfresco.jlan.server.filesys.TreeConnection; import org.alfresco.jlan.server.filesys.TreeConnectionHash; /** * NFS Server Session Class * * @author gkspencer */ public class NFSSrvSession extends SrvSession { // Default and maximum number of search slots private static final int DefaultSearches = 32; private static final int MaxSearches = 256; // Remote address and port private InetAddress m_remAddr; private int m_remPort; // Session type (TCP or UDP) private int m_type; // Authentication identifier // // Identifies this session uniquely within the authentication type being used by the client private Object m_authIdentifier; // Active tree connections private TreeConnectionHash m_connections; // Cache of currently open files private NetworkFileCache m_fileCache; // Last time the session was accessed. Used to determine when to expire UDP sessions. private long m_lastAccess; // Active search list for this session private SearchContext[] m_search; private int m_searchCount; // NFS client information private ClientInfo m_nfsClientInfo; /** * Class constructor * * @param srv NetworkServer * @param addr InetAddress * @param port int * @param type int */ public NFSSrvSession(NetworkServer srv, InetAddress addr, int port, int type) { super(-1, srv, "NFS", null); // Save the remove address/port and type m_remAddr = addr; m_remPort = port; m_type = type; // Create a unique id for the session from the remote address, port and type StringBuffer str = new StringBuffer(); str.append(type == Rpc.TCP ? "T" : "U"); str.append(m_remAddr.getHostAddress()); str.append(":"); str.append(m_remPort); setUniqueId(str.toString()); // Set the remote name setRemoteName(m_remAddr.getHostAddress()); // Initialize the last access date/time setLastAccess(System.currentTimeMillis()); } /** * Return the session type * * @return int */ public final int isType() { return m_type; } /** * Return the open file cache * * @return NetworkFileCache */ public final NetworkFileCache getFileCache() { // Check if the file cache has been created if ( m_fileCache == null) { m_fileCache = new NetworkFileCache(getUniqueId()); // Copy settings to the file cache NFSConfigSection config = getNFSServer().getNFSConfiguration(); m_fileCache.setDebug( config.hasNFSFileCacheDebug()); if ( config.getNFSFileCacheIOTimer() > 0) m_fileCache.setIOTimer( config.getNFSFileCacheIOTimer()); if ( config.getNFSFileCacheCloseTimer() > 0) m_fileCache.setCloseTimer( config.getNFSFileCacheCloseTimer()); } // Return the file cache return m_fileCache; } /** * Determine if the session has an authentication identifier * * @return boolean */ public final boolean hasAuthIdentifier() { return m_authIdentifier != null ? true : false; } /** * Return the authentication identifier * * @return Object */ public final Object getAuthIdentifier() { return m_authIdentifier; } /** * Return the client network address * * @return InetAddress */ public InetAddress getRemoteAddress() { return m_remAddr; } /** * Return the remote port * * @return int */ public final int getRemotePort() { return m_remPort; } /** * Get the last access date/time for the session * * @return long */ public final long getLastAccess() { return m_lastAccess; } /** * return the NFS client information * * @return ClientInfo */ public final ClientInfo getNFSClientInformation() { return m_nfsClientInfo; } /** * Set the NFS client information * * @param cInfo ClientInfo */ public final void setNFSClientInformation( ClientInfo cInfo) { m_nfsClientInfo = cInfo; } /** * Find the tree connection for the specified share hash * * @param shareHash int * @return TreeConnection */ public final TreeConnection findConnection(int shareHash) { if ( m_connections == null) return null; return m_connections.findConnection(shareHash); } /** * Add a new connection to the list of active tree connections for this session * * @param tree TreeConnection */ public final void addConnection(TreeConnection tree) { if ( m_connections == null) m_connections = new TreeConnectionHash(); m_connections.addConnection(tree); } /** * Remove a connection from the list of active tree connections for this session * * @param tree TreeConnection */ public final void removeConnection(TreeConnection tree) { if ( m_connections == null) return; m_connections.deleteConnection(tree.getSharedDevice().getName()); } /** * Set the authentication identifier * * @param authIdent Object */ public final void setAuthIdentifier(Object authIdent) { m_authIdentifier = authIdent; } /** * Set the last access date/time for the session * * @param dateTime long */ public final void setLastAccess(long dateTime) { m_lastAccess = dateTime; } /** * Set the last access date/time for the session */ public final void setLastAccess() { m_lastAccess = System.currentTimeMillis(); } /** * Close the session, cleanup any resources. */ public void closeSession() { // Cleanup open files, tree connections and searches cleanupSession(); // Inform listeners that the session has closed getNFSServer().fireSessionClosed(this); // Call the base class super.closeSession(); } /** * Allocate a slot in the active searches list for a new search. * * @param search SearchContext * @return int Search slot index, or -1 if there are no more search slots available. */ protected synchronized final int allocateSearchSlot(SearchContext search) { // Check if the search array has been allocated if (m_search == null) m_search = new SearchContext[DefaultSearches]; // Find a free slot for the new search int idx = 0; while (idx < m_search.length && m_search[idx] != null) idx++; // Check if we found a free slot if (idx == m_search.length) { // The search array needs to be extended, check if we reached the limit. if (m_search.length >= MaxSearches) return -1; // Extend the search array SearchContext[] newSearch = new SearchContext[m_search.length * 2]; System.arraycopy(m_search, 0, newSearch, 0, m_search.length); m_search = newSearch; } // If the search context is valid then store in the allocated slot if ( search != null) m_search[idx] = search; // Return the allocated search slot index m_searchCount++; return idx; } /** * Deallocate the specified search context/slot. * * @param ctxId int */ protected synchronized final void deallocateSearchSlot(int ctxId) { // Check if the search array has been allocated and that the index is valid if (m_search == null || ctxId >= m_search.length) return; // Close the search if (m_search[ctxId] != null) m_search[ctxId].closeSearch(); // Free the specified search context slot m_searchCount--; m_search[ctxId] = null; } /** * Return the NFS server that the session is associated with * * @return NFSServer */ public final NFSServer getNFSServer() { return (NFSServer) getServer(); } /** * Return the search context for the specified search id. * * @return SearchContext * @param srchId int */ protected final SearchContext getSearchContext(int srchId) { // Check if the search array is valid and the search index is valid if (m_search == null || srchId >= m_search.length) return null; // Return the required search context return m_search[srchId]; } /** * Return the number of active tree searches. * * @return int */ public final int getSearchCount() { return m_searchCount; } /** * Store the seach context in the specified slot. * * @param slot Slot to store the search context. * @param srch SearchContext */ protected final void setSearchContext(int slot, SearchContext srch) { // Check if the search slot id is valid if (m_search == null || slot > m_search.length) return; // Store the context m_search[slot] = srch; } /** * Cleanup any resources owned by this session, close files, searches and change notification requests. */ protected final void cleanupSession() { // Debug if (Debug.EnableInfo && hasDebug(NFSServer.DBG_SESSION)) debugPrintln("NFS Cleanup session, searches=" + getSearchCount() + ", files=" + (m_fileCache != null ? m_fileCache.numberOfEntries() : 0) + ", treeConns=" + (m_connections != null ? m_connections.numberOfEntries() : 0)); // Check if there are any active searches if (m_search != null) { // Close all active searches for (int idx = 0; idx < m_search.length; idx++) { // Check if the current search slot is active if (m_search[idx] != null) deallocateSearchSlot(idx); } // Release the search context list, clear the search count m_search = null; m_searchCount = 0; } // Close any open files if ( m_fileCache != null) m_fileCache.closeAllFiles(); // Check if there are open tree connections if ( m_connections != null && m_connections.numberOfEntries() > 0) { // Enumerate the active connections Enumeration conns = m_connections.enumerateConnections(); while ( conns.hasMoreElements()) { // Get the current tree connection TreeConnection tree = (TreeConnection) conns.nextElement(); tree.closeConnection(this); // Inform the driver that the connection has been closed DeviceInterface devIface = tree.getInterface(); if ( devIface != null) devIface.treeClosed(this,tree); // Release the connection list m_connections = null; } } } }