summaryrefslogtreecommitdiff
path: root/src/com/sun/apoc/daemon/admin/AdminManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/sun/apoc/daemon/admin/AdminManager.java')
-rw-r--r--src/com/sun/apoc/daemon/admin/AdminManager.java286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/com/sun/apoc/daemon/admin/AdminManager.java b/src/com/sun/apoc/daemon/admin/AdminManager.java
new file mode 100644
index 0000000..3dfcf68
--- /dev/null
+++ b/src/com/sun/apoc/daemon/admin/AdminManager.java
@@ -0,0 +1,286 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either
+ * the GNU General Public License Version 2 only ("GPL") or
+ * the Common Development and Distribution License("CDDL")
+ * (collectively, the "License"). You may not use this file
+ * except in compliance with the License. You can obtain a copy
+ * of the License at www.sun.com/CDDL or at COPYRIGHT. See the
+ * License for the specific language governing permissions and
+ * limitations under the License. When distributing the software,
+ * include this License Header Notice in each file and include
+ * the License file at /legal/license.txt. If applicable, add the
+ * following below the License Header, with the fields enclosed
+ * by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by
+ * only the CDDL or only the GPL Version 2, indicate your
+ * decision by adding "[Contributor] elects to include this
+ * software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice
+ * of license, a recipient has the option to distribute your
+ * version of this file under either the CDDL, the GPL Version
+ * 2 or to extend the choice of license to its licensees as
+ * provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the
+ * option applies only if the new code is made subject to such
+ * option by the copyright holder.
+ */
+package com.sun.apoc.daemon.admin;
+
+import com.sun.apoc.daemon.config.*;
+import com.sun.apoc.daemon.misc.*;
+import com.sun.apoc.daemon.transport.*;
+
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+
+public class AdminManager extends Thread
+{
+ private static final byte[] sSuccess = { 0 };
+ private static final byte[] sFailure = { 1 };
+ private static final byte sOpChangeDetect = ( byte )1;
+ private static final byte sOpReload = ( byte )6;
+ private static final byte sOpStatus = ( byte )9;
+ private static final byte sOpStop = ( byte )10;
+
+ private static final byte[] sAcceptByte = { 1 };
+ private static final ByteBuffer sAccept =
+ ( ByteBuffer )ByteBuffer.wrap( sAcceptByte );
+
+ private Selector mSelector;
+ private ServerSocketChannel mChannel;
+ private AdminOpHandler mAdminOpHandler;
+ private final Object mTerminateLock = new Object();
+ private boolean mTerminate = false;
+
+ public AdminManager( final AdminOpHandler inAdminOpHandler )
+ throws APOCException
+ {
+ setName( "AdminManager" );
+ mAdminOpHandler = inAdminOpHandler;
+ initChannel();
+ }
+
+ public void run()
+ {
+ APOCLogger.fine( "Admr001" );
+ while ( ! shouldTerminate() )
+ {
+ try
+ {
+ final ClientChannel theChannel = acceptClientChannel();
+ if ( theChannel != null )
+ {
+ if ( authenticate( theChannel ) )
+ {
+ try
+ {
+ handleRequest( theChannel );
+ }
+ catch( Exception theException )
+ {
+ APOCLogger.throwing( "AdminManager",
+ "run",
+ theException );
+ }
+ }
+ theChannel.close();
+ }
+ }
+ catch ( IOException theException )
+ {
+ APOCLogger.throwing( "AdminManager", "run", theException );
+ break;
+ }
+ }
+ closeServerChannel();
+ APOCLogger.fine( "Admr002" );
+ }
+
+ public void terminate()
+ {
+ synchronized( mTerminateLock )
+ {
+ mTerminate = true;
+ }
+ }
+
+ private ClientChannel acceptClientChannel()
+ throws IOException
+ {
+ ClientChannel theChannel = null;
+ if ( mSelector.select() > 0 )
+ {
+ final Iterator theIterator = mSelector.selectedKeys().iterator();
+ while ( theIterator.hasNext() )
+ {
+ final SelectionKey theKey = ( SelectionKey )theIterator.next();
+ theIterator.remove();
+ if ( theKey.isAcceptable() )
+ {
+ SocketChannel theSocketChannel = null;
+ try
+ {
+ theSocketChannel =
+ (( ServerSocketChannel )theKey.channel() ).accept();
+ if ( theSocketChannel.
+ socket().
+ getInetAddress().
+ isLoopbackAddress() )
+ {
+ theChannel =
+ new ClientChannel( theSocketChannel, null);
+ theChannel.write( sAccept );
+ sAccept.flip();
+ break;
+ }
+ }
+ catch( IOException theException )
+ {
+ if ( theSocketChannel != null )
+ {
+ try
+ {
+ theSocketChannel.close();
+ }
+ catch( IOException ignore ){}
+ }
+ APOCLogger.throwing( "AdminManager",
+ "acceptClientChannel",
+ theException );
+ }
+ }
+ }
+ }
+ return theChannel;
+ }
+
+ private boolean authenticate( final ClientChannel inChannel )
+ {
+ boolean isAuthenticated;
+ APOCAuthenticator theAuthenticator = null;
+ try
+ {
+ theAuthenticator = new APOCAuthenticator( null );
+ byte[] theChallenge = theAuthenticator.getChallenge();
+ inChannel.write(
+ ( ByteBuffer )ByteBuffer.allocate( theChallenge.length + 1 )
+ .put( theChallenge )
+ .put( ( byte )0 )
+ .flip() );
+ ByteBuffer theAuthBuffer =
+ ByteBuffer.wrap(
+ new byte[ APOCAuthenticator.getAuthBufferSize() ] );
+ while ( inChannel.read( theAuthBuffer ) == 0 ){}
+ theAuthenticator.processResponse( theAuthBuffer.array() );
+ inChannel.write(
+ ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sSuccess ).flip() );
+ isAuthenticated = true;
+ }
+ catch( Exception theException )
+ {
+ inChannel.write(
+ ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sFailure ).flip() );
+ isAuthenticated = false;
+ }
+ finally
+ {
+ if ( theAuthenticator != null )
+ {
+ theAuthenticator.cleanup();
+ }
+ }
+ return isAuthenticated;
+ }
+
+ private void closeServerChannel()
+ {
+ try
+ {
+ mSelector.close();
+ mChannel.close();
+ }
+ catch( IOException theException )
+ {
+ APOCLogger.throwing( "AdminManager",
+ "closeServerChannel",
+ theException );
+ }
+ }
+
+ private void handleRequest( final ClientChannel inChannel )
+ throws Exception
+ {
+ int theRC;
+ ByteBuffer theBuffer = ByteBuffer.wrap( new byte[ 1 ] );
+ while ( inChannel.read( theBuffer ) != 1 ){}
+ switch( theBuffer.array()[ 0 ] )
+ {
+ case sOpStop:
+ theRC = mAdminOpHandler.onStop();
+ terminate();
+ break;
+
+ case sOpStatus:
+ theRC = mAdminOpHandler.onStatus();
+ break;
+
+ case sOpReload:
+ theRC = mAdminOpHandler.onReload();
+ break;
+
+ case sOpChangeDetect:
+ theRC = mAdminOpHandler.onChangeDetect();
+ break;
+
+ default:
+ theRC = -1;
+ break;
+ }
+ theBuffer = ByteBuffer.wrap( theRC == 0 ? sSuccess : sFailure );
+ inChannel.write( theBuffer );
+ }
+
+ private void initChannel()
+ throws APOCException
+ {
+ try
+ {
+ mSelector = Selector.open();
+ mChannel = ServerSocketChannel.open();
+ mChannel.configureBlocking( false );
+ mChannel.socket().bind( null );
+ mChannel.register( mSelector, SelectionKey.OP_ACCEPT );
+ /*
+ * 6417539 - Need to use IANA registered port
+ * Use a PortMapper instance to let admin. clients
+ * know which port the agent is using.
+ */
+ new PortMapper(
+ ( ( InetSocketAddress )mChannel.socket().getLocalSocketAddress() )
+ .getPort() ).start();
+ }
+ catch( IOException theException )
+ {
+ throw new APOCException( theException );
+ }
+ }
+
+ private boolean shouldTerminate()
+ {
+ synchronized( mTerminateLock )
+ {
+ return mTerminate;
+ }
+ }
+}