/*
* 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 java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
/**
* NetBIOS Selector Class
*
* <p>Selector type class for NetBIOSSocket objects. Groups a set of sockets to wait for events on.
*
* @author gkspencer
*/
public class NetBIOSSelector {
// Constrants
//
// Initial allocation size for the socket id array
private static final int DefaultSockArraySize = 64;
// Array of socket ids
private int[] m_sockIds;
private int[] m_eventIds;
// Hash table to link socket ids to selection keys
private Hashtable<Integer, NetBIOSSelectionKey> m_selectionKeys;
private Set<Integer> m_keySet;
// Current list of sockets that have triggered events
private Set<NetBIOSSelectionKey> m_triggeredKeys;
/**
* Default constructor
*/
public NetBIOSSelector() {
m_sockIds = new int[DefaultSockArraySize];
m_selectionKeys = new Hashtable<Integer, NetBIOSSelectionKey>();
m_keySet = m_selectionKeys.keySet();
m_triggeredKeys = new HashSet<NetBIOSSelectionKey>();
}
/**
* Class constructor
*
* @param initSize int
*/
public NetBIOSSelector(int initSize) {
m_sockIds = new int[initSize];
m_selectionKeys = new Hashtable<Integer, NetBIOSSelectionKey>();
m_keySet = m_selectionKeys.keySet();
m_triggeredKeys = new HashSet<NetBIOSSelectionKey>();
}
/**
* Register a socket with this selector
*
* @param socket NetBIOSSocket
* @param ops int
* @return NetBIOSSelectionKey
* @exception IOException
* @exception IllegalblockingModeException
*/
protected final NetBIOSSelectionKey registerSocket(NetBIOSSocket socket, int ops)
throws IOException, IllegalBlockingModeException {
NetBIOSSelectionKey selKey = null;
synchronized ( m_selectionKeys) {
// Check if the socket is already registered with this selector
Integer key = new Integer( socket.getSocket());
if ( m_selectionKeys.containsKey( key))
throw new IOException( "Socket already registered with selector");
// Check if hte socket is in non-blocking mode
if ( socket.isNonBlocking() == false)
throw new IllegalBlockingModeException();
// Create the selection key
selKey = new NetBIOSSelectionKey( this, socket, ops, null);
m_selectionKeys.put( key, selKey);
}
// Return the new selection key
return selKey;
}
/**
* Remove a socket from this selector
*
* @param socket NetBIOSSocket
* @return NetBIOSSelectionKey
*/
public final NetBIOSSelectionKey deregisterSocket( NetBIOSSocket socket)
throws IOException {
// Remove the selection key for the specified socket
NetBIOSSelectionKey selKey = m_selectionKeys.remove( new Integer( socket.getSocket()));
// Remove from the triggered set
if ( selKey != null)
m_triggeredKeys.remove( selKey);
// Return the removed selection key, or null if not found
return selKey;
}
/**
* Wait for events to trigger on one or more sockets
*
* @return int
* @exception WinsockNetBIOSException
*/
public final int select()
throws WinsockNetBIOSException {
int idx = 0;
synchronized ( m_selectionKeys) {
// Build the array of socket ids to listen for events on
if ( m_sockIds.length < m_selectionKeys.size())
m_sockIds = new int[m_selectionKeys.size()];
// Copy sockets that are interested in accept or read events to the socket id list
Iterator<Integer> keys = m_keySet.iterator();
while ( keys.hasNext()) {
// Get the current selection key and check if is interested in accept or read events
Integer curKey = keys.next();
NetBIOSSelectionKey selKey = m_selectionKeys.get( curKey);
if ( m_triggeredKeys.contains( selKey) == false &&
( selKey.interestOps() & NetBIOSSelectionKey.OP_ACCEPT + NetBIOSSelectionKey.OP_READ) != 0) {
// Add the socket id to the list
m_sockIds[idx++] = selKey.socket().getSocket();
}
}
}
// Check if any sockets were added to the list
if ( idx == 0)
return 0;
// Allocate the array to hold the socket ids of the triggered sockets
if ( m_eventIds == null || m_eventIds.length != m_sockIds.length)
m_eventIds = new int[m_sockIds.length];
// Clear the current list of triggered sockets
m_triggeredKeys.clear();
// Wait for one or more sockets to generate an event
int eventCnt = Win32NetBIOS.SelectReceiveSockets( idx, m_sockIds, m_eventIds);
if ( eventCnt > 0) {
// Add triggered socket selection keys to the triggered list
for ( int i = 0; i < eventCnt; i++) {
// Get the selection key for the triggered socket, add to the triggered set
NetBIOSSelectionKey selKey = m_selectionKeys.get( new Integer( m_eventIds[ i]));
if ( selKey != null) {
selKey.setTriggers( selKey.socket().isListener() ? NetBIOSSelectionKey.OP_ACCEPT : NetBIOSSelectionKey.OP_READ);
m_triggeredKeys.add( selKey);
}
}
}
// Return the count of triggered sockets
return eventCnt;
}
/**
* Close the NetBIOS selector
*/
public final void close() {
// Clear the selection keys
m_selectionKeys.clear();
m_triggeredKeys.clear();
}
/**
* Return the full selection key list
*
* @return Set<Integer>
*/
public final Set<Integer> keys() {
return m_keySet;
}
/**
* Return the selection key for the specified key
*
* @param key Integer
* @return NetBIOSSelectionKey
*/
public final NetBIOSSelectionKey getSelectionKey( Integer key) {
return m_selectionKeys.get( key);
}
/**
* Return the selected keys from the last select
*
* @return Set<NetBIOSSelectionKey>
*/
public final Set<NetBIOSSelectionKey> selectedKeys() {
return m_triggeredKeys;
}
}