/*
* 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.netbios.win32;
import java.io.IOException;
import java.nio.channels.IllegalBlockingModeException;
import org.alfresco.jlan.netbios.NetBIOSName;
/**
* NetBIOS Socket Class
*
* <p>
* Contains the details of a Winsock NetBIOS socket that was opened using native code.
*
* @author gkspencer
*/
public class NetBIOSSocket {
// Status value to indicate that a write could not be don as it would block the socket
public static final int SocketWouldBlock = -2;
// Flag to indicate if the NetBIOS socket interface has been initialized
private static boolean _nbSocketInit;
// NetBIOS LANA that the socket is associated with
private int m_lana;
// Socket pointer (Windows SOCKET)
private int m_socket;
// NetBIOS name, either listening name or callers name
private NetBIOSName m_nbName;
// Flag to indicate if this is a listener socket
private boolean m_listenerSocket;
// Socket blocking mode, true if in non-blocking mode
private boolean m_nonBlockMode;
// Associated selector
private NetBIOSSelector m_selector;
/**
* Initialize the Winsock NetBIOS interface
*/
public static final void initializeSockets()
throws WinsockNetBIOSException {
// Check if the NetBIOS socket interface has been initialized
if ( _nbSocketInit == false) {
// Initialize the NetBIOS socket interface
Win32NetBIOS.InitializeSockets();
// Indicate that the NetBIOS socket interface is initialized
_nbSocketInit = true;
}
}
/**
* Shutdown the Winsock NetBIOS interface
*/
public static final void shutdownSockets() {
// Check if the NetBIOS socket interface has been initialized
if ( _nbSocketInit == true) {
// Indicate that the NetBIOS socket interface is not initialized
_nbSocketInit = false;
// Initialize the NetBIOS socket interface
Win32NetBIOS.ShutdownSockets();
}
}
/**
* Determine if the Winsock NetBIOS interface is initialized
*
* @return boolean
*/
public static final boolean isInitialized() {
return _nbSocketInit;
}
/**
* Wait for one or more asynchronous sockets to trigger a receive event
*
* @param sockCnt int
* @param sockList int[]
* @param sockEvent int[]
* @return int
* @exception WinsockNetBIOSException
*/
public static final int SelectReceiveSockets( int sockCnt, int[] sockList, int[] sockEvent)
throws WinsockNetBIOSException {
// Wait for one or more sockets in the list to trigger receive events
return Win32NetBIOS.SelectReceiveSockets( sockCnt, sockList, sockEvent);
}
/**
* Create a NetBIOS socket to listen for incoming sessions on the specified LANA
*
* @param lana int
* @param nbName NetBIOSName
* @return NetBIOSSocket
* @exception NetBIOSSocketException
* @exception WinsockNetBIOSException
*/
public static final NetBIOSSocket createListenerSocket(int lana, NetBIOSName nbName)
throws WinsockNetBIOSException, NetBIOSSocketException {
// Create the listener socket, check for duplicate names when registering
return NetBIOSSocket.createListenerSocket(lana, nbName, false);
}
/**
* Create a NetBIOS socket to listen for incoming sessions on the specified LANA
*
* @param lana int
* @param nbName NetBIOSName
* @param fastAddName boolean
* @return NetBIOSSocket
* @exception NetBIOSSocketException
* @exception WinsockNetBIOSException
*/
public static final NetBIOSSocket createListenerSocket(int lana, NetBIOSName nbName, boolean fastAddName)
throws WinsockNetBIOSException, NetBIOSSocketException {
// Initialize the Winsock NetBIOS interface
initializeSockets();
// Create a new NetBIOS socket
int sockPtr = Win32NetBIOS.CreateSocket(lana);
if ( sockPtr == 0)
throw new NetBIOSSocketException("Failed to create NetBIOS socket");
// Bind the socket to a NetBIOS name
if ( Win32NetBIOS.BindSocket(sockPtr, nbName.getNetBIOSName(), fastAddName) != 0)
throw new NetBIOSSocketException("Failed to bind NetBIOS socket");
// Return the NetBIOS socket
return new NetBIOSSocket(lana, sockPtr, nbName, true);
}
/**
* Create a NetBIOS socket that is connected to a remote server/service
*
* @param lana int
* @param remoteName NetBIOSName
* @return NetBIOSSocket
* @exception NetBIOSSocketException
* @exception WinsockNetBIOSException
*/
public static final NetBIOSSocket connectSocket( int lana, NetBIOSName remoteName)
throws WinsockNetBIOSException, NetBIOSSocketException {
// Initialize the Winsock NetBIOS interface
initializeSockets();
// Create a new NetBIOS socket
int sockPtr = Win32NetBIOS.CreateSocket(lana);
if ( sockPtr == 0)
throw new NetBIOSSocketException("Failed to create NetBIOS socket");
// Connect to the remote server/service
Win32NetBIOS.ConnectSocket( sockPtr, remoteName.getNetBIOSName());
// Return the NetBIOS socket
return new NetBIOSSocket(lana, sockPtr, remoteName, false);
}
/**
* Class constructor
*
* @param lana int
* @param sockPtr int
* @param nbName NetBIOSName
* @param listener boolean
*/
private NetBIOSSocket(int lana, int sockPtr, NetBIOSName nbName, boolean listener) {
m_lana = lana;
m_nbName = nbName;
m_socket = sockPtr;
m_listenerSocket = listener;
}
/**
* Return the NetBIOS LANA the socket is associated with
*
* @return int
*/
public final int getLana() {
return m_lana;
}
/**
* Determine if this is a listener type socket
*
* @return boolean
*/
public final boolean isListener() {
return m_listenerSocket;
}
/**
* Determine if the socket is valid
*
* @return boolean
*/
public final boolean hasSocket() {
return m_socket != 0 ? true : false;
}
/**
* Return the socket pointer
*
* @return int
*/
public final int getSocket() {
return m_socket;
}
/**
* Return the NetBIOS name. For a listening socket this is the local name, for a session socket
* this is the remote callers name.
*
* @return NetBIOSName
*/
public final NetBIOSName getName() {
return m_nbName;
}
/**
* Set this socket to use non-blocking I/O
*
* @param nonBlocking boolean
* @exception WinsockNetBIOSException
*/
public final void configureBlocking( boolean nonBlocking)
throws WinsockNetBIOSException {
// Set the non-blocking mode of the socket
Win32NetBIOS.SetNonBlockingSocket( getSocket(), nonBlocking);
// save the new setting
m_nonBlockMode = nonBlocking ? false : true;
}
/**
* Write data to the session socket
*
* @param buf byte[]
* @param off int
* @param len int
* @return int
* @exception WinsockNetBIOSException
*/
public final int write(byte[] buf, int off, int len)
throws WinsockNetBIOSException {
return Win32NetBIOS.SendSocket(getSocket(), buf, off, len);
}
/**
* Return the available data length for the socket
*
* @return int
* @exception WinsockNetBIOSException
*/
public final int available()
throws WinsockNetBIOSException {
return Win32NetBIOS.ReceiveLengthSocket( getSocket());
}
/**
* Read data from the session socket
*
* @param buf byte[]
* @param off int
* @param maxLen int
* @return int
* @exception WinsockNetBIOSException
*/
public final int read(byte[] buf, int off, int maxLen)
throws WinsockNetBIOSException {
return Win32NetBIOS.ReceiveSocket(getSocket(), buf, off, maxLen);
}
/**
* Accept an incoming session connection and create a session socket for the new session. If the socket is in
* blocking mode then it will not return until a connection is received.
*
* @return NetBIOSSocket
* @exception NetBIOSSocketException
* @exception winsockNetBIOSException
*/
public final NetBIOSSocket accept()
throws WinsockNetBIOSException, NetBIOSSocketException {
// Check if this socket is a listener socket, and the socket is valid
if ( isListener() == false)
throw new NetBIOSSocketException("Not a listener type socket");
if ( hasSocket() == false)
throw new NetBIOSSocketException("NetBIOS socket not valid");
// Wait for an incoming session request
byte[] callerName = new byte[NetBIOSName.NameLength];
int sessSockPtr = Win32NetBIOS.ListenSocket(getSocket(), callerName);
if ( sessSockPtr == 0)
throw new NetBIOSSocketException("NetBIOS socket listen failed");
// Return the new NetBIOS socket session
return new NetBIOSSocket(getLana(), sessSockPtr, new NetBIOSName(callerName, 0), false);
}
/**
* Close the socket
*/
public final void closeSocket() {
// Close the native socket, if valid
if ( hasSocket()) {
// Check if the socket is registered with a selector, remove from the selector
if ( m_selector != null) {
// Remove from the selector
try {
m_selector.deregisterSocket( this);
}
catch ( Exception ex) {
}
// Clear the selector
m_selector = null;
}
// Close the socket
Win32NetBIOS.CloseSocket(getSocket());
setSocket(0);
}
}
/**
* Check if this socket is in a non-blocking mode
*
* @return boolean
*/
public final boolean isNonBlocking() {
return m_nonBlockMode;
}
/**
* Set the socket pointer
*
* @param sockPtr int
*/
protected final void setSocket(int sockPtr) {
m_socket = sockPtr;
}
/**
* Register a non-blocking socket with a selector
*
* @param selector NetBIOSSelector
* @param ops int
* @param attachment Object
* @return NetBIOSSelectionKey
* @exception IllegalBlockingModeException
* @exception IOException
*/
public final NetBIOSSelectionKey register( NetBIOSSelector selector, int ops, Object attachment)
throws IllegalBlockingModeException, IOException {
// Check if the socket is in blocking I/O mode
if ( isNonBlocking() == false)
throw new IllegalBlockingModeException();
// Check if the selector is valid
if ( selector == null)
throw new IOException("Null NetBIOS selector");
// Register with the selector
NetBIOSSelectionKey selKey = selector.registerSocket(this, ops);
if ( selKey != null) {
selKey.attach( attachment);
m_selector = selector;
}
// Return the selection key
return selKey;
}
/**
* Return the NetBIOS socket details as a string
*
* @return String
*/
public String toString() {
StringBuffer str = new StringBuffer();
str.append("[LANA:");
str.append(getLana());
str.append(",Name:");
str.append(getName());
str.append(",Socket:");
if ( hasSocket()) {
str.append("0x");
str.append(Integer.toHexString(getSocket()));
}
else
str.append("<None>");
if ( isListener())
str.append(",Listener");
if ( isNonBlocking())
str.append(",NonBlocking");
str.append("]");
return str.toString();
}
/**
* Return a hash code for the NetBIOS socket, using the socket id
*
* @return int
*/
public int hashCode() {
return getSocket();
}
}