001    /*
002     *   Copyright 2005 The Apache Software Foundation
003     *
004     *   Licensed under the Apache License, Version 2.0 (the "License");
005     *   you may not use this file except in compliance with the License.
006     *   You may obtain a copy of the License at
007     *
008     *       http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *   Unless required by applicable law or agreed to in writing, software
011     *   distributed under the License is distributed on an "AS IS" BASIS,
012     *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *   See the License for the specific language governing permissions and
014     *   limitations under the License.
015     *
016     */
017    
018    package org.apache.directory.server.dhcp.options;
019    
020    
021    import java.nio.ByteBuffer;
022    import java.util.Collections;
023    import java.util.HashMap;
024    import java.util.Map;
025    
026    import org.apache.directory.server.dhcp.options.dhcp.BootfileName;
027    import org.apache.directory.server.dhcp.options.dhcp.ClientIdentifier;
028    import org.apache.directory.server.dhcp.options.dhcp.DhcpMessageType;
029    import org.apache.directory.server.dhcp.options.dhcp.IpAddressLeaseTime;
030    import org.apache.directory.server.dhcp.options.dhcp.MaximumDhcpMessageSize;
031    import org.apache.directory.server.dhcp.options.dhcp.OptionOverload;
032    import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList;
033    import org.apache.directory.server.dhcp.options.dhcp.RebindingTimeValue;
034    import org.apache.directory.server.dhcp.options.dhcp.RenewalTimeValue;
035    import org.apache.directory.server.dhcp.options.dhcp.RequestedIpAddress;
036    import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier;
037    import org.apache.directory.server.dhcp.options.dhcp.TftpServerName;
038    import org.apache.directory.server.dhcp.options.dhcp.UnrecognizedOption;
039    import org.apache.directory.server.dhcp.options.dhcp.VendorClassIdentifier;
040    import org.apache.directory.server.dhcp.options.misc.DefaultFingerServers;
041    import org.apache.directory.server.dhcp.options.misc.DefaultIrcServers;
042    import org.apache.directory.server.dhcp.options.misc.DefaultWwwServers;
043    import org.apache.directory.server.dhcp.options.misc.MobileIpHomeAgents;
044    import org.apache.directory.server.dhcp.options.misc.NbddServers;
045    import org.apache.directory.server.dhcp.options.misc.NetbiosNameServers;
046    import org.apache.directory.server.dhcp.options.misc.NetbiosNodeType;
047    import org.apache.directory.server.dhcp.options.misc.NetbiosScope;
048    import org.apache.directory.server.dhcp.options.misc.NisDomain;
049    import org.apache.directory.server.dhcp.options.misc.NisPlusDomain;
050    import org.apache.directory.server.dhcp.options.misc.NisPlusServers;
051    import org.apache.directory.server.dhcp.options.misc.NisServers;
052    import org.apache.directory.server.dhcp.options.misc.NntpServers;
053    import org.apache.directory.server.dhcp.options.misc.NtpServers;
054    import org.apache.directory.server.dhcp.options.misc.Pop3Servers;
055    import org.apache.directory.server.dhcp.options.misc.SmtpServers;
056    import org.apache.directory.server.dhcp.options.misc.StdaServers;
057    import org.apache.directory.server.dhcp.options.misc.StreetTalkServers;
058    import org.apache.directory.server.dhcp.options.misc.VendorSpecificInformation;
059    import org.apache.directory.server.dhcp.options.misc.XWindowDisplayManagers;
060    import org.apache.directory.server.dhcp.options.misc.XWindowFontServers;
061    import org.apache.directory.server.dhcp.options.perhost.DefaultIpTimeToLive;
062    import org.apache.directory.server.dhcp.options.perhost.IpForwarding;
063    import org.apache.directory.server.dhcp.options.perhost.MaximumDatagramSize;
064    import org.apache.directory.server.dhcp.options.perhost.NonLocalSourceRouting;
065    import org.apache.directory.server.dhcp.options.perhost.PathMtuAgingTimeout;
066    import org.apache.directory.server.dhcp.options.perhost.PathMtuPlateauTable;
067    import org.apache.directory.server.dhcp.options.perhost.PolicyFilter;
068    import org.apache.directory.server.dhcp.options.perinterface.AllSubnetsAreLocal;
069    import org.apache.directory.server.dhcp.options.perinterface.BroadcastAddress;
070    import org.apache.directory.server.dhcp.options.perinterface.InterfaceMtu;
071    import org.apache.directory.server.dhcp.options.perinterface.MaskSupplier;
072    import org.apache.directory.server.dhcp.options.perinterface.PerformMaskDiscovery;
073    import org.apache.directory.server.dhcp.options.perinterface.PerformRouterDiscovery;
074    import org.apache.directory.server.dhcp.options.perinterface.RouterSolicitationAddress;
075    import org.apache.directory.server.dhcp.options.perinterface.StaticRoute;
076    import org.apache.directory.server.dhcp.options.tcp.TcpDefaultTimeToLive;
077    import org.apache.directory.server.dhcp.options.tcp.TcpKeepaliveGarbage;
078    import org.apache.directory.server.dhcp.options.tcp.TcpKeepaliveInterval;
079    import org.apache.directory.server.dhcp.options.vendor.BootFileSize;
080    import org.apache.directory.server.dhcp.options.vendor.CookieServers;
081    import org.apache.directory.server.dhcp.options.vendor.DomainName;
082    import org.apache.directory.server.dhcp.options.vendor.DomainNameServers;
083    import org.apache.directory.server.dhcp.options.vendor.ExtensionsPath;
084    import org.apache.directory.server.dhcp.options.vendor.HostName;
085    import org.apache.directory.server.dhcp.options.vendor.ImpressServers;
086    import org.apache.directory.server.dhcp.options.vendor.LogServers;
087    import org.apache.directory.server.dhcp.options.vendor.LprServers;
088    import org.apache.directory.server.dhcp.options.vendor.MeritDumpFile;
089    import org.apache.directory.server.dhcp.options.vendor.NameServers;
090    import org.apache.directory.server.dhcp.options.vendor.ResourceLocationServers;
091    import org.apache.directory.server.dhcp.options.vendor.RootPath;
092    import org.apache.directory.server.dhcp.options.vendor.Routers;
093    import org.apache.directory.server.dhcp.options.vendor.SubnetMask;
094    import org.apache.directory.server.dhcp.options.vendor.SwapServer;
095    import org.apache.directory.server.dhcp.options.vendor.TimeOffset;
096    import org.apache.directory.server.dhcp.options.vendor.TimeServers;
097    import org.apache.directory.server.i18n.I18n;
098    
099    
100    /**
101     * The Dynamic Host Configuration Protocol (DHCP) provides a framework
102     * for passing configuration information to hosts on a TCP/IP network.  
103     * Configuration parameters and other control information are carried in
104     * tagged data items that are stored in the 'options' field of the DHCP
105     * message.  The data items themselves are also called "options."
106     * 
107     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
108     * @version $Rev: 902331 $, $Date: 2010-01-23 02:41:35 +0100 (Sat, 23 Jan 2010) $
109     */
110    public abstract class DhcpOption
111    {
112        /**
113         * An array of concrete implementations of DhcpOption.
114         */
115        private static Class OPTION_CLASSES[] =
116            { BootfileName.class, ClientIdentifier.class, DhcpMessageType.class, IpAddressLeaseTime.class,
117                MaximumDhcpMessageSize.class, org.apache.directory.server.dhcp.options.dhcp.Message.class,
118                OptionOverload.class, ParameterRequestList.class, RebindingTimeValue.class, RenewalTimeValue.class,
119                RequestedIpAddress.class, ServerIdentifier.class, TftpServerName.class, VendorClassIdentifier.class,
120                ClientIdentifier.class, DhcpMessageType.class, IpAddressLeaseTime.class, MaximumDhcpMessageSize.class,
121                OptionOverload.class, ParameterRequestList.class, RebindingTimeValue.class, RenewalTimeValue.class,
122                RequestedIpAddress.class, ServerIdentifier.class, TftpServerName.class, UnrecognizedOption.class,
123                VendorClassIdentifier.class, DefaultFingerServers.class, DefaultIrcServers.class, DefaultWwwServers.class,
124                MobileIpHomeAgents.class, NbddServers.class, NetbiosNameServers.class, NetbiosNodeType.class,
125                NetbiosScope.class, NisDomain.class, NisPlusDomain.class, NisPlusServers.class, NisServers.class,
126                NntpServers.class, NtpServers.class, Pop3Servers.class, SmtpServers.class, StdaServers.class,
127                StreetTalkServers.class, VendorSpecificInformation.class, XWindowDisplayManagers.class,
128                XWindowFontServers.class, DefaultIpTimeToLive.class, IpForwarding.class, MaximumDatagramSize.class,
129                NonLocalSourceRouting.class, PathMtuAgingTimeout.class, PathMtuPlateauTable.class, PolicyFilter.class,
130                AllSubnetsAreLocal.class, BroadcastAddress.class, InterfaceMtu.class, MaskSupplier.class,
131                PerformMaskDiscovery.class, PerformRouterDiscovery.class, RouterSolicitationAddress.class,
132                StaticRoute.class, TcpDefaultTimeToLive.class, TcpKeepaliveGarbage.class, TcpKeepaliveInterval.class,
133                BootFileSize.class, CookieServers.class, DomainName.class, DomainNameServers.class, ExtensionsPath.class,
134                HostName.class, ImpressServers.class, LogServers.class, LprServers.class, MeritDumpFile.class,
135                NameServers.class, ResourceLocationServers.class, RootPath.class, Routers.class, SubnetMask.class,
136                SwapServer.class, TimeOffset.class, TimeServers.class, };
137    
138        /**
139         * A map of concrete implementations of DhcpOption indexed by tag code.
140         */
141        private static Map OPTION_CLASS_BY_CODE;
142    
143        /**
144         * A map of tag codes indexed by OptionClass subclass.
145         */
146        private static Map CODE_BY_CLASS;
147    
148        static
149        {
150            try
151            {
152                // initialize the tag-to-class and class-to-tag map
153                Map classByCode = new HashMap();
154                Map codeByClass = new HashMap();
155                for ( int i = 0; i < OPTION_CLASSES.length; i++ )
156                {
157                    Class c = OPTION_CLASSES[i];
158    
159                    if ( !DhcpOption.class.isAssignableFrom( c ) )
160                        throw new RuntimeException( I18n.err( I18n.ERR_639, c ) );
161    
162                    DhcpOption o = ( DhcpOption ) c.newInstance();
163    
164                    Integer tagInt = new Integer( o.getTag() );
165                    classByCode.put( tagInt, c );
166                    codeByClass.put( c, tagInt );
167                }
168    
169                OPTION_CLASS_BY_CODE = Collections.unmodifiableMap( classByCode );
170                CODE_BY_CLASS = Collections.unmodifiableMap( codeByClass );
171            }
172            catch ( Exception e )
173            {
174                throw new RuntimeException( I18n.err( I18n.ERR_640 ), e );
175            }
176        }
177    
178    
179        public static Class getClassByTag( int tag )
180        {
181            return ( Class ) OPTION_CLASS_BY_CODE.get( new Integer( tag ) );
182        }
183    
184    
185        public static int getTagByClass( Class c )
186        {
187            return ( ( Integer ) CODE_BY_CLASS.get( c ) ).intValue();
188        }
189    
190        /**
191         * The default data array used for simple (unparsed) options.
192         */
193        private byte[] data;
194    
195    
196        /**
197         * Get the option's code tag.
198         * 
199         * @return byte
200         */
201        public abstract byte getTag();
202    
203    
204        /**
205         * Set the data (wire format) from a byte array. The default implementation
206         * just records the data as a byte array. Subclasses may parse the data into
207         * something more meaningful.
208         * 
209         * @param data
210         */
211        public void setData( byte data[] )
212        {
213            this.data = data;
214        }
215    
216    
217        /**
218         * Get the data (wire format) into a byte array. Subclasses must provide an
219         * implementation which serializes the parsed data back into a byte array if
220         * they override {@link #setData(byte[])}.
221         * 
222         * @return byte[]
223         */
224        public byte[] getData()
225        {
226            return data;
227        }
228    
229    
230        public final void writeTo( ByteBuffer out )
231        {
232            out.put( getTag() );
233    
234            // FIXME: handle continuation, i.e. options longer than 128 bytes?
235            byte data[] = getData();
236            if ( data.length > 255 )
237                throw new IllegalArgumentException( I18n.err( I18n.ERR_641 ) );
238    
239            out.put( ( byte ) data.length );
240            out.put( data );
241        }
242    }