001: /*
002: * JacORB - a free Java ORB
003: *
004: * Copyright (C) 1997-2004 Gerald Brose.
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Library General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Library General Public License for more details.
015: *
016: * You should have received a copy of the GNU Library General Public
017: * License along with this library; if not, write to the Free
018: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
019: */
020: package org.jacorb.orb.iiop;
021:
022: import java.util.*;
023:
024: import org.apache.avalon.framework.configuration.*;
025: import org.apache.avalon.framework.logger.Logger;
026:
027: import org.jacorb.orb.CDRInputStream;
028: import org.jacorb.orb.CDROutputStream;
029: import org.jacorb.orb.TaggedComponentList;
030: import org.jacorb.orb.etf.ProtocolAddressBase;
031:
032: import org.omg.ETF.*;
033: import org.omg.IOP.*;
034: import org.omg.SSLIOP.*;
035: import org.omg.CORBA.INTERNAL;
036: import org.omg.CSIIOP.*;
037:
038: /**
039: * @author Andre Spiegel
040: * @version $Id: IIOPProfile.java,v 1.26 2006/07/11 13:16:45 alphonse.bendt Exp $
041: */
042: public class IIOPProfile extends org.jacorb.orb.etf.ProfileBase
043: implements Cloneable {
044: private IIOPAddress primaryAddress = null;
045: private Logger logger;
046:
047: public IIOPProfile() {
048: super ();
049: }
050:
051: public IIOPProfile(byte[] data) {
052: this ();
053:
054: initFromProfileData(data);
055: }
056:
057: public IIOPProfile(IIOPAddress address, byte[] objectKey, int minor) {
058: this ();
059:
060: this .version = new org.omg.GIOP.Version((byte) 1, (byte) minor);
061: this .primaryAddress = address;
062: this .objectKey = objectKey;
063: this .components = new TaggedComponentList();
064: }
065:
066: public IIOPProfile(IIOPAddress address, byte[] objectKey) {
067: this (address, objectKey, 2);
068: }
069:
070: /**
071: * Constructs an IIOPProfile from a corbaloc URL. Only to be used
072: * from the corbaloc parser.
073: */
074: public IIOPProfile(String corbaloc) {
075: this ();
076:
077: this .version = null;
078: this .primaryAddress = null;
079: this .objectKey = null;
080: this .components = null;
081: this .corbalocStr = corbaloc;
082: }
083:
084: public void configure(Configuration config)
085: throws ConfigurationException {
086: configuration = (org.jacorb.config.Configuration) config;
087: logger = configuration.getNamedLogger("jacorb.iiop.profile");
088: if (primaryAddress != null) {
089: primaryAddress.configure(config);
090: }
091:
092: if (corbalocStr != null) {
093: try {
094: decode_corbaloc(corbalocStr);
095: } catch (Exception e) {
096: logger.debug("unable to decode_corbaloc", e);
097: }
098: }
099: }
100:
101: /**
102: * An IPv6 corbaloc URL is of the format
103: * corbaloc:iiop:[fe80:5443::3333%3]:2809/my_object
104: * where the zone ID seperator is / or % depending on
105: * what the underlying OS supports.
106: *
107: * This preserves compatilibility with TAO, and falls in
108: * line with RFC 2732 and discussion on OMG news groups.
109: */
110: private void decode_corbaloc(final String address) {
111: String addr = address;
112: String host = "127.0.0.1"; //default to localhost
113: short port = 2809; // default IIOP port
114:
115: int major = 1; // should be 1 by default. see 13.6.10.3
116: int minor = 0; // should be 0 by default. see 13.6.10.3
117:
118: String errorstr = "Illegal IIOP protocol format in object address format: "
119: + addr;
120:
121: int sep = addr.indexOf(':');
122:
123: String protocol_identifier = "";
124: if (sep != 0) {
125: protocol_identifier = addr.substring(0, sep);
126: }
127: if (sep + 1 == addr.length()) {
128: throw new IllegalArgumentException(errorstr);
129: }
130: addr = addr.substring(sep + 1);
131: // decode optional version number
132: sep = addr.indexOf('@');
133: if (sep > -1) {
134: String ver_str = addr.substring(0, sep);
135: addr = addr.substring(sep + 1);
136: sep = ver_str.indexOf('.');
137: if (sep != -1) {
138: try {
139: major = Integer.parseInt(ver_str.substring(0, sep));
140: minor = Integer
141: .parseInt(ver_str.substring(sep + 1));
142: } catch (NumberFormatException nfe) {
143: throw new IllegalArgumentException(errorstr);
144: }
145: }
146: }
147: version = new org.omg.GIOP.Version((byte) major, (byte) minor);
148:
149: int ipv6SeperatorStart = -1;
150: int ipv6SeperatorEnd = -1;
151: ipv6SeperatorStart = addr.indexOf('[');
152: if (ipv6SeperatorStart != -1) {
153: ipv6SeperatorEnd = addr.indexOf(']');
154: if (ipv6SeperatorEnd == -1) {
155: throw new IllegalArgumentException(errorstr);
156: }
157: }
158:
159: sep = addr.indexOf(':');
160: if (sep != -1) {
161: if (ipv6SeperatorStart != -1) //IPv6
162: {
163: host = addr.substring(ipv6SeperatorStart + 1,
164: ipv6SeperatorEnd);
165: if (addr.charAt(ipv6SeperatorEnd + 1) == ':') {
166: port = (short) Integer.parseInt(addr
167: .substring(ipv6SeperatorEnd + 2));
168: } else {
169: throw new IllegalArgumentException(errorstr);
170: }
171: } else //IPv4 or hostname
172: {
173: try {
174: port = (short) Integer.parseInt(addr
175: .substring(sep + 1));
176: host = addr.substring(0, sep);
177: } catch (NumberFormatException ill) {
178: throw new IllegalArgumentException(errorstr);
179: }
180: }
181: }
182: primaryAddress = new IIOPAddress(host, port);
183:
184: try {
185: primaryAddress.configure(configuration);
186: } catch (ConfigurationException ce) {
187: logger.warn("ConfigurationException", ce);
188: }
189: decode_extensions(protocol_identifier.toLowerCase());
190: }
191:
192: private void decode_extensions(String ident) {
193: this .components = new TaggedComponentList();
194: if (ident.equals("ssliop")) {
195: SSL ssl = new SSL();
196: ssl.port = (short) primaryAddress.getPort();
197: String propname = "jacorb.security.ssl.corbaloc_ssliop.supported_options";
198: ssl.target_supports = get_ssl_options(propname);
199: propname = "jacorb.security.ssl.corbaloc_ssliop.required_options";
200: ssl.target_requires = get_ssl_options(propname);
201:
202: //create the tagged component containing the ssl struct
203: final CDROutputStream out = new CDROutputStream();
204: try {
205: out.beginEncapsulatedArray();
206: SSLHelper.write(out, ssl);
207:
208: // TAG_SSL_SEC_TRANS must be disambiguated in case OpenORB-generated
209: // OMG classes are in the classpath.
210: components.addComponent(new TaggedComponent(
211: org.omg.SSLIOP.TAG_SSL_SEC_TRANS.value, out
212: .getBufferCopy()));
213: } finally {
214: out.close();
215: }
216: }
217: }
218:
219: private short get_ssl_options(String propname) {
220: //For the time being, we only use EstablishTrustInTarget,
221: //because we don't handle any of the other options anyway.
222: // So this makes a reasonable default.
223:
224: short value = (short) configuration.getAttributeAsInteger(
225: propname, EstablishTrustInTarget.value);
226: return value;
227: }
228:
229: /**
230: * Writes the bytes that would make up the ETF::AddressProfile bytes (new spec)
231: * to a stream.
232: * <p>
233: * Writes GIOP version, host string, and port.
234: */
235: public void writeAddressProfile(CDROutputStream addressProfileStream) {
236: org.omg.GIOP.VersionHelper.write(addressProfileStream, version);
237: primaryAddress.write(addressProfileStream);
238: }
239:
240: /**
241: * Reads the bytes that make up the ETF::AddressProfile bytes (new spec)
242: * from a stream.
243: * <p>
244: * Writes GIOP version, host string, and port.
245: */
246: public void readAddressProfile(CDRInputStream addressProfileStream) {
247: this .version = org.omg.GIOP.VersionHelper
248: .read(addressProfileStream);
249: this .primaryAddress = IIOPAddress.read(addressProfileStream);
250: if (configuration != null) {
251: try {
252: primaryAddress.configure(configuration);
253: } catch (ConfigurationException ce) {
254: logger.warn("ConfigurationException", ce);
255: }
256: }
257: }
258:
259: /**
260: * To improve the management of a large set of profile instances,
261: * the author may provide a hash function using the data in a Profile
262: * instance. The Profile shall always implement this function and either
263: * return a hash number, or 0 (zero) if no hashing is supported.
264: */
265: public int hash() {
266: return hashCode();
267: }
268:
269: public Object clone() throws CloneNotSupportedException {
270: IIOPProfile result = (IIOPProfile) super .clone(); // bitwise copy
271:
272: result.primaryAddress = new IIOPAddress(primaryAddress
273: .getHostname(), primaryAddress.getPort());
274:
275: if (configuration != null) {
276: try {
277: result.primaryAddress.configure(configuration);
278: } catch (ConfigurationException ce) {
279: logger.warn("ConfigurationException", ce);
280: }
281: }
282:
283: result.version = new org.omg.GIOP.Version(this .version.major,
284: this .version.minor);
285:
286: if (this .objectKey != null) {
287: result.objectKey = new byte[this .objectKey.length];
288: System.arraycopy(this .objectKey, 0, result.objectKey, 0,
289: this .objectKey.length);
290: }
291:
292: if (this .components != null) {
293: result.components = (TaggedComponentList) this .components
294: .clone();
295: }
296:
297: return result;
298: }
299:
300: /**
301: * This function shall determine if the passed profile, prof, is a match
302: * to this profile. The specifics of the match are left to the details
303: * of the underlying transport, however profiles shall be considered a
304: * match, if they would create connections that share the same attributes
305: * relevant to the transport setup. Among others, this could include
306: * address information (eg. host address) and transport layer
307: * characteristics (eg. encryption levels). If a match is found, it
308: * shall return true, or false otherwise.
309: */
310: public boolean is_match(Profile prof) {
311: if (prof == null) {
312: return false;
313: }
314:
315: if (prof instanceof IIOPProfile) {
316: IIOPProfile other = (IIOPProfile) prof;
317: return (this .getSSLPort() == other.getSSLPort()
318: && this .primaryAddress.equals(other.primaryAddress) && this
319: .getAlternateAddresses().equals(
320: other.getAlternateAddresses()));
321: }
322:
323: return false;
324: }
325:
326: public int tag() {
327: return TAG_INTERNET_IOP.value;
328: }
329:
330: public ProtocolAddressBase getAddress() {
331: return primaryAddress;
332: }
333:
334: /**
335: * Replaces the host in this profile's primary address with newHost
336: * (if it is not null), and the port with newPort (if it is not -1).
337: */
338: public void patchPrimaryAddress(ProtocolAddressBase replacement) {
339: if (replacement instanceof IIOPAddress) {
340: primaryAddress.replaceFrom((IIOPAddress) replacement);
341: }
342: }
343:
344: public List getAlternateAddresses() {
345: return components.getComponents(
346: TAG_ALTERNATE_IIOP_ADDRESS.value, IIOPAddress.class);
347: }
348:
349: public SSL getSSL() {
350: // TAG_SSL_SEC_TRANS must be disambiguated in case OpenORB-generated
351: // OMG classes are in the classpath.
352: return (SSL) components
353: .getComponent(org.omg.SSLIOP.TAG_SSL_SEC_TRANS.value,
354: SSLHelper.class);
355: }
356:
357: /**
358: * If there is a component tagged with TAG_CSI_SEC_MECH_LIST,
359: * get the SSL port from this component. Return the SSL port in the
360: * TAG_TLS_SEC_TRANS component encapsulated into the transport_mech
361: * field of the first CompoundSecMech of the CSI_SEC_MECH_LIST.
362: * Return -1 if there is no component tagged with TAG_CSI_SEC_MECH_LIST
363: * or if this component specifies no SSL port.
364: */
365: public int getTLSPortFromCSIComponent() {
366: CompoundSecMechList csmList = (CompoundSecMechList) components
367: .getComponent(TAG_CSI_SEC_MECH_LIST.value,
368: CompoundSecMechListHelper.class);
369: if (csmList != null && csmList.mechanism_list.length > 0) {
370: byte[] tlsSecTransData = csmList.mechanism_list[0].transport_mech.component_data;
371: CDRInputStream in = new CDRInputStream(
372: (org.omg.CORBA.ORB) null, tlsSecTransData);
373: try {
374: in.openEncapsulatedArray();
375: TLS_SEC_TRANS tls = TLS_SEC_TRANSHelper.read(in);
376: if (tls.addresses.length > 0) {
377: int ssl_port = tls.addresses[0].port;
378: if (ssl_port != 0) {
379: if (ssl_port < 0) {
380: ssl_port += 65536;
381: }
382: return ssl_port;
383: }
384: }
385: } catch (Exception ex) {
386: logger.debug("unexpected exception", ex);
387: throw new INTERNAL(ex.toString());
388: }
389: }
390: return -1;
391:
392: }
393:
394: /**
395: * Returns the port on which SSL is available according to this profile,
396: * or -1 if SSL is not supported.
397: */
398: public int getSSLPort() {
399: SSL ssl = getSSL();
400: if (ssl == null) {
401: return getTLSPortFromCSIComponent();
402: }
403:
404: int port = ssl.port;
405: if (port < 0) {
406: port += 65536;
407: }
408: return port;
409: }
410:
411: /**
412: * Returns a copy of this profile that is compatible with GIOP 1.0.
413: */
414: public IIOPProfile to_GIOP_1_0() {
415: IIOPProfile result = new IIOPProfile(this .primaryAddress,
416: this .objectKey);
417: result.version.minor = 0;
418: return result;
419: }
420:
421: public boolean equals(Object other) {
422: if (other instanceof org.omg.ETF.Profile) {
423: return this .is_match((org.omg.ETF.Profile) other);
424: }
425:
426: return false;
427: }
428:
429: public int hashCode() {
430: return primaryAddress.hashCode();
431: }
432:
433: public String toString() {
434: return primaryAddress.toString();
435: }
436: }
|