001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.kerberos.shared.messages.value;
021    
022    
023    import java.net.InetAddress;
024    import java.net.UnknownHostException;
025    import java.nio.BufferOverflowException;
026    import java.nio.ByteBuffer;
027    
028    import org.apache.directory.server.i18n.I18n;
029    import org.apache.directory.server.kerberos.shared.messages.value.types.HostAddrType;
030    import org.apache.directory.shared.asn1.AbstractAsn1Object;
031    import org.apache.directory.shared.asn1.ber.tlv.TLV;
032    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
033    import org.apache.directory.shared.asn1.ber.tlv.Value;
034    import org.apache.directory.shared.asn1.codec.EncoderException;
035    import org.apache.directory.shared.ldap.util.StringTools;
036    import org.slf4j.Logger;
037    import org.slf4j.LoggerFactory;
038    
039    
040    /**
041     * Provides host address information.
042     * 
043     * The ASN.1 grammaor for this structure is :
044     * 
045     * HostAddress     ::= SEQUENCE  {
046     *        addr-type       [0] Int32,
047     *        address         [1] OCTET STRING
048     * }
049     * 
050     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051     * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $
052     */
053    public class HostAddress extends AbstractAsn1Object
054    {
055        /** The logger */
056        private static final Logger LOG = LoggerFactory.getLogger( HostAddress.class );
057    
058        /** Speedup for logs */
059        private static final boolean IS_DEBUG = LOG.isDebugEnabled();
060    
061        /** The host address type. One of :
062         *    Address Type                   Value
063         *
064         *    IPv4                             2
065         *    Directional                      3
066         *    ChaosNet                         5
067         *    XNS                              6
068         *    ISO                              7
069         *    DECNET Phase IV                 12
070         *    AppleTalk DDP                   16
071         *    NetBios                         20
072         *    IPv6                            24
073         */
074        private HostAddrType addrType;
075    
076        /** The address */
077        private byte[] address;
078    
079        // Storage for computed lengths
080        private transient int addrTypeLength;
081        private transient int addressLength;
082        private transient int hostAddressLength;
083        private transient int hostAddressSeqLength;
084    
085    
086        /**
087         * Creates a new instance of HostAddress.
088         *
089         * @param addrType
090         * @param address
091         */
092        public HostAddress( HostAddrType addrType, byte[] address )
093        {
094            this.addrType = addrType;
095            this.address = address;
096        }
097    
098    
099        /**
100         * Creates a new instance of HostAddress.
101         *
102         * @param internetAddress
103         */
104        public HostAddress( InetAddress internetAddress )
105        {
106            addrType = HostAddrType.ADDRTYPE_INET;
107            byte[] newAddress = internetAddress.getAddress();
108            address = new byte[newAddress.length];
109            System.arraycopy( newAddress, 0, address, 0, newAddress.length );
110        }
111    
112    
113        /**
114         * Returns whether one {@link HostAddress} is equal to another.
115         *
116         * @param that The {@link HostAddress} to compare with
117         * @return true if the {@link HostAddress}'s are equal.
118         */
119        public boolean equals( Object that )
120        {
121            if ( this == that )
122            {
123                return true;
124            }
125            
126            if ( !(that instanceof HostAddress ) )
127            {
128                return false;
129            }
130            
131            HostAddress hostAddress = (HostAddress)that;
132            
133            if ( addrType != hostAddress.addrType || ( address != null && hostAddress.address == null )
134                || ( address == null && hostAddress.address != null ) )
135            {
136                return false;
137            }
138    
139            if ( address != null && hostAddress.address != null )
140            {
141                if ( address.length != hostAddress.address.length )
142                {
143                    return false;
144                }
145    
146                for ( int ii = 0; ii < address.length; ii++ )
147                {
148                    if ( address[ii] != hostAddress.address[ii] )
149                    {
150                        return false;
151                    }
152                }
153            }
154    
155            return true;
156        }
157    
158    
159        /**
160         * Get the bytes for this address.
161         *
162         * @return The bytes of this address.
163         */
164        public byte[] getAddress()
165        {
166            return address;
167        }
168    
169    
170        /**
171         * Set the address 
172         *
173         * @param addresse The address
174         */
175        public void setAddress( byte[] addresse )
176        {
177            this.address = addresse;
178        }
179    
180    
181        /**
182         * Compute the host address length
183         * 
184         * HostAddress :
185         * 
186         * 0x30 L1 hostAddress sequence
187         *  |
188         *  +--> 0xA0 L2 addrType tag
189         *  |     |
190         *  |     +--> 0x02 L2-1 addrType (int)
191         *  |
192         *  +--> 0xA1 L3 address tag
193         *        |
194         *        +--> 0x04 L3-1 address (OCTET STRING)
195         *        
196         *  where L1 = L2 + length(0xA0) + length(L2) +
197         *             L3 + length(0xA1) + length(L3) 
198         *  and
199         *  L2 = L2-1 + length(0x02) + length( L2-1) 
200         *  L3 = L3-1 + length(0x04) + length( L3-1) 
201         */
202        public int computeLength()
203        {
204            // Compute the keyType. The Length will always be contained in 1 byte
205            addrTypeLength = 1 + 1 + Value.getNbBytes( addrType.getOrdinal() );
206            hostAddressLength = 1 + TLV.getNbBytes( addrTypeLength ) + addrTypeLength;
207    
208            // Compute the keyValue
209            if ( address == null )
210            {
211                addressLength = 1 + 1;
212            }
213            else
214            {
215                addressLength = 1 + TLV.getNbBytes( address.length ) + address.length;
216            }
217    
218            hostAddressLength += 1 + TLV.getNbBytes( addressLength ) + addressLength;
219    
220            // Compute the whole sequence length
221            hostAddressSeqLength = 1 + Value.getNbBytes( hostAddressLength ) + hostAddressLength;
222    
223            return hostAddressSeqLength;
224        }
225    
226    
227        /**
228         * Encode the HostAddress message to a PDU. 
229         * 
230         * HostAddress :
231         * 
232         * 0x30 LL
233         *   0xA0 LL 
234         *     0x02 0x01 addr-type
235         *   0xA1 LL 
236         *     0x04 LL address
237         * 
238         * @param buffer The buffer where to put the PDU. It should have been allocated
239         * before, with the right size.
240         * @return The constructed PDU.
241         */
242        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
243        {
244            if ( buffer == null )
245            {
246                throw new EncoderException( I18n.err( I18n.ERR_148 ) );
247            }
248    
249            try
250            {
251                // The HostAddress SEQ Tag
252                buffer.put( UniversalTag.SEQUENCE_TAG );
253                buffer.put( TLV.getBytes( hostAddressLength ) );
254    
255                // The addr-type, first the tag, then the value
256                buffer.put( ( byte ) 0xA0 );
257                buffer.put( TLV.getBytes( addrTypeLength ) );
258                Value.encode( buffer, addrType.getOrdinal() );
259    
260                // The address, first the tag, then the value
261                buffer.put( ( byte ) 0xA1 );
262                buffer.put( TLV.getBytes( addressLength ) );
263                Value.encode( buffer, address );
264            }
265            catch ( BufferOverflowException boe )
266            {
267                LOG.error( I18n.err( I18n.ERR_143, 1 + TLV.getNbBytes( hostAddressLength )
268                    + hostAddressLength, buffer.capacity() ) );
269                throw new EncoderException( I18n.err( I18n.ERR_138 ) );
270            }
271    
272            if ( IS_DEBUG )
273            {
274                LOG.debug( "Checksum encoding : {}", StringTools.dumpBytes( buffer.array() ) );
275                LOG.debug( "Checksum initial value : {}", toString() );
276            }
277    
278            return buffer;
279        }
280    
281    
282        /**
283         * Returns the {@link HostAddrType} of this {@link HostAddress}.
284         *
285         * @return The {@link HostAddrType}.
286         */
287        public HostAddrType getAddrType()
288        {
289            return addrType;
290        }
291    
292    
293        /**
294         * Set the addr-type field
295         *
296         * @param addrType The address type
297         */
298        public void setAddrType( HostAddrType addrType )
299        {
300            this.addrType = addrType;
301        }
302    
303    
304        /**
305         * Set the addr-type field
306         *
307         * @param addrType The address type
308         */
309        public void setAddrType( int addrType )
310        {
311            this.addrType = HostAddrType.getTypeByOrdinal( addrType );
312        }
313    
314    
315        /**
316         * @see Object#toString()
317         */
318        public String toString()
319        {
320            String result = "";
321    
322            try
323            {
324                result = InetAddress.getByAddress( address ).getHostAddress();
325            }
326            catch ( UnknownHostException uhe )
327            {
328                // Allow default to return.
329            }
330    
331            return result;
332        }
333    }