/* * Copyright (C) 2005 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a * copy of the License at * * http://www.alfresco.org/legal/license.txt * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. */ package org.alfresco.filesys.netbios.win32; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.Hashtable; import org.alfresco.filesys.netbios.NetBIOSName; import org.alfresco.filesys.util.DataBuffer; import org.alfresco.filesys.util.IPAddress; import org.alfresco.filesys.util.X64; /** * Win32 NetBIOS Native Call Wrapper Class */ public class Win32NetBIOS { // Constants // // FIND_NAME_BUFFER structure length protected final static int FindNameBufferLen = 33; // Exception if the native code DLL load failed private static Throwable m_loadDLLException; /** * Check if the native code was loaded successfully * * @return boolean */ public static final boolean isInitialized() { return m_loadDLLException == null ? true : false; } /** * Return the native code load exception * * @return Throwable */ public static final Throwable getInitializationException() { return m_loadDLLException; } /** * Check if NetBIOS is enabled on any network adapters * * @return boolean */ public static final boolean isAvailable() { // Check if the DLL was loaded successfully if ( isInitialized() == false) return false; // Check if there are any valid LANAs, if not then NetBIOS is not enabled or network // adapters that have NetBIOS enabled are not currently enabled int[] lanas = LanaEnum(); if ( lanas != null && lanas.length > 0) return true; return false; } /** * Add a NetBIOS name to the local name table * * @param lana int * @param name byte[] * @return int */ public static native int AddName(int lana, byte[] name); /** * Add a group NetBIOS name to the local name table * * @param lana int * @param name byte[] * @return int */ public static native int AddGroupName(int lana, byte[] name); /** * Find a NetBIOS name, return the name buffer * * @param lana int * @param name byte[] * @param nameBuf byte[] * @param bufLen int * @return int */ public static native int FindNameRaw(int lana, byte[] name, byte[] nameBuf, int bufLen); /** * Find a NetBIOS name * * @param lana int * @param name NetBIOSName * @return int */ public static int FindName(int lana, NetBIOSName nbName) { // Allocate a buffer to receive the name details byte[] nameBuf = new byte[nbName.isGroupName() ? 65535 : 4096]; // Get the raw NetBIOS name data int sts = FindNameRaw(lana, nbName.getNetBIOSName(), nameBuf, nameBuf.length); if (sts != NetBIOS.NRC_GoodRet) return -sts; // Unpack the FIND_NAME_HEADER structure DataBuffer buf = new DataBuffer(nameBuf, 0, nameBuf.length); int nodeCount = buf.getShort(); buf.skipBytes(1); boolean isGroupName = buf.getByte() == 0 ? false : true; // Unpack the FIND_NAME_BUFFER structures int curPos = buf.getPosition(); for (int i = 0; i < nodeCount; i++) { // FIND_NAME_BUFFER: // UCHAR length // UCHAR access_control // UCHAR frame_control // UCHAR destination_addr[6] // UCHAR source_addr[6] // UCHAR routing_info[18] // Skip to the source_addr field buf.skipBytes(9); // Source address field format should be 0.0.n.n.n.n for TCP/IP address if (buf.getByte() == 0 && buf.getByte() == 0) { // Looks like a TCP/IP format address, unpack it byte[] ipAddr = new byte[4]; ipAddr[0] = (byte) buf.getByte(); ipAddr[1] = (byte) buf.getByte(); ipAddr[2] = (byte) buf.getByte(); ipAddr[3] = (byte) buf.getByte(); // Add the address to the list of TCP/IP addresses for the NetBIOS name nbName.addIPAddress(ipAddr); // Skip to the start of the next FIND_NAME_BUFFER structure curPos += FindNameBufferLen; buf.setPosition(curPos); } } // Return the node count return nodeCount; } /** * Delete a NetBIOS name from the local name table * * @param lana int * @param name byte[] * @return int */ public static native int DeleteName(int lana, byte[] name); /** * Enumerate the available LANAs * * @return int[] */ public static int[] LanaEnumerate() { // Make sure that there is an active network adapter as making calls to the LanaEnum native call // causes problems when there are no active network adapters. boolean adapterAvail = false; try { // Enumerate the available network adapters and check for an active adapter, not including // the loopback adapter Enumeration nis = NetworkInterface.getNetworkInterfaces(); while ( nis.hasMoreElements() && adapterAvail == false) { NetworkInterface ni = nis.nextElement(); if ( ni.getName().equals("lo") == false) { // Make sure the adapter has a valid IP address Enumeration addrs = ni.getInetAddresses(); if ( addrs.hasMoreElements()) adapterAvail = true; } } } catch ( SocketException ex) { } // Check if there are network adapter(s) available if ( adapterAvail == false) return null; // Call the native code to return the available LANA list return LanaEnum(); } /** * Enumerate the available LANAs * * @return int[] */ private static native int[] LanaEnum(); /** * Reset the NetBIOS environment * * @param lana int * @return int */ public static native int Reset(int lana); /** * Listen for an incoming session request * * @param lana int * @param toName byte[] * @param fromName byte[] * @param callerName byte[] * @return int */ public static native int Listen(int lana, byte[] toName, byte[] fromName, byte[] callerName); /** * Receive a data packet on a session * * @param lana int * @param lsn int * @param buf byte[] * @param off int * @param maxLen int * @return int */ public static native int Receive(int lana, int lsn, byte[] buf, int off, int maxLen); /** * Send a data packet on a session * * @param lana int * @param lsn int * @param buf byte[] * @param off int * @param len int * @return int */ public static native int Send(int lana, int lsn, byte[] buf, int off, int len); /** * Send a datagram to a specified name * * @param lana int * @param srcNum int * @param destName byte[] * @param buf byte[] * @param off int * @param len int * @return int */ public static native int SendDatagram(int lana, int srcNum, byte[] destName, byte[] buf, int off, int len); /** * Send a broadcast datagram * * @param lana * @param buf byte[] * @param off int * @param len int * @return int */ public static native int SendBroadcastDatagram(int lana, byte[] buf, int off, int len); /** * Receive a datagram on a specified name * * @param lana int * @param nameNum int * @param buf byte[] * @param off int * @param maxLen int * @return int */ public static native int ReceiveDatagram(int lana, int nameNum, byte[] buf, int off, int maxLen); /** * Receive a broadcast datagram * * @param lana int * @param nameNum int * @param buf byte[] * @param off int * @param maxLen int * @return int */ public static native int ReceiveBroadcastDatagram(int lana, int nameNum, byte[] buf, int off, int maxLen); /** * Hangup a session * * @param lsn int * @return int */ public static native int Hangup(int lana, int lsn); /** * Return the local computers NetBIOS name * * @return String */ public static native String GetLocalNetBIOSName(); /** * Return the local domain name * * @return String */ public static native String GetLocalDomainName(); /** * Return a comma delimeted list of WINS server TCP/IP addresses, or null if no WINS servers are * configured. * * @return String */ public static native String getWINSServerList(); /** * Find the TCP/IP address for a LANA * * @param lana int * @return String */ public static final String getIPAddressForLANA(int lana) { // Get the local NetBIOS name String localName = GetLocalNetBIOSName(); if (localName == null) return null; // Create a NetBIOS name for the local name NetBIOSName nbName = new NetBIOSName(localName, NetBIOSName.WorkStation, false); // Get the local NetBIOS name details int sts = FindName(lana, nbName); if (sts == -NetBIOS.NRC_EnvNotDef) { // Reset the LANA then try the name lookup again Reset(lana); sts = FindName(lana, nbName); } // Check if the name lookup was successful String ipAddr = null; if (sts >= 0) { // Get the first IP address from the list ipAddr = nbName.getIPAddressString(0); } // Return the TCP/IP address for the LANA return ipAddr; } /** * Find the adapter name for a LANA * * @param lana int * @return String */ public static final String getAdapterNameForLANA(int lana) { // Get the TCP/IP address for a LANA String ipAddr = getIPAddressForLANA(lana); if (ipAddr == null) return null; // Get the list of available network adapters Hashtable adapters = getNetworkAdapterList(); String adapterName = null; if (adapters != null) { // Find the network adapter for the TCP/IP address NetworkInterface ni = adapters.get(ipAddr); if (ni != null) adapterName = ni.getDisplayName(); } // Return the adapter name for the LANA return adapterName; } /** * Find the LANA for a TCP/IP address * * @param addr String * @return int */ public static final int getLANAForIPAddress(String addr) { // Check if the address is a numeric TCP/IP address if (IPAddress.isNumericAddress(addr) == false) return -1; // Get a list of the available NetBIOS LANAs int[] lanas = LanaEnum(); if (lanas == null || lanas.length == 0) return -1; // Search for the LANA with the matching TCP/IP address for (int i = 0; i < lanas.length; i++) { // Get the current LANAs TCP/IP address String curAddr = getIPAddressForLANA(lanas[i]); if (curAddr != null && curAddr.equals(addr)) return lanas[i]; } // Failed to find the LANA for the specified TCP/IP address return -1; } /** * Find the LANA for a network adapter * * @param name String * @return int */ public static final int getLANAForAdapterName(String name) { // Get the list of available network adapters Hashtable niList = getNetworkAdapterList(); // Search for the address of the specified network adapter Enumeration niEnum = niList.keys(); while (niEnum.hasMoreElements()) { // Get the current TCP/IP address String ipAddr = niEnum.nextElement(); NetworkInterface ni = niList.get(ipAddr); if (ni.getDisplayName().equalsIgnoreCase(name)) { // Return the LANA for the network adapters TCP/IP address return getLANAForIPAddress(ipAddr); } } // Failed to find matching network adapter return -1; } /** * Return a hashtable of NetworkInterfaces indexed by TCP/IP address * * @return Hashtable */ private static final Hashtable getNetworkAdapterList() { // Get a list of the local network adapters Hashtable niList = new Hashtable(); try { // Enumerate the available network adapters Enumeration niEnum = NetworkInterface.getNetworkInterfaces(); while (niEnum.hasMoreElements()) { // Get the current network interface details NetworkInterface ni = niEnum.nextElement(); Enumeration addrEnum = ni.getInetAddresses(); while (addrEnum.hasMoreElements()) { // Get the address and add the adapter to the list indexed via the numeric IP // address string InetAddress addr = addrEnum.nextElement(); niList.put(addr.getHostAddress(), ni); } } } catch (Exception ex) { } // Return the network adapter list return niList; } //---------- Winsock based NetBIOS interface ----------// /** * Initialize the NetBIOS socket interface * * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native void InitializeSockets() throws WinsockNetBIOSException; /** * Shutdown the NetBIOS socket interface */ protected static native void ShutdownSockets(); /** * Create a NetBIOS socket * * @param lana int * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int CreateSocket(int lana) throws WinsockNetBIOSException; /** * Create a NetBIOS datagram socket * * @param lana int * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int CreateDatagramSocket(int lana) throws WinsockNetBIOSException; /** * Bind a NetBIOS socket to a name to listen for incoming sessions * * @param sockPtr int * @param name byte[] * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int BindSocket(int sockPtr, byte[] name) throws WinsockNetBIOSException; /** * Listen for an incoming connection * * @param sockPtr int * @param callerName byte[] * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int ListenSocket(int sockPtr, byte[] callerName) throws WinsockNetBIOSException; /** * Close a NetBIOS socket * * @param sockPtr int */ protected static native void CloseSocket(int sockPtr); /** * Send data on a session socket * * @param sockPtr int * @param buf byte[] * @param off int * @param len int * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int SendSocket(int sockPtr, byte[] buf, int off, int len) throws WinsockNetBIOSException; /** * Receive data on a session socket * * @param sockPtr int * @param toName byte[] * @param buf byte[] * @param off int * @param maxLen int * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int ReceiveSocket(int sockPtr, byte[] buf, int off, int maxLen) throws WinsockNetBIOSException; /** * Send data on a datagram socket * * @param sockPtr int * @param toName byte[] * @param buf byte[] * @param off int * @param len int * @return int * @exception WinsockNetBIOSException If a Winsock error occurs */ protected static native int SendSocketDatagram(int sockPtr, byte[] toName, byte[] buf, int off, int len) throws WinsockNetBIOSException; /** * Wait for a network address change event, block until a change occurs or the Winsock NetBIOS * interface is shut down */ public static native void waitForNetworkAddressChange(); /** * Static initializer used to load the native code library */ static { // Check if we are running under 64 bit Windows String dllName = "Win32NetBIOS"; if ( X64.isWindows64()) dllName = "Win32NetBIOSx64"; // Load the Win32 NetBIOS interface library try { System.loadLibrary( dllName); } catch (Throwable ex) { ex.printStackTrace(); // Save the native code load exception m_loadDLLException = ex; } } }