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.kerberos.shared.messages.value.types.HostAddrType;
029    import org.apache.directory.shared.asn1.AbstractAsn1Object;
030    import org.apache.directory.shared.asn1.ber.tlv.TLV;
031    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
032    import org.apache.directory.shared.asn1.ber.tlv.Value;
033    import org.apache.directory.shared.asn1.codec.EncoderException;
034    import org.apache.directory.shared.ldap.util.StringTools;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    
039    /**
040     * Provides host address information.
041     * 
042     * The ASN.1 grammaor for this structure is :
043     * 
044     * HostAddress     ::= SEQUENCE  {
045     *        addr-type       [0] Int32,
046     *        address         [1] OCTET STRING
047     * }
048     * 
049     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
050     * @version $Rev: 642496 $, $Date: 2008-03-29 05:09:22 +0200 (Sat, 29 Mar 2008) $
051     */
052    public class HostAddress extends AbstractAsn1Object
053    {
054        /** The logger */
055        private static final Logger LOG = LoggerFactory.getLogger( HostAddress.class );
056    
057        /** Speedup for logs */
058        private static final boolean IS_DEBUG = LOG.isDebugEnabled();
059    
060        /** The host address type. One of :
061         *    Address Type                   Value
062         *
063         *    IPv4                             2
064         *    Directional                      3
065         *    ChaosNet                         5
066         *    XNS                              6
067         *    ISO                              7
068         *    DECNET Phase IV                 12
069         *    AppleTalk DDP                   16
070         *    NetBios                         20
071         *    IPv6                            24
072         */
073        private HostAddrType addrType;
074    
075        /** The address */
076        private byte[] address;
077    
078        // Storage for computed lengths
079        private transient int addrTypeLength;
080        private transient int addressLength;
081        private transient int hostAddressLength;
082        private transient int hostAddressSeqLength;
083    
084    
085        /**
086         * Creates a new instance of HostAddress.
087         *
088         * @param addrType
089         * @param address
090         */
091        public HostAddress( HostAddrType addrType, byte[] address )
092        {
093            this.addrType = addrType;
094            this.address = address;
095        }
096    
097    
098        /**
099         * Creates a new instance of HostAddress.
100         *
101         * @param internetAddress
102         */
103        public HostAddress( InetAddress internetAddress )
104        {
105            addrType = HostAddrType.ADDRTYPE_INET;
106            byte[] newAddress = internetAddress.getAddress();
107            address = new byte[newAddress.length];
108            System.arraycopy( newAddress, 0, address, 0, newAddress.length );
109        }
110    
111    
112        /**
113         * Returns whether one {@link HostAddress} is equal to another.
114         *
115         * @param that The {@link HostAddress} to compare with
116         * @return true if the {@link HostAddress}'s are equal.
117         */
118        public boolean equals( Object that )
119        {
120            if ( this == that )
121            {
122                return true;
123            }
124            
125            if ( !(that instanceof HostAddress ) )
126            {
127                return false;
128            }
129            
130            HostAddress hostAddress = (HostAddress)that;
131            
132            if ( addrType != hostAddress.addrType || ( address != null && hostAddress.address == null )
133                || ( address == null && hostAddress.address != null ) )
134            {
135                return false;
136            }
137    
138            if ( address != null && hostAddress.address != null )
139            {
140                if ( address.length != hostAddress.address.length )
141                {
142                    return false;
143                }
144    
145                for ( int ii = 0; ii < address.length; ii++ )
146                {
147                    if ( address[ii] != hostAddress.address[ii] )
148                    {
149                        return false;
150                    }
151                }
152            }
153    
154            return true;
155        }
156    
157    
158        /**
159         * Get the bytes for this address.
160         *
161         * @return The bytes of this address.
162         */
163        public byte[] getAddress()
164        {
165            return address;
166        }
167    
168    
169        /**
170         * Set the address 
171         *
172         * @param addresse The address
173         */
174        public void setAddress( byte[] addresse )
175        {
176            this.address = addresse;
177        }
178    
179    
180        /**
181         * Compute the host address length
182         * 
183         * HostAddress :
184         * 
185         * 0x30 L1 hostAddress sequence
186         *  |
187         *  +--> 0xA0 L2 addrType tag
188         *  |     |
189         *  |     +--> 0x02 L2-1 addrType (int)
190         *  |
191         *  +--> 0xA1 L3 address tag
192         *        |
193         *        +--> 0x04 L3-1 address (OCTET STRING)
194         *        
195         *  where L1 = L2 + length(0xA0) + length(L2) +
196         *             L3 + length(0xA1) + length(L3) 
197         *  and
198         *  L2 = L2-1 + length(0x02) + length( L2-1) 
199         *  L3 = L3-1 + length(0x04) + length( L3-1) 
200         */
201        public int computeLength()
202        {
203            // Compute the keyType. The Length will always be contained in 1 byte
204            addrTypeLength = 1 + 1 + Value.getNbBytes( addrType.getOrdinal() );
205            hostAddressLength = 1 + TLV.getNbBytes( addrTypeLength ) + addrTypeLength;
206    
207            // Compute the keyValue
208            if ( address == null )
209            {
210                addressLength = 1 + 1;
211            }
212            else
213            {
214                addressLength = 1 + TLV.getNbBytes( address.length ) + address.length;
215            }
216    
217            hostAddressLength += 1 + TLV.getNbBytes( addressLength ) + addressLength;
218    
219            // Compute the whole sequence length
220            hostAddressSeqLength = 1 + Value.getNbBytes( hostAddressLength ) + hostAddressLength;
221    
222            return hostAddressSeqLength;
223        }
224    
225    
226        /**
227         * Encode the HostAddress message to a PDU. 
228         * 
229         * HostAddress :
230         * 
231         * 0x30 LL
232         *   0xA0 LL 
233         *     0x02 0x01 addr-type
234         *   0xA1 LL 
235         *     0x04 LL address
236         * 
237         * @param buffer The buffer where to put the PDU. It should have been allocated
238         * before, with the right size.
239         * @return The constructed PDU.
240         */
241        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
242        {
243            if ( buffer == null )
244            {
245                throw new EncoderException( "Cannot put a PDU in a null buffer !" );
246            }
247    
248            try
249            {
250                // The HostAddress SEQ Tag
251                buffer.put( UniversalTag.SEQUENCE_TAG );
252                buffer.put( TLV.getBytes( hostAddressLength ) );
253    
254                // The addr-type, first the tag, then the value
255                buffer.put( ( byte ) 0xA0 );
256                buffer.put( TLV.getBytes( addrTypeLength ) );
257                Value.encode( buffer, addrType.getOrdinal() );
258    
259                // The address, first the tag, then the value
260                buffer.put( ( byte ) 0xA1 );
261                buffer.put( TLV.getBytes( addressLength ) );
262                Value.encode( buffer, address );
263            }
264            catch ( BufferOverflowException boe )
265            {
266                LOG.error(
267                    "Cannot encode the HostAddress object, the PDU size is {} when only {} bytes has been allocated", 1
268                        + TLV.getNbBytes( hostAddressLength ) + hostAddressLength, buffer.capacity() );
269                throw new EncoderException( "The PDU buffer size is too small !" );
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    }