/* * 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.smb.server.win32; import java.util.BitSet; import org.alfresco.jlan.debug.Debug; import org.alfresco.jlan.netbios.win32.NetBIOSSocket; import org.alfresco.jlan.netbios.win32.Win32NetBIOS; import org.alfresco.jlan.netbios.win32.WinsockNetBIOSException; import org.alfresco.jlan.server.config.ServerConfiguration; import org.alfresco.jlan.smb.mailslot.win32.Win32NetBIOSHostAnnouncer; import org.alfresco.jlan.smb.server.CIFSConfigSection; import org.alfresco.jlan.smb.server.SMBServer; /** * Win32 NetBIOS LANA Monitor Class * * <p> * Monitors the available NetBIOS LANAs to check for new network interfaces coming online. A session * socket handler will be created for new LANAs as they appear. * * @author gkspencer */ public class Win32NetBIOSLanaMonitor extends Thread { // Constants // // Initial LANA listener array size private static final int LanaListenerArraySize = 16; // Global LANA monitor private static Win32NetBIOSLanaMonitor _lanaMonitor; // Available LANA list and current status private BitSet m_lanas; private BitSet m_lanaSts; // LANA status listeners private LanaListener[] m_listeners; // SMB/CIFS server to add new session handlers to private SMBServer m_server; // Shutdown request flag private boolean m_shutdown; // Debug output enable private boolean m_debug; /** * Class constructor * * @param server SMBServer * @param lanas int[] * @param wakeup long * @param debug boolean */ public Win32NetBIOSLanaMonitor(SMBServer server, int[] lanas, long wakeup, boolean debug) { // Set the SMB server and wakeup interval m_server = server; m_debug = debug; // Set the current LANAs in the available LANAs list m_lanas = new BitSet(); m_lanaSts = new BitSet(); if ( lanas != null) { // Set the currently available LANAs for (int i = 0; i < lanas.length; i++) m_lanas.set(lanas[i]); } // Initialize the online LANA status list int[] curLanas = Win32NetBIOS.LanaEnumerate(); if ( curLanas != null) { for (int i = 0; i < curLanas.length; i++) m_lanaSts.set(curLanas[i], true); } // Set the global LANA monitor, if not already set if ( _lanaMonitor == null) _lanaMonitor = this; // Start the LANA monitor thread setDaemon(true); start(); } /** * Return the global LANA monitor * * @return Win32NetBIOSLanaMonitor */ public static Win32NetBIOSLanaMonitor getLanaMonitor() { return _lanaMonitor; } /** * Add a LANA listener * * @param lana int * @param l LanaListener */ public synchronized final void addLanaListener(int lana, LanaListener l) { // Range check the LANA id if ( lana < 0 || lana > 255) return; // Check if the listener array has been allocated if ( m_listeners == null) { int len = LanaListenerArraySize; if ( lana > len) len = (lana + 3) & 0x00FC; m_listeners = new LanaListener[len]; } else if ( lana >= m_listeners.length) { // Extend the LANA listener array LanaListener[] newArray = new LanaListener[(lana + 3) & 0x00FC]; // Copy the existing array to the extended array System.arraycopy(m_listeners, 0, newArray, 0, m_listeners.length); m_listeners = newArray; } // Add the LANA listener m_listeners[lana] = l; // DEBUG if ( Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS register listener for LANA " + lana); } /** * Remove a LANA listener * * @param lana int */ public synchronized final void removeLanaListener(int lana) { // Validate the LANA id if ( m_listeners == null || lana < 0 || lana >= m_listeners.length) return; m_listeners[lana] = null; } /** * Thread method */ public void run() { // Clear the shutdown flag m_shutdown = false; // If Winsock NetBIOS is not enabled then initialize the sockets interface ServerConfiguration config = m_server.getConfiguration(); CIFSConfigSection cifsConfig = (CIFSConfigSection) config.getConfigSection(CIFSConfigSection.SectionName); if ( cifsConfig.useWinsockNetBIOS() == false) { try { NetBIOSSocket.initializeSockets(); } catch (WinsockNetBIOSException ex) { // DEBUG if ( Debug.EnableError && hasDebug()) { Debug.println("[SMB] Win32 NetBIOS initialization error"); Debug.println(ex); } // Shutdown the LANA monitor thread m_shutdown = true; } } // Loop until shutdown BitSet curLanas = new BitSet(); while (m_shutdown == false) { // Wait for a network address change event Win32NetBIOS.waitForNetworkAddressChange(); // Check if the monitor has been closed if ( m_shutdown == true) continue; // Clear the current active LANA bit set curLanas.clear(); // Get the available LANA list int[] lanas = Win32NetBIOS.LanaEnumerate(); if ( lanas != null) { // Check if there are any new LANAs available Win32NetBIOSSessionSocketHandler sessHandler = null; for (int i = 0; i < lanas.length; i++) { // Get the current LANA id, check if it's a known LANA int lana = lanas[i]; curLanas.set(lana, true); if ( m_lanas.get(lana) == false) { // DEBUG if ( Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS found new LANA, " + lana); // Create a single Win32 NetBIOS session handler using the specified LANA sessHandler = new Win32NetBIOSSessionSocketHandler(m_server, lana, hasDebug()); try { sessHandler.initializeSessionHandler(m_server); } catch (Exception ex) { // DEBUG if ( Debug.EnableError && hasDebug()) { Debug.println("[SMB] Win32 NetBIOS failed to create session handler for LANA " + lana); Debug.println(ex); } // Clear the session handler sessHandler = null; } // If the session handler was initialized successfully add it to the // SMB/CIFS server if ( sessHandler != null) { // Add the session handler to the SMB/CIFS server // m_server.addSessionHandler(sessHandler); // Run the NetBIOS session handler in a seperate thread Thread nbThread = new Thread(sessHandler); nbThread.setName("Win32NB_Handler_" + lana); nbThread.start(); // DEBUG if ( Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS created session handler on LANA " + lana); // Check if a host announcer should be enabled if ( cifsConfig.hasWin32EnableAnnouncer()) { // Create a host announcer Win32NetBIOSHostAnnouncer hostAnnouncer = new Win32NetBIOSHostAnnouncer(sessHandler, cifsConfig .getDomainName(), cifsConfig.getWin32HostAnnounceInterval()); // Add the host announcer to the SMB/CIFS server list // m_server.addHostAnnouncer(hostAnnouncer); hostAnnouncer.start(); // DEBUG if ( Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS host announcer enabled on LANA " + lana); } // Set the LANA in the available LANA list, and set the current status // to online m_lanas.set(lana); m_lanaSts.set(lana, true); } } else { // Check if the LANA has just come back online if ( m_lanaSts.get(lana) == false) { // Change the LANA status to indicate the LANA is back online m_lanaSts.set(lana, true); // Inform the listener that the LANA is back online if ( m_listeners != null && lana < m_listeners.length && m_listeners[lana] != null) m_listeners[lana].lanaStatusChange(lana, true); // DEBUG if ( Debug.EnableError && hasDebug()) Debug.println("[SMB] Win32 NetBIOS LANA online - " + lana); } } } // Check if there are any LANAs that have gone offline for (int i = 0; i < m_lanaSts.length(); i++) { if ( curLanas.get(i) == false && m_lanaSts.get(i) == true) { // DEBUG if ( Debug.EnableError && hasDebug()) Debug.println("[SMB] Win32 NetBIOS LANA offline - " + i); // Change the LANA status m_lanaSts.set(i, false); // Check if there is an associated listener for the LANA if ( m_listeners != null && m_listeners[i] != null) { // Notify the LANA listener that the LANA is now offline m_listeners[i].lanaStatusChange(i, false); } } } } else if ( m_lanaSts.length() == 0) { // No network devices, sleep for a while as waitForNetworkAddressChange() does not // wait // if there are no network devices try { Thread.sleep(10000); } catch (InterruptedException e) { } } } } /** * Determine if debug output is enabled * * @return boolean */ public final boolean hasDebug() { return m_debug; } /** * Request the LANA monitor thread to shutdown */ public final void shutdownRequest() { m_shutdown = true; // If Winsock NetBIOS is being used shutdown the Winsock interface if ( m_server.getCIFSConfiguration().useWinsockNetBIOS()) NetBIOSSocket.shutdownSockets(); // Interrupt the LANA monitor thread this.interrupt(); // Clear the global LANA monitor, if this is the global monitor if ( this == _lanaMonitor) _lanaMonitor = null; } }