blob: b257a220b67f73b3a0bce135e4d0bb1088d9b091 [file] [log] [blame]
/*
* 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 org.apache.yoko.orb.OCI.IIOP;
import static org.apache.yoko.orb.OCI.IIOP.Exceptions.*;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.yoko.orb.OCI.ConnectCB;
import org.apache.yoko.orb.OCI.Connector;
import org.apache.yoko.orb.OCI.ProfileInfo;
import org.apache.yoko.orb.OCI.ProfileInfoHolder;
import org.omg.CORBA.Policy;
import org.omg.CSIIOP.TAG_CSI_SEC_MECH_LIST;
import org.omg.IOP.Codec;
import org.omg.IOP.IOR;
import org.omg.IOP.TaggedComponent;
final class Connector_impl extends org.omg.CORBA.LocalObject implements Connector {
// the real logger backing instance. We use the interface class as the locator
static final Logger logger = Logger.getLogger(Connector.class.getName());
private final IOR ior_; // the target IOR we're connecting with
private final Policy[] policies_; // the policies used for the connection.
private boolean keepAlive_; // The keepalive flag
private final ConnectorInfo_impl info_; // Connector information
private java.net.Socket socket_; // The socket
private ListenerMap listenMap_;
private final ConnectionHelper connectionHelper_;
private byte[] transportInfo;
private final ExtendedConnectionHelper extendedConnectionHelper_;
private final Codec codec_;
// ------------------------------------------------------------------
// Private and protected functions
// ------------------------------------------------------------------
private void close() {
logger.fine("Closing connection to host=" + this.info_.getHost() + ", port=" + this.info_.getPort());
//
// Close the socket
//
try {
socket_.close();
socket_ = null;
} catch (java.io.IOException ex) {
//ignore
}
}
// ------------------------------------------------------------------
// Standard IDL to Java Mapping
// ------------------------------------------------------------------
public String id() {
return PLUGIN_ID.value;
}
public int tag() {
return org.omg.IOP.TAG_INTERNET_IOP.value;
}
public org.apache.yoko.orb.OCI.Transport connect() {
if (socket_ != null)
close();
//
// Get the address
//
java.net.InetAddress address;
try {
address = java.net.InetAddress.getByName(this.info_.getHost());
} catch (java.net.UnknownHostException ex) {
logger.log(Level.FINE, "Host resolution error", ex);
throw asCommFailure(ex);
}
//
// Create socket and connect
//
try {
logger.fine("Connecting to host=" + address + ", port=" + this.info_.getPort());
if (connectionHelper_ != null) {
socket_ = connectionHelper_.createSocket(ior_, policies_, address, this.info_.getPort());
} else {
socket_ = extendedConnectionHelper_.createSocket(ior_, policies_, address, this.info_.getPort());
}
logger.fine("Connection created with socket " + socket_);
} catch (java.net.ConnectException ex) {
logger.log(Level.FINE, "Error connecting to host=" + address + ", port=" + this.info_.getPort(), ex);
throw new org.omg.CORBA.TRANSIENT(
org.apache.yoko.orb.OB.MinorCodes
.describeTransient(org.apache.yoko.orb.OB.MinorCodes.MinorConnectFailed)
+ "Error connecting to host=" + address + ", port=" + this.info_.getPort() + ": " + ex.getMessage(),
org.apache.yoko.orb.OB.MinorCodes.MinorConnectFailed,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
} catch (java.io.IOException ex) {
logger.log(Level.FINE, "Error connecting to host=" + address + ", port=" + this.info_.getPort(), ex);
throw (org.omg.CORBA.COMM_FAILURE)new org.omg.CORBA.COMM_FAILURE(
org.apache.yoko.orb.OB.MinorCodes
.describeCommFailure(org.apache.yoko.orb.OB.MinorCodes.MinorSocket)
+ "Error connecting to host=" + address + ", port=" + this.info_.getPort() + ": " + ex.getMessage(),
org.apache.yoko.orb.OB.MinorCodes.MinorSocket,
org.omg.CORBA.CompletionStatus.COMPLETED_NO).initCause(ex);
}
//
// Set TCP_NODELAY and SO_KEEPALIVE options
//
try {
socket_.setTcpNoDelay(true);
if (keepAlive_)
socket_.setKeepAlive(true);
} catch (java.net.SocketException ex) {
logger.log(Level.FINE, "Socket setup error", ex);
try {
socket_.close();
} catch (java.io.IOException e) {
}
throw Exceptions.asCommFailure(ex);
}
//
// Create new transport
//
org.apache.yoko.orb.OCI.Transport tr = null;
try {
tr = new Transport_impl(socket_, listenMap_);
socket_ = null;
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Transport creation error", ex);
try {
socket_.close();
} catch (java.io.IOException e) {
}
throw ex;
}
//
// Call callbacks
//
org.apache.yoko.orb.OCI.TransportInfo trInfo = tr.get_info();
try {
info_._OB_callConnectCB(trInfo);
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Connection callback error", ex);
tr.close();
throw ex;
}
//
// Return new transport
//
return tr;
}
//
// Helper class for connect_timeout()
//
private class ConnectTimeout extends Thread {
private java.net.InetAddress address_ = null;
private java.net.Socket so_ = null;
private java.io.IOException ex_ = null;
private boolean finished_ = false;
private boolean timeout_ = false;
ConnectTimeout(java.net.InetAddress address) {
address_ = address;
}
public void run() {
try {
if (connectionHelper_ != null) {
so_ = connectionHelper_.createSocket(ior_, policies_, address_, Connector_impl.this.info_.getPort());
} else {
so_ = extendedConnectionHelper_.createSocket(ior_, policies_, address_, Connector_impl.this.info_.getPort());
}
} catch (java.io.IOException ex) {
logger.log(Level.FINE, "Socket creation error", ex);
ex_ = ex;
}
synchronized (this) {
if (timeout_) {
if (so_ != null) {
try {
so_.close();
} catch (java.io.IOException ex) {
}
so_ = null;
}
} else {
finished_ = true;
ConnectTimeout.this.notify();
}
}
}
synchronized java.net.Socket waitForConnect(int t)
throws java.io.IOException {
while (!finished_) {
try {
ConnectTimeout.this.wait(t);
} catch (InterruptedException ex) {
continue;
}
if (!finished_) // Timeout
{
timeout_ = true;
return null;
}
}
if (so_ != null) // Connect succeeded
return so_;
if (ex_ != null) // Connect failed
throw ex_;
throw new InternalError();
}
}
public org.apache.yoko.orb.OCI.Transport connect_timeout(int t) {
if (socket_ != null)
close();
//
// Get the address
//
java.net.InetAddress address = null;
try {
address = java.net.InetAddress.getByName(this.info_.getHost());
} catch (java.net.UnknownHostException ex) {
logger.log(Level.FINE, "Host resolution error", ex);
throw asCommFailure(ex);
}
//
// Create socket and connect
//
try {
ConnectTimeout connectTimeout = new ConnectTimeout(address);
connectTimeout.start();
socket_ = connectTimeout.waitForConnect(t);
if (socket_ == null)
return null;
} catch (java.net.ConnectException ex) {
logger.log(Level.FINE, "Socket connection error", ex);
throw new org.omg.CORBA.TRANSIENT(
org.apache.yoko.orb.OB.MinorCodes
.describeTransient(org.apache.yoko.orb.OB.MinorCodes.MinorConnectFailed)
+ ": " + ex.getMessage(),
org.apache.yoko.orb.OB.MinorCodes.MinorConnectFailed,
org.omg.CORBA.CompletionStatus.COMPLETED_NO);
} catch (java.io.IOException ex) {
logger.log(Level.FINE, "Socket I/O error", ex);
throw (org.omg.CORBA.COMM_FAILURE)new org.omg.CORBA.COMM_FAILURE(
org.apache.yoko.orb.OB.MinorCodes
.describeCommFailure(org.apache.yoko.orb.OB.MinorCodes.MinorSocket)
+ ": " + ex.getMessage(),
org.apache.yoko.orb.OB.MinorCodes.MinorSocket,
org.omg.CORBA.CompletionStatus.COMPLETED_NO).initCause(ex);
}
//
// Set TCP_NODELAY and SO_KEEPALIVE options
//
try {
socket_.setTcpNoDelay(true);
if (keepAlive_)
socket_.setKeepAlive(true);
} catch (java.net.SocketException ex) {
logger.log(Level.FINE, "Socket setup error", ex);
try {
socket_.close();
} catch (java.io.IOException e) {
}
throw Exceptions.asCommFailure(ex);
}
//
// Create new transport
//
org.apache.yoko.orb.OCI.Transport tr = null;
try {
tr = new Transport_impl(socket_, listenMap_);
socket_ = null;
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Transport setup error", ex);
try {
socket_.close();
} catch (java.io.IOException e) {
}
throw ex;
}
//
// Call callbacks
//
org.apache.yoko.orb.OCI.TransportInfo trInfo = tr.get_info();
try {
info_._OB_callConnectCB(trInfo);
} catch (org.omg.CORBA.SystemException ex) {
logger.log(Level.FINE, "Callback setup error", ex);
tr.close();
throw ex;
}
//
// Return new transport
//
return tr;
}
public org.apache.yoko.orb.OCI.ProfileInfo[] get_usable_profiles(
org.omg.IOP.IOR ior, org.omg.CORBA.Policy[] policies) {
//
// Make sure that the set of policies is met
//
for (int i = 0; i < policies.length; i++) {
if (policies[i].policy_type() == org.apache.yoko.orb.OB.PROTOCOL_POLICY_ID.value) {
org.apache.yoko.orb.OB.ProtocolPolicy protocolPolicy = org.apache.yoko.orb.OB.ProtocolPolicyHelper
.narrow(policies[i]);
if (!protocolPolicy.contains(PLUGIN_ID.value))
return new org.apache.yoko.orb.OCI.ProfileInfo[0];
}
}
org.apache.yoko.orb.OCI.ProfileInfoSeqHolder profileInfoSeq = new org.apache.yoko.orb.OCI.ProfileInfoSeqHolder();
profileInfoSeq.value = new org.apache.yoko.orb.OCI.ProfileInfo[0];
Util.extractAllProfileInfos(ior, profileInfoSeq, true, this.info_.getHost(), this.info_.getPort(),
false, codec_);
//check that the transport info matches ours.
//we could return just the profiles that match rather than bailing if one doesn't match.
for (int i = 0; i< profileInfoSeq.value.length; i++ ) {
TaggedComponent[] components = profileInfoSeq.value[i].components;
byte[] otherTransportInfo = new byte[0];
for (int j = 0; j < components.length; j++ ) {
TaggedComponent component = components[j];
if (component.tag == TAG_CSI_SEC_MECH_LIST.value) {
otherTransportInfo = component.component_data;
break;
}
}
if (!Arrays.equals(transportInfo, otherTransportInfo)) {
return new org.apache.yoko.orb.OCI.ProfileInfo[0];
}
}
return profileInfoSeq.value;
}
public boolean equal(org.apache.yoko.orb.OCI.Connector con) {
Connector_impl impl = null;
try {
impl = (Connector_impl) con;
} catch (ClassCastException ex) {
return false;
}
//
// Compare ports
//
if (this.info_.getPort() != impl.info_.getPort())
return false;
//
// Direct host name comparison
//
if (!this.info_.getHost().equals(impl.info_.getHost())) {
//
// Direct host name comparision failed - must look up
// addresses to be really sure if the hosts differ
//
try {
java.net.InetAddress addr1 = java.net.InetAddress
.getByName(this.info_.getHost());
java.net.InetAddress addr2 = java.net.InetAddress
.getByName(impl.info_.getHost());
if (!addr1.equals(addr2))
return false;
} catch (java.net.UnknownHostException ex) {
//
// Return false on hostname lookup failure
//
return false;
}
}
return Arrays.equals(transportInfo, impl.transportInfo);
}
byte[] extractTransportInfo(IOR ior) {
ProfileInfoHolder holder = new ProfileInfoHolder();
// we need to extract the profile information from the IOR to see if this connection has
// any transport-level security defined.
if (org.apache.yoko.orb.OCI.IIOP.Util.extractProfileInfo(ior, holder)) {
ProfileInfo profileInfo = holder.value;
for (int i = 0; i < profileInfo.components.length; i++) {
// we're lookoing for the security mechanism items.
if (profileInfo.components[i].tag == TAG_CSI_SEC_MECH_LIST.value) {
return profileInfo.components[i].component_data;
}
}
}
return new byte[0];
}
public org.apache.yoko.orb.OCI.ConnectorInfo get_info() {
return info_;
}
// ------------------------------------------------------------------
// Yoko internal functions
// Application programs must not use these functions directly
// ------------------------------------------------------------------
private Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ConnectionHelper helper, ExtendedConnectionHelper xhelper, Codec codec) {
if ((null == helper) && (null == xhelper)) throw new IllegalArgumentException("Both connection helpers must not be null");
ior_ = ior;
policies_ = policies;
keepAlive_ = keepAlive;
info_ = new ConnectorInfo_impl(host, port, cb);
listenMap_ = lm;
connectionHelper_ = helper;
extendedConnectionHelper_ = xhelper;
codec_ = codec;
transportInfo = extractTransportInfo(ior);
}
public Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ConnectionHelper helper, Codec codec) {
this(ior, policies, host, port, keepAlive, cb, lm, helper, null, codec);
}
public Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ExtendedConnectionHelper xhelper, Codec codec) {
this(ior, policies, host, port, keepAlive, cb, lm, null, xhelper, codec);
}
public void finalize() throws Throwable {
if (socket_ != null)
close();
super.finalize();
}
}