mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-02 17:35:18 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3617 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1991 lines
56 KiB
Java
1991 lines
56 KiB
Java
/*
|
|
* 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.server;
|
|
|
|
import java.io.IOException;
|
|
import java.net.DatagramPacket;
|
|
import java.net.DatagramSocket;
|
|
import java.net.InetAddress;
|
|
import java.net.NetworkInterface;
|
|
import java.net.SocketException;
|
|
import java.util.Enumeration;
|
|
import java.util.Hashtable;
|
|
import java.util.Vector;
|
|
|
|
import org.alfresco.filesys.netbios.NetBIOSName;
|
|
import org.alfresco.filesys.netbios.NetBIOSPacket;
|
|
import org.alfresco.filesys.netbios.NetworkSettings;
|
|
import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
|
|
import org.alfresco.filesys.server.NetworkServer;
|
|
import org.alfresco.filesys.server.ServerListener;
|
|
import org.alfresco.filesys.server.config.ServerConfiguration;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* NetBIOS name server class.
|
|
*/
|
|
public class NetBIOSNameServer extends NetworkServer implements Runnable
|
|
{
|
|
private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.netbios");
|
|
|
|
// Various NetBIOS packet sizes
|
|
|
|
public static final int AddNameSize = 256;
|
|
public static final int DeleteNameSize = 256;
|
|
public static final int RefreshNameSize = 256;
|
|
|
|
// Add name thread broadcast interval and retry count
|
|
|
|
private static final int AddNameInterval = 2000; // ms between transmits
|
|
private static final int AddNameRetries = 5; // number of broadcasts
|
|
|
|
private static final int AddNameWINSInterval = 250; // ms between requests when using WINS
|
|
|
|
// Delete name interval and retry count
|
|
|
|
private static final int DeleteNameInterval = 200; // ms between transmits
|
|
private static final int DeleteNameRetries = 1; // number of broadcasts
|
|
|
|
// Refresh name retry count
|
|
|
|
public static final int RefreshNameRetries = 2; // number of broadcasts
|
|
|
|
// NetBIOS flags
|
|
|
|
public static final int GroupName = 0x8000;
|
|
|
|
// Default time to live value for names registered by this server, in seconds
|
|
|
|
public static final int DefaultTTL = 10800; // 3 hours
|
|
|
|
// Name refresh thread wakeup interval
|
|
|
|
public static final long NameRefreshWakeupInterval = 180000L; // 3 minutes
|
|
|
|
// Name transaction id
|
|
|
|
private static int m_tranId;
|
|
|
|
// NetBIOS name service datagram socket
|
|
|
|
private DatagramSocket m_socket;
|
|
|
|
// Shutdown flag
|
|
|
|
private boolean m_shutdown;
|
|
|
|
// Local address to bind the name server to
|
|
|
|
private InetAddress m_bindAddress;
|
|
|
|
// Broadcast address, if not using WINS
|
|
|
|
private InetAddress m_bcastAddr;
|
|
|
|
// Port/socket to bind to
|
|
|
|
private int m_port = RFCNetBIOSProtocol.NAME_PORT;
|
|
|
|
// WINS server addresses
|
|
|
|
private InetAddress m_winsPrimary;
|
|
private InetAddress m_winsSecondary;
|
|
|
|
// Local add name listener list
|
|
|
|
private Vector<AddNameListener> m_addListeners;
|
|
|
|
// Local name query listener list
|
|
|
|
private Vector<QueryNameListener> m_queryListeners;
|
|
|
|
// Remote name add listener list
|
|
|
|
private Vector<RemoteNameListener> m_remoteListeners;
|
|
|
|
// Local NetBIOS name table
|
|
|
|
private Vector<NetBIOSName> m_localNames;
|
|
|
|
// Remote NetBIOS name table
|
|
|
|
private Hashtable<NetBIOSName, byte[]> m_remoteNames;
|
|
|
|
// List of active add name requests
|
|
|
|
private Vector<NetBIOSRequest> m_reqList;
|
|
|
|
// NetBIOS request handler and name refresh threads
|
|
|
|
private NetBIOSRequestHandler m_reqHandler;
|
|
private NetBIOSNameRefresh m_refreshThread;
|
|
|
|
// Server thread
|
|
|
|
private Thread m_srvThread;
|
|
|
|
// NetBIOS request handler thread inner class
|
|
|
|
class NetBIOSRequestHandler extends Thread
|
|
{
|
|
|
|
// Shutdown request flag
|
|
|
|
private boolean m_hshutdown = false;
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public NetBIOSRequestHandler()
|
|
{
|
|
setDaemon(true);
|
|
setName("NetBIOSRequest");
|
|
}
|
|
|
|
/**
|
|
* Shutdown the request handler thread
|
|
*/
|
|
public final void shutdownRequest()
|
|
{
|
|
m_hshutdown = true;
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
m_reqList.notify();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main thread code
|
|
*/
|
|
public void run()
|
|
{
|
|
|
|
// Loop until shutdown requested
|
|
|
|
while (m_hshutdown == false)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Wait for something to do
|
|
|
|
NetBIOSRequest req = null;
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
|
|
// Check if there are any requests in the queue
|
|
|
|
if (m_reqList.size() == 0)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled() && hasDebug())
|
|
logger.debug("NetBIOS handler waiting for request ...");
|
|
|
|
// Wait for some work ...
|
|
|
|
m_reqList.wait();
|
|
}
|
|
|
|
// Remove a request from the queue
|
|
|
|
if (m_reqList.size() > 0)
|
|
req = m_reqList.get(0);
|
|
else if (m_hshutdown == true)
|
|
break;
|
|
}
|
|
|
|
// Get the request retry count, for WINS only send one request
|
|
|
|
int reqRetry = req.getRetryCount();
|
|
if (hasPrimaryWINSServer())
|
|
reqRetry = 1;
|
|
|
|
// Process the request
|
|
|
|
boolean txsts = true;
|
|
int retry = 0;
|
|
|
|
while (req.hasErrorStatus() == false && retry++ < reqRetry)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("NetBIOS handler, processing " + req);
|
|
|
|
// Process the request
|
|
|
|
switch (req.isType())
|
|
{
|
|
|
|
// Add name request
|
|
|
|
case NetBIOSRequest.AddName:
|
|
|
|
// Check if a WINS server is configured
|
|
|
|
if (hasPrimaryWINSServer())
|
|
txsts = sendAddName(req, getPrimaryWINSServer(), false);
|
|
else
|
|
txsts = sendAddName(req, getBroadcastAddress(), true);
|
|
break;
|
|
|
|
// Delete name request
|
|
|
|
case NetBIOSRequest.DeleteName:
|
|
|
|
// Check if a WINS server is configured
|
|
|
|
if (hasPrimaryWINSServer())
|
|
txsts = sendDeleteName(req, getPrimaryWINSServer(), false);
|
|
else
|
|
txsts = sendDeleteName(req, getBroadcastAddress(), true);
|
|
break;
|
|
|
|
// Refresh name request
|
|
|
|
case NetBIOSRequest.RefreshName:
|
|
|
|
// Check if a WINS server is configured
|
|
|
|
if (hasPrimaryWINSServer())
|
|
txsts = sendRefreshName(req, getPrimaryWINSServer(), false);
|
|
else
|
|
txsts = sendRefreshName(req, getBroadcastAddress(), true);
|
|
break;
|
|
}
|
|
|
|
// Check if the request was successful
|
|
|
|
if (txsts == true && req.getRetryInterval() > 0)
|
|
{
|
|
|
|
// Sleep for a while
|
|
|
|
sleep(req.getRetryInterval());
|
|
}
|
|
}
|
|
|
|
// Check if the request was successful
|
|
|
|
if (req.hasErrorStatus() == false)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("NetBIOS handler successful, " + req);
|
|
|
|
// Update the name record
|
|
|
|
NetBIOSName nbName = req.getNetBIOSName();
|
|
|
|
switch (req.isType())
|
|
{
|
|
|
|
// Add name request
|
|
|
|
case NetBIOSRequest.AddName:
|
|
|
|
// Add the name to the list of local names
|
|
|
|
if (m_localNames.contains(nbName) == false)
|
|
m_localNames.addElement(nbName);
|
|
|
|
// Update the expiry time for the name
|
|
|
|
nbName.setExpiryTime(System.currentTimeMillis() + (nbName.getTimeToLive() * 1000L));
|
|
|
|
// Inform listeners that the request was successful
|
|
|
|
fireAddNameEvent(nbName, NetBIOSNameEvent.ADD_SUCCESS);
|
|
break;
|
|
|
|
// Delete name request
|
|
|
|
case NetBIOSRequest.DeleteName:
|
|
|
|
// Remove the name from the list of local names
|
|
|
|
m_localNames.remove(req.getNetBIOSName());
|
|
break;
|
|
|
|
// Refresh name registration request
|
|
|
|
case NetBIOSRequest.RefreshName:
|
|
|
|
// Update the expiry time for the name
|
|
|
|
nbName.setExpiryTime(System.currentTimeMillis() + (nbName.getTimeToLive() * 1000L));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Error occurred
|
|
|
|
switch (req.isType())
|
|
{
|
|
|
|
// Add name request
|
|
|
|
case NetBIOSRequest.AddName:
|
|
|
|
// Remove the name from the local name list
|
|
|
|
m_localNames.remove(req.getNetBIOSName());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Remove the request from the queue
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
m_reqList.remove(0);
|
|
}
|
|
}
|
|
catch (InterruptedException ex)
|
|
{
|
|
}
|
|
|
|
// Check if the request handler has been shutdown
|
|
|
|
if (m_hshutdown == true)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send an add name request
|
|
*
|
|
* @param req NetBIOSRequest
|
|
* @param dest InetAddress
|
|
* @param bcast boolean
|
|
* @return boolean
|
|
*/
|
|
private final boolean sendAddName(NetBIOSRequest req, InetAddress dest, boolean bcast)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Allocate a buffer for the add name NetBIOS packet
|
|
|
|
byte[] buf = new byte[AddNameSize];
|
|
NetBIOSPacket addPkt = new NetBIOSPacket(buf);
|
|
|
|
// Build an add name packet for each IP address
|
|
|
|
for (int i = 0; i < req.getNetBIOSName().numberOfAddresses(); i++)
|
|
{
|
|
|
|
// Build an add name request for the current IP address
|
|
|
|
int len = addPkt.buildAddNameRequest(req.getNetBIOSName(), i, req.getTransactionId());
|
|
if (bcast == false)
|
|
addPkt.setFlags(0);
|
|
|
|
// Allocate the datagram packet, using the add name buffer
|
|
|
|
DatagramPacket pkt = new DatagramPacket(buf, len, dest, RFCNetBIOSProtocol.NAME_PORT);
|
|
|
|
// Send the add name request
|
|
|
|
if (m_socket != null)
|
|
m_socket.send(pkt);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug(" Add name " + (bcast ? "broadcast" : "WINS") + ", " + req);
|
|
}
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
fireAddNameEvent(req.getNetBIOSName(), NetBIOSNameEvent.ADD_IOERROR);
|
|
req.setErrorStatus(true);
|
|
return false;
|
|
}
|
|
|
|
// Add name broadcast successful
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Send a refresh name request
|
|
*
|
|
* @param req NetBIOSRequest
|
|
* @param dest InetAddress
|
|
* @param bcast boolean
|
|
* @return boolean
|
|
*/
|
|
private final boolean sendRefreshName(NetBIOSRequest req, InetAddress dest, boolean bcast)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Allocate a buffer for the refresh name NetBIOS packet
|
|
|
|
byte[] buf = new byte[RefreshNameSize];
|
|
NetBIOSPacket refreshPkt = new NetBIOSPacket(buf);
|
|
|
|
// Build a refresh name packet for each IP address
|
|
|
|
for (int i = 0; i < req.getNetBIOSName().numberOfAddresses(); i++)
|
|
{
|
|
|
|
// Build a refresh name request for the current IP address
|
|
|
|
int len = refreshPkt.buildRefreshNameRequest(req.getNetBIOSName(), i, req.getTransactionId());
|
|
if (bcast == false)
|
|
refreshPkt.setFlags(0);
|
|
|
|
// Allocate the datagram packet, using the refresh name buffer
|
|
|
|
DatagramPacket pkt = new DatagramPacket(buf, len, dest, RFCNetBIOSProtocol.NAME_PORT);
|
|
|
|
// Send the refresh name request
|
|
|
|
if (m_socket != null)
|
|
m_socket.send(pkt);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug(" Refresh name " + (bcast ? "broadcast" : "WINS") + ", " + req);
|
|
}
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
req.setErrorStatus(true);
|
|
return false;
|
|
}
|
|
|
|
// Add name broadcast successful
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Send a delete name request via a network broadcast
|
|
*
|
|
* @param req NetBIOSRequest
|
|
* @param dest InetAddress
|
|
* @param bcast boolean
|
|
* @return boolean
|
|
*/
|
|
private final boolean sendDeleteName(NetBIOSRequest req, InetAddress dest, boolean bcast)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Allocate a buffer for the delete name NetBIOS packet
|
|
|
|
byte[] buf = new byte[DeleteNameSize];
|
|
NetBIOSPacket delPkt = new NetBIOSPacket(buf);
|
|
|
|
// Build a delete name packet for each IP address
|
|
|
|
for (int i = 0; i < req.getNetBIOSName().numberOfAddresses(); i++)
|
|
{
|
|
|
|
// Build an add name request for the current IP address
|
|
|
|
int len = delPkt.buildDeleteNameRequest(req.getNetBIOSName(), i, req.getTransactionId());
|
|
if (bcast == false)
|
|
delPkt.setFlags(0);
|
|
|
|
// Allocate the datagram packet, using the add name buffer
|
|
|
|
DatagramPacket pkt = new DatagramPacket(buf, len, dest, RFCNetBIOSProtocol.NAME_PORT);
|
|
|
|
// Send the add name request
|
|
|
|
if (m_socket != null)
|
|
m_socket.send(pkt);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug(" Delete name " + (bcast ? "broadcast" : "WINS") + ", " + req);
|
|
}
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
req.setErrorStatus(true);
|
|
return false;
|
|
}
|
|
|
|
// Delete name broadcast successful
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// NetBIOS name refresh thread inner class
|
|
|
|
class NetBIOSNameRefresh extends Thread
|
|
{
|
|
|
|
// Shutdown request flag
|
|
|
|
private boolean m_hshutdown = false;
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public NetBIOSNameRefresh()
|
|
{
|
|
setDaemon(true);
|
|
setName("NetBIOSRefresh");
|
|
}
|
|
|
|
/**
|
|
* Shutdown the name refresh thread
|
|
*/
|
|
public final void shutdownRequest()
|
|
{
|
|
m_hshutdown = true;
|
|
|
|
// Wakeup the thread
|
|
|
|
this.interrupt();
|
|
}
|
|
|
|
/**
|
|
* Main thread code
|
|
*/
|
|
public void run()
|
|
{
|
|
|
|
// Loop for ever
|
|
|
|
while (m_hshutdown == false)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Sleep for a while
|
|
|
|
sleep(NameRefreshWakeupInterval);
|
|
|
|
// Check if there is a shutdown pending
|
|
|
|
if (m_hshutdown == true)
|
|
break;
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("NetBIOS name refresh wakeup ...");
|
|
|
|
// Check if there are any registered names that will expire in the next interval
|
|
|
|
synchronized (m_localNames)
|
|
{
|
|
|
|
// Get the current time plus the wakeup interval
|
|
|
|
long expireTime = System.currentTimeMillis() + NameRefreshWakeupInterval;
|
|
|
|
// Loop through the local name list
|
|
|
|
for (int i = 0; i < m_localNames.size(); i++)
|
|
{
|
|
|
|
// Get a name from the list
|
|
|
|
NetBIOSName nbName = m_localNames.get(i);
|
|
|
|
// Check if the name has expired, or will expire before the next wakeup
|
|
// event
|
|
|
|
if (nbName.getExpiryTime() < expireTime)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Queuing name refresh for " + nbName);
|
|
|
|
// Queue a refresh request for the NetBIOS name
|
|
|
|
NetBIOSRequest nbReq = new NetBIOSRequest(NetBIOSRequest.RefreshName, nbName,
|
|
getNextTransactionId());
|
|
nbReq.setRetryCount(RefreshNameRetries);
|
|
|
|
// Queue the request
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
|
|
// Add the request to the list
|
|
|
|
m_reqList.addElement(nbReq);
|
|
|
|
// Wakeup the processing thread
|
|
|
|
m_reqList.notify();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if ( m_hshutdown == false)
|
|
logger.error("NetBIOS Name refresh thread exception", ex);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Default constructor
|
|
*
|
|
* @param serviceRegistry repository connection
|
|
* @param config ServerConfiguration
|
|
* @exception SocketException If a network setup error occurs
|
|
*/
|
|
public NetBIOSNameServer(ServerConfiguration config) throws SocketException
|
|
{
|
|
super("NetBIOS", config);
|
|
|
|
// Set the NetBIOS name server port
|
|
|
|
setServerPort( config.getNetBIOSNamePort());
|
|
|
|
// Perform common constructor code
|
|
|
|
commonConstructor();
|
|
}
|
|
|
|
/**
|
|
* Common constructor code
|
|
*
|
|
* @exception SocketException If a network setup error occurs
|
|
*/
|
|
private final void commonConstructor() throws SocketException
|
|
{
|
|
// Allocate the local and remote name tables
|
|
|
|
m_localNames = new Vector<NetBIOSName>();
|
|
m_remoteNames = new Hashtable<NetBIOSName, byte[]>();
|
|
|
|
// Check if NetBIOS name server debug output is enabled
|
|
|
|
if (getConfiguration().hasNetBIOSDebug())
|
|
setDebug(true);
|
|
|
|
// Set the local address to bind the server to, and server port
|
|
|
|
setBindAddress(getConfiguration().getNetBIOSBindAddress());
|
|
|
|
// Copy the WINS server addresses, if set
|
|
|
|
setPrimaryWINSServer(getConfiguration().getPrimaryWINSServer());
|
|
setSecondaryWINSServer(getConfiguration().getSecondaryWINSServer());
|
|
|
|
// Check if WINS is not enabled, use broadcasts instead
|
|
|
|
if (hasPrimaryWINSServer() == false)
|
|
{
|
|
|
|
try
|
|
{
|
|
m_bcastAddr = InetAddress.getByName(getConfiguration().getBroadcastMask());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the local address the server binds to, or null if all local addresses are used.
|
|
*
|
|
* @return java.net.InetAddress
|
|
*/
|
|
public final InetAddress getBindAddress()
|
|
{
|
|
return m_bindAddress;
|
|
}
|
|
|
|
/**
|
|
* Return the next available transaction id for outgoing NetBIOS packets.
|
|
*
|
|
* @return int
|
|
*/
|
|
protected final synchronized int getNextTransactionId()
|
|
{
|
|
return m_tranId++;
|
|
}
|
|
|
|
/**
|
|
* Return the port/socket that the server is bound to.
|
|
*
|
|
* @return int
|
|
*/
|
|
public final int getPort()
|
|
{
|
|
return m_port;
|
|
}
|
|
|
|
/**
|
|
* Determine if the server binds to a particulat local address, or all addresses
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public final boolean hasBindAddress()
|
|
{
|
|
return m_bindAddress != null ? true : false;
|
|
}
|
|
|
|
/**
|
|
* Return the remote name table
|
|
*
|
|
* @return Hashtable<NetBIOSName, byte[]>
|
|
*/
|
|
public final Hashtable<NetBIOSName, byte[]> getNameTable()
|
|
{
|
|
return m_remoteNames;
|
|
}
|
|
|
|
/**
|
|
* Return the broadcast address, if WINS is disabled
|
|
*
|
|
* @return InetAddress
|
|
*/
|
|
public final InetAddress getBroadcastAddress()
|
|
{
|
|
return m_bcastAddr;
|
|
}
|
|
|
|
/**
|
|
* Determine if the primary WINS server address has been set
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public final boolean hasPrimaryWINSServer()
|
|
{
|
|
return m_winsPrimary != null ? true : false;
|
|
}
|
|
|
|
/**
|
|
* Return the primary WINS server address
|
|
*
|
|
* @return InetAddress
|
|
*/
|
|
public final InetAddress getPrimaryWINSServer()
|
|
{
|
|
return m_winsPrimary;
|
|
}
|
|
|
|
/**
|
|
* Determine if the secondary WINS server address has been set
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public final boolean hasSecondaryWINSServer()
|
|
{
|
|
return m_winsSecondary != null ? true : false;
|
|
}
|
|
|
|
/**
|
|
* Return the secondary WINS server address
|
|
*
|
|
* @return InetAddress
|
|
*/
|
|
public final InetAddress getSecondaryWINSServer()
|
|
{
|
|
return m_winsSecondary;
|
|
}
|
|
|
|
/**
|
|
* Add a NetBIOS name.
|
|
*
|
|
* @param name NetBIOS name to be added
|
|
* @exception java.io.IOException I/O error occurred.
|
|
*/
|
|
public final synchronized void AddName(NetBIOSName name) throws IOException
|
|
{
|
|
|
|
// Check if the NetBIOS name socket has been initialized
|
|
|
|
if (m_socket == null)
|
|
throw new IOException("NetBIOS name socket not initialized");
|
|
|
|
// Create an add name request and add to the request list
|
|
|
|
NetBIOSRequest nbReq = new NetBIOSRequest(NetBIOSRequest.AddName, name, getNextTransactionId());
|
|
|
|
// Set the retry interval
|
|
|
|
if (hasPrimaryWINSServer())
|
|
nbReq.setRetryInterval(AddNameWINSInterval);
|
|
else
|
|
nbReq.setRetryInterval(AddNameInterval);
|
|
|
|
// Add the name to the local name list
|
|
|
|
m_localNames.addElement(name);
|
|
|
|
// Queue the request
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
|
|
// Add the request to the list
|
|
|
|
m_reqList.addElement(nbReq);
|
|
|
|
// Wakeup the processing thread
|
|
|
|
m_reqList.notify();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete a NetBIOS name.
|
|
*
|
|
* @param name NetBIOS name to be deleted
|
|
* @exception java.io.IOException I/O error occurred.
|
|
*/
|
|
public final synchronized void DeleteName(NetBIOSName name) throws IOException
|
|
{
|
|
|
|
// Check if the NetBIOS name socket has been initialized
|
|
|
|
if (m_socket == null)
|
|
throw new IOException("NetBIOS name socket not initialized");
|
|
|
|
// Create a delete name request and add to the request list
|
|
|
|
NetBIOSRequest nbReq = new NetBIOSRequest(NetBIOSRequest.DeleteName, name, getNextTransactionId(),
|
|
DeleteNameRetries);
|
|
nbReq.setRetryInterval(DeleteNameInterval);
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
|
|
// Add the request to the list
|
|
|
|
m_reqList.addElement(nbReq);
|
|
|
|
// Wakeup the processing thread
|
|
|
|
m_reqList.notify();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a local add name listener to the NetBIOS name server.
|
|
*
|
|
* @param l AddNameListener
|
|
*/
|
|
public final synchronized void addAddNameListener(AddNameListener l)
|
|
{
|
|
|
|
// Check if the add name listener list is allocated
|
|
|
|
if (m_addListeners == null)
|
|
m_addListeners = new Vector<AddNameListener>();
|
|
m_addListeners.addElement(l);
|
|
}
|
|
|
|
/**
|
|
* Add a query name listener to the NetBIOS name server.
|
|
*
|
|
* @param l QueryNameListener
|
|
*/
|
|
public final synchronized void addQueryListener(QueryNameListener l)
|
|
{
|
|
|
|
// Check if the query name listener list is allocated
|
|
|
|
if (m_queryListeners == null)
|
|
m_queryListeners = new Vector<QueryNameListener>();
|
|
m_queryListeners.addElement(l);
|
|
}
|
|
|
|
/**
|
|
* Add a remote name listener to the NetBIOS name server.
|
|
*
|
|
* @param l RemoteNameListener
|
|
*/
|
|
public final synchronized void addRemoteListener(RemoteNameListener l)
|
|
{
|
|
|
|
// Check if the remote name listener list is allocated
|
|
|
|
if (m_remoteListeners == null)
|
|
m_remoteListeners = new Vector<RemoteNameListener>();
|
|
m_remoteListeners.addElement(l);
|
|
}
|
|
|
|
/**
|
|
* Trigger an add name event to all registered listeners.
|
|
*
|
|
* @param name NetBIOSName
|
|
* @param sts int
|
|
*/
|
|
protected final synchronized void fireAddNameEvent(NetBIOSName name, int sts)
|
|
{
|
|
|
|
// Check if there are any listeners
|
|
|
|
if (m_addListeners == null || m_addListeners.size() == 0)
|
|
return;
|
|
|
|
// Create a NetBIOS name event
|
|
|
|
NetBIOSNameEvent evt = new NetBIOSNameEvent(name, sts);
|
|
|
|
// Inform all registered listeners
|
|
|
|
for (int i = 0; i < m_addListeners.size(); i++)
|
|
{
|
|
AddNameListener addListener = m_addListeners.get(i);
|
|
addListener.netbiosNameAdded(evt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger an query name event to all registered listeners.
|
|
*
|
|
* @param name NetBIOSName
|
|
* @param sts int
|
|
*/
|
|
protected final synchronized void fireQueryNameEvent(NetBIOSName name, InetAddress addr)
|
|
{
|
|
|
|
// Check if there are any listeners
|
|
|
|
if (m_queryListeners == null || m_queryListeners.size() == 0)
|
|
return;
|
|
|
|
// Create a NetBIOS name event
|
|
|
|
NetBIOSNameEvent evt = new NetBIOSNameEvent(name, NetBIOSNameEvent.QUERY_NAME);
|
|
|
|
// Inform all registered listeners
|
|
|
|
for (int i = 0; i < m_queryListeners.size(); i++)
|
|
{
|
|
QueryNameListener queryListener = m_queryListeners.get(i);
|
|
queryListener.netbiosNameQuery(evt, addr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger a name register event to all registered listeners.
|
|
*
|
|
* @param name NetBIOSName
|
|
* @param sts int
|
|
*/
|
|
protected final synchronized void fireNameRegisterEvent(NetBIOSName name, InetAddress addr)
|
|
{
|
|
|
|
// Check if there are any listeners
|
|
|
|
if (m_remoteListeners == null || m_remoteListeners.size() == 0)
|
|
return;
|
|
|
|
// Create a NetBIOS name event
|
|
|
|
NetBIOSNameEvent evt = new NetBIOSNameEvent(name, NetBIOSNameEvent.REGISTER_NAME);
|
|
|
|
// Inform all registered listeners
|
|
|
|
for (int i = 0; i < m_remoteListeners.size(); i++)
|
|
{
|
|
RemoteNameListener nameListener = m_remoteListeners.get(i);
|
|
nameListener.netbiosAddRemoteName(evt, addr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trigger a name release event to all registered listeners.
|
|
*
|
|
* @param name NetBIOSName
|
|
* @param sts int
|
|
*/
|
|
protected final synchronized void fireNameReleaseEvent(NetBIOSName name, InetAddress addr)
|
|
{
|
|
|
|
// Check if there are any listeners
|
|
|
|
if (m_remoteListeners == null || m_remoteListeners.size() == 0)
|
|
return;
|
|
|
|
// Create a NetBIOS name event
|
|
|
|
NetBIOSNameEvent evt = new NetBIOSNameEvent(name, NetBIOSNameEvent.REGISTER_NAME);
|
|
|
|
// Inform all registered listeners
|
|
|
|
for (int i = 0; i < m_remoteListeners.size(); i++)
|
|
{
|
|
RemoteNameListener nameListener = m_remoteListeners.get(i);
|
|
nameListener.netbiosReleaseRemoteName(evt, addr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Open the server socket
|
|
*
|
|
* @exception SocketException
|
|
*/
|
|
private void openSocket() throws java.net.SocketException
|
|
{
|
|
|
|
// Check if the server should bind to a particular local address, or all addresses
|
|
|
|
if (hasBindAddress())
|
|
m_socket = new DatagramSocket(getPort(), m_bindAddress);
|
|
else
|
|
m_socket = new DatagramSocket(getPort());
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS name query.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processNameQuery(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
|
|
// Check that the name query packet is valid
|
|
|
|
if (pkt.getQuestionCount() != 1)
|
|
return;
|
|
|
|
// Get the name that is being queried
|
|
|
|
String searchName = pkt.getQuestionName();
|
|
char nameType = searchName.charAt(15);
|
|
|
|
int len = 0;
|
|
while (len <= 14 && searchName.charAt(len) != ' ')
|
|
len++;
|
|
searchName = searchName.substring(0, len);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Query name=" + searchName + ", type=" + NetBIOSName.TypeAsString(nameType) + ", len="
|
|
+ len);
|
|
|
|
// Search for the name in the local name table
|
|
|
|
Enumeration<NetBIOSName> enm = m_localNames.elements();
|
|
NetBIOSName nbName = null;
|
|
boolean foundName = false;
|
|
|
|
while (enm.hasMoreElements() && foundName == false)
|
|
{
|
|
|
|
// Get the current NetBIOS name item from the local name table
|
|
|
|
nbName = enm.nextElement();
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("NetBIOS Name - " + nbName.getName() + ", len=" + nbName.getName().length() + ",type="
|
|
+ NetBIOSName.TypeAsString(nbName.getType()));
|
|
|
|
// Check if the name matches the query name
|
|
|
|
if (nbName.getType() == nameType && nbName.getName().compareTo(searchName) == 0)
|
|
foundName = true;
|
|
}
|
|
|
|
// Check if we found a matching name
|
|
|
|
if (foundName == true)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Found name " + searchName + " in local name table : " + nbName.toString());
|
|
|
|
// Build the name query response
|
|
|
|
int pktLen = pkt.buildNameQueryResponse(nbName);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("%% NetBIOS Reply to " + fromAddr.getHostAddress() + " :-");
|
|
pkt.DumpPacket(false);
|
|
}
|
|
|
|
// Send the reply packet
|
|
|
|
try
|
|
{
|
|
|
|
// Send the name query reply
|
|
|
|
sendPacket(pkt, pktLen, fromAddr, fromPort);
|
|
}
|
|
catch (java.io.IOException ex)
|
|
{
|
|
logger.error("Name query response error", ex);
|
|
}
|
|
|
|
// Inform listeners of the name query
|
|
|
|
fireQueryNameEvent(nbName, fromAddr);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Failed to find match for name " + searchName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS name register request.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processNameRegister(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
|
|
// Check that the name register packet is valid
|
|
|
|
if (pkt.getQuestionCount() != 1)
|
|
return;
|
|
|
|
// Get the name that is being registered
|
|
|
|
String regName = pkt.getQuestionName();
|
|
char nameType = regName.charAt(15);
|
|
|
|
int len = 0;
|
|
while (len <= 14 && regName.charAt(len) != ' ')
|
|
len++;
|
|
regName = regName.substring(0, len);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Register name=" + regName + ", type=" + NetBIOSName.TypeAsString(nameType) + ", len="
|
|
+ len);
|
|
|
|
// Create a NetBIOS name for the host
|
|
|
|
byte[] hostIP = fromAddr.getAddress();
|
|
NetBIOSName nbName = new NetBIOSName(regName, nameType, false, hostIP);
|
|
|
|
// Add the name to the remote host name table
|
|
|
|
m_remoteNames.put(nbName, hostIP);
|
|
|
|
// Inform listeners that a new remote name has been added
|
|
|
|
fireNameRegisterEvent(nbName, fromAddr);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Added remote name " + nbName.toString() + " to remote names table");
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS name release.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processNameRelease(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
|
|
// Check that the name release packet is valid
|
|
|
|
if (pkt.getQuestionCount() != 1)
|
|
return;
|
|
|
|
// Get the name that is being released
|
|
|
|
String regName = pkt.getQuestionName();
|
|
char nameType = regName.charAt(15);
|
|
|
|
int len = 0;
|
|
while (len <= 14 && regName.charAt(len) != ' ')
|
|
len++;
|
|
regName = regName.substring(0, len);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger
|
|
.debug("%% Release name=" + regName + ", type=" + NetBIOSName.TypeAsString(nameType) + ", len="
|
|
+ len);
|
|
|
|
// Create a NetBIOS name for the host
|
|
|
|
byte[] hostIP = fromAddr.getAddress();
|
|
NetBIOSName nbName = new NetBIOSName(regName, nameType, false, hostIP);
|
|
|
|
// Remove the name from the remote host name table
|
|
|
|
m_remoteNames.remove(nbName);
|
|
|
|
// Inform listeners that a remote name has been released
|
|
|
|
fireNameReleaseEvent(nbName, fromAddr);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Released remote name " + nbName.toString() + " from remote names table");
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS query response.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processQueryResponse(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS name register response.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processRegisterResponse(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
|
|
// Check if there are any reply name details
|
|
|
|
if (pkt.getAnswerCount() == 0)
|
|
return;
|
|
|
|
// Get the details from the response packet
|
|
|
|
int tranId = pkt.getTransactionId();
|
|
|
|
// Find the matching request
|
|
|
|
NetBIOSRequest req = findRequest(tranId);
|
|
if (req == null)
|
|
return;
|
|
|
|
// Get the error code from the response
|
|
|
|
int errCode = pkt.getResultCode();
|
|
|
|
if (errCode != 0)
|
|
{
|
|
|
|
// Mark the request error
|
|
|
|
req.setErrorStatus(true);
|
|
|
|
// Get the name details
|
|
|
|
String regName = pkt.getAnswerName();
|
|
char nameType = regName.charAt(15);
|
|
|
|
int len = 0;
|
|
while (len <= 14 && regName.charAt(len) != ' ')
|
|
len++;
|
|
regName = regName.substring(0, len);
|
|
|
|
// Create a NetBIOS name for the host
|
|
|
|
byte[] hostIP = fromAddr.getAddress();
|
|
NetBIOSName nbName = new NetBIOSName(regName, nameType, false, hostIP);
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Negative Name Registration name=" + nbName);
|
|
|
|
// Inform listeners of the add name failure
|
|
|
|
fireAddNameEvent(req.getNetBIOSName(), NetBIOSNameEvent.ADD_FAILED);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Debug
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("%% Name Registration Successful name=" + req.getNetBIOSName().getName());
|
|
|
|
// Inform listeners that the add name was successful
|
|
|
|
fireAddNameEvent(req.getNetBIOSName(), NetBIOSNameEvent.ADD_SUCCESS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS name release response.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processReleaseResponse(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Process a NetBIOS WACK.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param fromAddr InetAddress
|
|
* @param fromPort int
|
|
*/
|
|
protected final void processWack(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Remove a local add name listener from the NetBIOS name server.
|
|
*
|
|
* @param l AddNameListener
|
|
*/
|
|
public final synchronized void removeAddNameListener(AddNameListener l)
|
|
{
|
|
|
|
// Check if the listener list is valid
|
|
|
|
if (m_addListeners == null)
|
|
return;
|
|
m_addListeners.removeElement(l);
|
|
}
|
|
|
|
/**
|
|
* Remove a query name listner from the NetBIOS name server.
|
|
*
|
|
* @param l QueryNameListener
|
|
*/
|
|
public final synchronized void removeQueryNameListener(QueryNameListener l)
|
|
{
|
|
|
|
// Check if the listener list is valid
|
|
|
|
if (m_queryListeners == null)
|
|
return;
|
|
m_queryListeners.removeElement(l);
|
|
}
|
|
|
|
/**
|
|
* Remove a remote name listener from the NetBIOS name server.
|
|
*
|
|
* @param l RemoteNameListener
|
|
*/
|
|
public final synchronized void removeRemoteListener(RemoteNameListener l)
|
|
{
|
|
|
|
// Check if the listener list is valid
|
|
|
|
if (m_remoteListeners == null)
|
|
return;
|
|
m_remoteListeners.removeElement(l);
|
|
}
|
|
|
|
/**
|
|
* Run the NetBIOS name server.
|
|
*/
|
|
public void run()
|
|
{
|
|
|
|
// Initialize the NetBIOS name socket
|
|
|
|
NetBIOSPacket nbPkt = null;
|
|
DatagramPacket pkt = null;
|
|
byte[] buf = null;
|
|
|
|
try
|
|
{
|
|
|
|
// Get a list of the local IP addresses
|
|
|
|
Vector<byte[]> ipList = new Vector<byte[]>();
|
|
|
|
if (hasBindAddress())
|
|
{
|
|
|
|
// Use the specified bind address
|
|
|
|
ipList.add(getBindAddress().getAddress());
|
|
}
|
|
else
|
|
{
|
|
|
|
// Get a list of all the local addresses
|
|
|
|
InetAddress[] addrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
|
|
|
|
for (int i = 0; i < addrs.length; i++)
|
|
{
|
|
|
|
// Check for a valid address, filter out '127.0.0.1' and '0.0.0.0' addresses
|
|
|
|
if (addrs[i].getHostAddress().equals("127.0.0.1") == false
|
|
&& addrs[i].getHostAddress().equals("0.0.0.0") == false)
|
|
ipList.add(addrs[i].getAddress());
|
|
}
|
|
|
|
// Check if the address list is empty, use the network interface list to get the local IP addresses
|
|
|
|
if ( ipList.size() == 0)
|
|
{
|
|
// Enumerate the network adapter list
|
|
|
|
Enumeration<NetworkInterface> niEnum = NetworkInterface.getNetworkInterfaces();
|
|
|
|
if ( niEnum != null)
|
|
{
|
|
while ( niEnum.hasMoreElements())
|
|
{
|
|
// Get the current network interface
|
|
|
|
NetworkInterface ni = niEnum.nextElement();
|
|
|
|
// Enumerate the addresses for the network adapter
|
|
|
|
Enumeration<InetAddress> niAddrs = ni.getInetAddresses();
|
|
if ( niAddrs != null)
|
|
{
|
|
// Check for any valid addresses
|
|
|
|
while ( niAddrs.hasMoreElements())
|
|
{
|
|
InetAddress curAddr = niAddrs.nextElement();
|
|
|
|
if ( curAddr.getHostAddress().equals("127.0.0.1") == false &&
|
|
curAddr.getHostAddress().equals("0.0.0.0") == false)
|
|
ipList.add( curAddr.getAddress());
|
|
}
|
|
}
|
|
}
|
|
|
|
// DEBUG
|
|
|
|
if ( ipList.size() > 0 && logger.isDebugEnabled())
|
|
logger.debug("Found " + ipList.size() + " addresses using interface list");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// DBEUG
|
|
|
|
if ( logger.isDebugEnabled())
|
|
logger.debug("Found " + ipList.size() + " addresses using host name lookup");
|
|
}
|
|
|
|
// Check if any addresses were added to the list
|
|
|
|
if ( ipList.size() == 0)
|
|
{
|
|
// Log the available IP addresses
|
|
|
|
logger.error("Failed to get IP address(es) for NetBIOS name");
|
|
for ( int i = 0; i < addrs.length; i++)
|
|
logger.error( " Address: " + addrs[i]);
|
|
logger.error("Check hosts file and/or DNS setup");
|
|
logger.error("NetBIOS name server is shutting down");
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Initialize the NetBIOS name socket
|
|
|
|
if (m_socket == null)
|
|
openSocket();
|
|
|
|
// Allocate the NetBIOS request queue, and add the server name/alias name requests
|
|
|
|
m_reqList = new Vector<NetBIOSRequest>();
|
|
|
|
// Add the server name requests to the queue
|
|
|
|
AddName(new NetBIOSName(getConfiguration().getServerName(), NetBIOSName.FileServer, false, ipList,
|
|
DefaultTTL));
|
|
AddName(new NetBIOSName(getConfiguration().getServerName(), NetBIOSName.WorkStation, false, ipList,
|
|
DefaultTTL));
|
|
|
|
if (getConfiguration().getDomainName() != null)
|
|
AddName(new NetBIOSName(getConfiguration().getDomainName(), NetBIOSName.Domain, true, ipList,
|
|
DefaultTTL));
|
|
|
|
// Create the request handler thread
|
|
|
|
m_reqHandler = new NetBIOSRequestHandler();
|
|
m_reqHandler.start();
|
|
|
|
// Create the name refresh thread
|
|
|
|
m_refreshThread = new NetBIOSNameRefresh();
|
|
m_refreshThread.start();
|
|
|
|
// Allocate a receive buffer, NetBIOS packet and datagram packet
|
|
|
|
buf = new byte[1024];
|
|
nbPkt = new NetBIOSPacket(buf);
|
|
pkt = new DatagramPacket(buf, buf.length);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
// Debug
|
|
|
|
logger.error("NetBIOSNameServer setup error:", ex);
|
|
|
|
// Save the exception and inform listeners of the error
|
|
|
|
setException(ex);
|
|
fireServerEvent(ServerListener.ServerError);
|
|
}
|
|
|
|
// If there are any pending requests in the queue then wakeup the request handler thread
|
|
|
|
if (m_reqList != null && m_reqList.size() > 0)
|
|
{
|
|
synchronized (m_reqList)
|
|
{
|
|
m_reqList.notify();
|
|
}
|
|
}
|
|
|
|
// Indicate that the server is active
|
|
|
|
setActive(true);
|
|
fireServerEvent(ServerListener.ServerActive);
|
|
|
|
// Loop
|
|
|
|
if (hasException() == false)
|
|
{
|
|
|
|
// Clear the shutdown request flag
|
|
|
|
m_shutdown = false;
|
|
|
|
while (m_shutdown == false)
|
|
{
|
|
|
|
try
|
|
{
|
|
|
|
// Wait for an incoming packet ....
|
|
|
|
m_socket.receive(pkt);
|
|
|
|
// Check for a zero length datagram
|
|
|
|
if (pkt.getLength() == 0)
|
|
continue;
|
|
|
|
// Get the incoming NetBIOS packet opcode
|
|
|
|
InetAddress fromAddr = pkt.getAddress();
|
|
int fromPort = pkt.getPort();
|
|
|
|
switch (nbPkt.getOpcode())
|
|
{
|
|
|
|
// Name query
|
|
|
|
case NetBIOSPacket.NAME_QUERY:
|
|
processNameQuery(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Name register
|
|
|
|
case NetBIOSPacket.NAME_REGISTER:
|
|
processNameRegister(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Name release
|
|
|
|
case NetBIOSPacket.NAME_RELEASE:
|
|
processNameRelease(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Name register response
|
|
|
|
case NetBIOSPacket.RESP_REGISTER:
|
|
processRegisterResponse(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Name query response
|
|
|
|
case NetBIOSPacket.RESP_QUERY:
|
|
processQueryResponse(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Name release response
|
|
|
|
case NetBIOSPacket.RESP_RELEASE:
|
|
processReleaseResponse(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// WACK
|
|
|
|
case NetBIOSPacket.WACK:
|
|
processWack(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Refresh
|
|
|
|
case NetBIOSPacket.REFRESH:
|
|
processNameRegister(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Multi-homed name registration
|
|
|
|
case NetBIOSPacket.NAME_REGISTER_MULTI:
|
|
processNameRegister(nbPkt, fromAddr, fromPort);
|
|
break;
|
|
|
|
// Unknown opcode
|
|
|
|
default:
|
|
logger.error("Unknown OpCode 0x" + Integer.toHexString(nbPkt.getOpcode()));
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
// Debug
|
|
|
|
if ( m_shutdown == false)
|
|
logger.error("NetBIOSNameServer error", ex);
|
|
|
|
// Store the error and inform listeners of the server error. If the server is
|
|
// shutting down we expect a
|
|
// socket error as the socket is closed by the shutdown thread and the pending
|
|
// read request generates an
|
|
// exception.
|
|
|
|
if (m_shutdown == false)
|
|
{
|
|
setException(ex);
|
|
fireServerEvent(ServerListener.ServerError);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Indicate that the server is closed
|
|
|
|
setActive(false);
|
|
fireServerEvent(ServerListener.ServerShutdown);
|
|
}
|
|
|
|
/**
|
|
* Send a packet via the NetBIOS naming datagram socket.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param len int
|
|
* @exception java.io.IOException The exception description.
|
|
*/
|
|
protected final void sendPacket(NetBIOSPacket nbpkt, int len) throws java.io.IOException
|
|
{
|
|
|
|
// Allocate the datagram packet, using the add name buffer
|
|
|
|
DatagramPacket pkt = new DatagramPacket(nbpkt.getBuffer(), len, NetworkSettings.getBroadcastAddress(),
|
|
getPort());
|
|
|
|
// Send the datagram packet
|
|
|
|
m_socket.send(pkt);
|
|
}
|
|
|
|
/**
|
|
* Send a packet via the NetBIOS naming datagram socket.
|
|
*
|
|
* @param pkt NetBIOSPacket
|
|
* @param len int
|
|
* @param replyAddr InetAddress
|
|
* @param replyPort int
|
|
* @exception java.io.IOException The exception description.
|
|
*/
|
|
protected final void sendPacket(NetBIOSPacket nbpkt, int len, InetAddress replyAddr, int replyPort)
|
|
throws java.io.IOException
|
|
{
|
|
// Allocate the datagram packet, using the add name buffer
|
|
|
|
DatagramPacket pkt = new DatagramPacket(nbpkt.getBuffer(), len, replyAddr, replyPort);
|
|
|
|
// Send the datagram packet
|
|
|
|
m_socket.send(pkt);
|
|
}
|
|
|
|
/**
|
|
* Set the local address that the server should bind to
|
|
*
|
|
* @param addr java.net.InetAddress
|
|
*/
|
|
public final void setBindAddress(InetAddress addr)
|
|
{
|
|
m_bindAddress = addr;
|
|
}
|
|
|
|
/**
|
|
* Set the server port
|
|
*
|
|
* @param port int
|
|
*/
|
|
public final void setServerPort(int port)
|
|
{
|
|
m_port = port;
|
|
}
|
|
|
|
/**
|
|
* Set the primary WINS server address
|
|
*
|
|
* @param addr InetAddress
|
|
*/
|
|
public final void setPrimaryWINSServer(InetAddress addr)
|
|
{
|
|
m_winsPrimary = addr;
|
|
}
|
|
|
|
/**
|
|
* Set the secondary WINS server address
|
|
*
|
|
* @param addr InetAddress
|
|
*/
|
|
public final void setSecondaryWINSServer(InetAddress addr)
|
|
{
|
|
m_winsSecondary = addr;
|
|
}
|
|
|
|
/**
|
|
* Find the NetBIOS request with the specified transation id
|
|
*
|
|
* @param id int
|
|
* @return NetBIOSRequest
|
|
*/
|
|
private final NetBIOSRequest findRequest(int id)
|
|
{
|
|
|
|
// Check if the request list is valid
|
|
|
|
if (m_reqList == null)
|
|
return null;
|
|
|
|
// Need to lock access to the request list
|
|
|
|
NetBIOSRequest req = null;
|
|
|
|
synchronized (m_reqList)
|
|
{
|
|
|
|
// Search for the required request
|
|
|
|
int idx = 0;
|
|
|
|
while (req == null && idx < m_reqList.size())
|
|
{
|
|
|
|
// Get the current request and check if it is the required request
|
|
|
|
NetBIOSRequest curReq = (NetBIOSRequest) m_reqList.elementAt(idx++);
|
|
if (curReq.getTransactionId() == id)
|
|
req = curReq;
|
|
}
|
|
}
|
|
|
|
// Return the request, or null if not found
|
|
|
|
return req;
|
|
}
|
|
|
|
/**
|
|
* Shutdown the NetBIOS name server
|
|
*
|
|
* @param immediate boolean
|
|
*/
|
|
public void shutdownServer(boolean immediate)
|
|
{
|
|
|
|
// Close the name refresh thread
|
|
|
|
try
|
|
{
|
|
|
|
if (m_refreshThread != null)
|
|
{
|
|
m_refreshThread.shutdownRequest();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
// Debug
|
|
|
|
logger.error("Shutdown NetBIOS server error", ex);
|
|
}
|
|
|
|
// If the shutdown is not immediate then release all of the names registered by this server
|
|
|
|
if (isActive() && immediate == false)
|
|
{
|
|
|
|
// Release all local names
|
|
|
|
for (int i = 0; i < m_localNames.size(); i++)
|
|
{
|
|
|
|
// Get the current name details
|
|
|
|
NetBIOSName nbName = (NetBIOSName) m_localNames.elementAt(i);
|
|
|
|
// Queue a delete name request
|
|
|
|
try
|
|
{
|
|
DeleteName(nbName);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
logger.error("Shutdown NetBIOS server error", ex);
|
|
}
|
|
}
|
|
|
|
// Wait for the request handler thread to process the delete name requests
|
|
|
|
while (m_reqList.size() > 0)
|
|
{
|
|
try
|
|
{
|
|
Thread.sleep(100);
|
|
}
|
|
catch (InterruptedException ex)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close the request handler thread
|
|
|
|
try
|
|
{
|
|
|
|
// Close the request handler thread
|
|
|
|
if (m_reqHandler != null)
|
|
{
|
|
m_reqHandler.shutdownRequest();
|
|
m_reqHandler.join(1000);
|
|
m_reqHandler = null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
// Debug
|
|
|
|
logger.error("Shutdown NetBIOS request handler error", ex);
|
|
}
|
|
|
|
// Indicate that the server is closing
|
|
|
|
m_shutdown = true;
|
|
|
|
try
|
|
{
|
|
|
|
// Close the server socket so that any pending receive is cancelled
|
|
|
|
if (m_socket != null)
|
|
{
|
|
|
|
try
|
|
{
|
|
m_socket.close();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
}
|
|
m_socket = null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.error("Shutdown NetBIOS server error", ex);
|
|
}
|
|
|
|
// Fire a shutdown notification event
|
|
|
|
fireServerEvent(ServerListener.ServerShutdown);
|
|
}
|
|
|
|
/**
|
|
* Start the NetBIOS name server is a seperate thread
|
|
*/
|
|
public void startServer()
|
|
{
|
|
|
|
// Create a seperate thread to run the NetBIOS name server
|
|
|
|
m_srvThread = new Thread(this);
|
|
m_srvThread.setName("NetBIOS Name Server");
|
|
m_srvThread.setDaemon(true);
|
|
|
|
m_srvThread.start();
|
|
|
|
// Fire a server startup event
|
|
|
|
fireServerEvent(ServerListener.ServerStartup);
|
|
}
|
|
} |