/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 com.sun.jini.discovery.internal; import com.sun.jini.discovery.UnicastDiscoveryClient; import com.sun.jini.discovery.UnicastResponse; import com.sun.jini.jeri.internal.connection.ConnManager; import com.sun.jini.jeri.internal.connection.ConnManagerFactory; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.util.Collection; import java.util.NoSuchElementException; import javax.net.SocketFactory; import net.jini.core.constraint.InvocationConstraints; import net.jini.io.UnsupportedConstraintException; import net.jini.jeri.Endpoint; import net.jini.jeri.OutboundRequest; import net.jini.jeri.OutboundRequestIterator; import net.jini.jeri.connection.Connection; import net.jini.jeri.connection.ConnectionEndpoint; import net.jini.jeri.connection.OutboundRequestHandle; /** * Provides an abstract endpoint-based UnicastDiscoveryClient implementation, * which serves as a superclass for client-side providers for the * net.jini.discovery.ssl and net.jini.discovery.kerberos unicast discovery * formats. */ public abstract class EndpointBasedClient extends EndpointBasedProvider implements UnicastDiscoveryClient { /** * Constructs instance with the given format name and object providing * access to non-public endpoint operations. */ protected EndpointBasedClient(String formatName, EndpointInternals endpointInternals) { super(formatName, endpointInternals); } // documentation inherited from UnicastDiscoveryClient public void checkUnicastDiscoveryConstraints( InvocationConstraints constraints) throws UnsupportedConstraintException { if (constraints == null) { constraints = InvocationConstraints.EMPTY; } ConnectionInfo ci = getConnectionInfo(null, constraints); checkIntegrity(endpointInternals.getUnfulfilledConstraints(ci.handle)); } // documentation inherited from UnicastDiscoveryClient public UnicastResponse doUnicastDiscovery( Socket socket, InvocationConstraints constraints, ClassLoader defaultLoader, ClassLoader verifierLoader, Collection context, ByteBuffer sent, ByteBuffer received) throws IOException, ClassNotFoundException { if (socket == null || sent == null || received == null) { throw new NullPointerException(); } if (constraints == null) { constraints = InvocationConstraints.EMPTY; } ConnectionInfo ci = getConnectionInfo(socket, constraints); Connection conn = ci.endpoint.connect(ci.handle); try { boolean integrity = checkIntegrity(conn.getUnfulfilledConstraints(ci.handle)); OutputStream out = new BufferedOutputStream(conn.getOutputStream()); conn.writeRequestData(ci.handle, out); out.write(calcHandshakeHash(sent, received)); out.flush(); InputStream in = new BufferedInputStream(conn.getInputStream()); IOException e = conn.readResponseData(ci.handle, in); if (e != null) { throw e; } return Plaintext.readUnicastResponse( in, defaultLoader, integrity, verifierLoader, context); } finally { conn.close(); } } /** * Returns an endpoint which uses the given socket factory, if non-null, * and may incorporate information (such as the expected server principal) * from the given set of constraints, if non-null. Other parameters of the * endpoint, such as the target host and port, are irrelevant from the * standpoint of this class and can be chosen arbitrarily. Throws an * UnsupportedConstraintException if the given constraints lack information * needed to construct the endpoint. */ protected abstract Endpoint getEndpoint(SocketFactory factory, InvocationConstraints constraints) throws UnsupportedConstraintException; /** * Returns components needed to initiate a connection over the given socket * in accordance with the specified constraints. */ private ConnectionInfo getConnectionInfo(Socket socket, InvocationConstraints constraints) throws UnsupportedConstraintException { Endpoint ep = getEndpoint(new PrearrangedSocketFactory(socket), constraints); ConnManagerFactoryImpl factory = new ConnManagerFactoryImpl(); endpointInternals.setConnManagerFactory(ep, factory); endpointInternals.disableSocketConnect(ep); OutboundRequestIterator iter = ep.newRequest(constraints); ConnectionInfo ci = factory.getConnectionInfo(); if (ci != null) { return ci; } /* * Connection manager was never consulted, so constraints must not be * supported. The resulting endpoint-fabricated outbound request * iterator should throw UnsupportedConstraintException from its next * method. */ if (iter.hasNext()) { try { iter.next(); } catch (UnsupportedConstraintException e) { throw e; } catch (IOException e) { } } throw new AssertionError("expected UnsupportedConstraintException"); } /** * Components for initiating a connection. */ private static class ConnectionInfo { final ConnectionEndpoint endpoint; final OutboundRequestHandle handle; ConnectionInfo(ConnectionEndpoint endpoint, OutboundRequestHandle handle) { this.endpoint = endpoint; this.handle = handle; } } /** * Factory which produces connection managers that capture the * OutboundRequestHandle and ConnectionEndpoint instances used to initiate * connections, and then return empty OutboundRequestIterators. */ private static class ConnManagerFactoryImpl implements ConnManagerFactory { private ConnectionInfo connInfo = null; ConnManagerFactoryImpl() { } public ConnManager create(final ConnectionEndpoint endpoint) { if (endpoint == null) { throw new NullPointerException(); } return new ConnManager() { public OutboundRequestIterator newRequest( OutboundRequestHandle handle) { if (handle == null) { throw new NullPointerException(); } connInfo = new ConnectionInfo(endpoint, handle); return new OutboundRequestIterator() { public boolean hasNext() { return false; } public OutboundRequest next() throws IOException { throw new NoSuchElementException(); } }; } }; } ConnectionInfo getConnectionInfo() { return connInfo; } } /** * Socket factory which returns a prearranged socket. */ private static class PrearrangedSocketFactory extends SocketFactory { private final Socket socket; PrearrangedSocketFactory(Socket socket) { this.socket = socket; } public Socket createSocket() throws IOException { return socket; } public Socket createSocket(String host, int port) throws IOException { return socket; } public Socket createSocket(InetAddress host, int port) throws IOException { return socket; } public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { return socket; } public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException { return socket; } public String toString() { return "PrearrangedSocketFactory[" + socket + "]"; } } }