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
021package org.apache.directory.server.dhcp.options;
022
023
024import java.nio.ByteBuffer;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.Map;
028
029import org.apache.directory.server.dhcp.options.dhcp.BootfileName;
030import org.apache.directory.server.dhcp.options.dhcp.ClientIdentifier;
031import org.apache.directory.server.dhcp.options.dhcp.DhcpMessageType;
032import org.apache.directory.server.dhcp.options.dhcp.IpAddressLeaseTime;
033import org.apache.directory.server.dhcp.options.dhcp.MaximumDhcpMessageSize;
034import org.apache.directory.server.dhcp.options.dhcp.OptionOverload;
035import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList;
036import org.apache.directory.server.dhcp.options.dhcp.RebindingTimeValue;
037import org.apache.directory.server.dhcp.options.dhcp.RenewalTimeValue;
038import org.apache.directory.server.dhcp.options.dhcp.RequestedIpAddress;
039import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier;
040import org.apache.directory.server.dhcp.options.dhcp.TftpServerName;
041import org.apache.directory.server.dhcp.options.dhcp.UnrecognizedOption;
042import org.apache.directory.server.dhcp.options.dhcp.VendorClassIdentifier;
043import org.apache.directory.server.dhcp.options.misc.DefaultFingerServers;
044import org.apache.directory.server.dhcp.options.misc.DefaultIrcServers;
045import org.apache.directory.server.dhcp.options.misc.DefaultWwwServers;
046import org.apache.directory.server.dhcp.options.misc.MobileIpHomeAgents;
047import org.apache.directory.server.dhcp.options.misc.NbddServers;
048import org.apache.directory.server.dhcp.options.misc.NetbiosNameServers;
049import org.apache.directory.server.dhcp.options.misc.NetbiosNodeType;
050import org.apache.directory.server.dhcp.options.misc.NetbiosScope;
051import org.apache.directory.server.dhcp.options.misc.NisDomain;
052import org.apache.directory.server.dhcp.options.misc.NisPlusDomain;
053import org.apache.directory.server.dhcp.options.misc.NisPlusServers;
054import org.apache.directory.server.dhcp.options.misc.NisServers;
055import org.apache.directory.server.dhcp.options.misc.NntpServers;
056import org.apache.directory.server.dhcp.options.misc.NtpServers;
057import org.apache.directory.server.dhcp.options.misc.Pop3Servers;
058import org.apache.directory.server.dhcp.options.misc.SmtpServers;
059import org.apache.directory.server.dhcp.options.misc.StdaServers;
060import org.apache.directory.server.dhcp.options.misc.StreetTalkServers;
061import org.apache.directory.server.dhcp.options.misc.VendorSpecificInformation;
062import org.apache.directory.server.dhcp.options.misc.XWindowDisplayManagers;
063import org.apache.directory.server.dhcp.options.misc.XWindowFontServers;
064import org.apache.directory.server.dhcp.options.perhost.DefaultIpTimeToLive;
065import org.apache.directory.server.dhcp.options.perhost.IpForwarding;
066import org.apache.directory.server.dhcp.options.perhost.MaximumDatagramSize;
067import org.apache.directory.server.dhcp.options.perhost.NonLocalSourceRouting;
068import org.apache.directory.server.dhcp.options.perhost.PathMtuAgingTimeout;
069import org.apache.directory.server.dhcp.options.perhost.PathMtuPlateauTable;
070import org.apache.directory.server.dhcp.options.perhost.PolicyFilter;
071import org.apache.directory.server.dhcp.options.perinterface.AllSubnetsAreLocal;
072import org.apache.directory.server.dhcp.options.perinterface.BroadcastAddress;
073import org.apache.directory.server.dhcp.options.perinterface.InterfaceMtu;
074import org.apache.directory.server.dhcp.options.perinterface.MaskSupplier;
075import org.apache.directory.server.dhcp.options.perinterface.PerformMaskDiscovery;
076import org.apache.directory.server.dhcp.options.perinterface.PerformRouterDiscovery;
077import org.apache.directory.server.dhcp.options.perinterface.RouterSolicitationAddress;
078import org.apache.directory.server.dhcp.options.perinterface.StaticRoute;
079import org.apache.directory.server.dhcp.options.tcp.TcpDefaultTimeToLive;
080import org.apache.directory.server.dhcp.options.tcp.TcpKeepaliveGarbage;
081import org.apache.directory.server.dhcp.options.tcp.TcpKeepaliveInterval;
082import org.apache.directory.server.dhcp.options.vendor.BootFileSize;
083import org.apache.directory.server.dhcp.options.vendor.CookieServers;
084import org.apache.directory.server.dhcp.options.vendor.DomainName;
085import org.apache.directory.server.dhcp.options.vendor.DomainNameServers;
086import org.apache.directory.server.dhcp.options.vendor.ExtensionsPath;
087import org.apache.directory.server.dhcp.options.vendor.HostName;
088import org.apache.directory.server.dhcp.options.vendor.ImpressServers;
089import org.apache.directory.server.dhcp.options.vendor.LogServers;
090import org.apache.directory.server.dhcp.options.vendor.LprServers;
091import org.apache.directory.server.dhcp.options.vendor.MeritDumpFile;
092import org.apache.directory.server.dhcp.options.vendor.NameServers;
093import org.apache.directory.server.dhcp.options.vendor.ResourceLocationServers;
094import org.apache.directory.server.dhcp.options.vendor.RootPath;
095import org.apache.directory.server.dhcp.options.vendor.Routers;
096import org.apache.directory.server.dhcp.options.vendor.SubnetMask;
097import org.apache.directory.server.dhcp.options.vendor.SwapServer;
098import org.apache.directory.server.dhcp.options.vendor.TimeOffset;
099import org.apache.directory.server.dhcp.options.vendor.TimeServers;
100import org.apache.directory.server.i18n.I18n;
101
102
103/**
104 * The Dynamic Host Configuration Protocol (DHCP) provides a framework
105 * for passing configuration information to hosts on a TCP/IP network.  
106 * Configuration parameters and other control information are carried in
107 * tagged data items that are stored in the 'options' field of the DHCP
108 * message.  The data items themselves are also called "options."
109 * 
110 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
111 */
112public abstract class DhcpOption
113{
114    /**
115     * An array of concrete implementations of DhcpOption.
116     */
117    private static final Class<?>[] OPTION_CLASSES =
118        { 
119            BootfileName.class, 
120            ClientIdentifier.class, 
121            DhcpMessageType.class, 
122            IpAddressLeaseTime.class,
123            MaximumDhcpMessageSize.class, 
124            org.apache.directory.server.dhcp.options.dhcp.Message.class,
125            OptionOverload.class, 
126            ParameterRequestList.class, 
127            RebindingTimeValue.class, 
128            RenewalTimeValue.class,
129            RequestedIpAddress.class, 
130            ServerIdentifier.class, 
131            TftpServerName.class, 
132            VendorClassIdentifier.class,
133            ClientIdentifier.class, 
134            DhcpMessageType.class, 
135            IpAddressLeaseTime.class, 
136            MaximumDhcpMessageSize.class,
137            OptionOverload.class, 
138            ParameterRequestList.class, 
139            RebindingTimeValue.class, 
140            RenewalTimeValue.class,
141            RequestedIpAddress.class, 
142            ServerIdentifier.class, 
143            TftpServerName.class, 
144            UnrecognizedOption.class,
145            VendorClassIdentifier.class, 
146            DefaultFingerServers.class, 
147            DefaultIrcServers.class, 
148            DefaultWwwServers.class,
149            MobileIpHomeAgents.class, 
150            NbddServers.class, 
151            NetbiosNameServers.class, 
152            NetbiosNodeType.class,
153            NetbiosScope.class, 
154            NisDomain.class, 
155            NisPlusDomain.class, 
156            NisPlusServers.class, 
157            NisServers.class,
158            NntpServers.class, 
159            NtpServers.class, 
160            Pop3Servers.class, 
161            SmtpServers.class, 
162            StdaServers.class,
163            StreetTalkServers.class, 
164            VendorSpecificInformation.class, 
165            XWindowDisplayManagers.class,
166            XWindowFontServers.class, 
167            DefaultIpTimeToLive.class, 
168            IpForwarding.class, 
169            MaximumDatagramSize.class,
170            NonLocalSourceRouting.class, 
171            PathMtuAgingTimeout.class, 
172            PathMtuPlateauTable.class, 
173            PolicyFilter.class,
174            AllSubnetsAreLocal.class, 
175            BroadcastAddress.class, 
176            InterfaceMtu.class, 
177            MaskSupplier.class,
178            PerformMaskDiscovery.class, 
179            PerformRouterDiscovery.class, 
180            RouterSolicitationAddress.class,
181            StaticRoute.class, 
182            TcpDefaultTimeToLive.class, 
183            TcpKeepaliveGarbage.class, 
184            TcpKeepaliveInterval.class,
185            BootFileSize.class, 
186            CookieServers.class, 
187            DomainName.class, 
188            DomainNameServers.class, 
189            ExtensionsPath.class,
190            HostName.class, 
191            ImpressServers.class, 
192            LogServers.class, 
193            LprServers.class, 
194            MeritDumpFile.class,
195            NameServers.class, 
196            ResourceLocationServers.class, 
197            RootPath.class, Routers.class, 
198            SubnetMask.class,
199            SwapServer.class, 
200            TimeOffset.class, 
201            TimeServers.class, };
202
203    /**
204     * A map of concrete implementations of DhcpOption indexed by tag code.
205     */
206    private static final Map<Integer, Class<?>> OPTION_CLASS_BY_CODE;
207
208    /**
209     * A map of tag codes indexed by OptionClass subclass.
210     */
211    private static final Map<Class<?>, Integer> CODE_BY_CLASS;
212
213    static
214    {
215        try
216        {
217            // initialize the tag-to-class and class-to-tag map
218            Map<Integer, Class<?>> classByCode = new HashMap<>();
219            Map<Class<?>, Integer> codeByClass = new HashMap<>();
220            
221            for ( int i = 0; i < OPTION_CLASSES.length; i++ )
222            {
223                Class<?> dhcpOptionClass = OPTION_CLASSES[i];
224
225                if ( !DhcpOption.class.isAssignableFrom( dhcpOptionClass ) )
226                {
227                    throw new RuntimeException( I18n.err( I18n.ERR_639, dhcpOptionClass ) );
228                }
229
230                DhcpOption dhcpOption = ( DhcpOption ) dhcpOptionClass.newInstance();
231
232                int tagInt = dhcpOption.getTag();
233                classByCode.put( tagInt, dhcpOptionClass );
234                codeByClass.put( dhcpOptionClass, tagInt );
235            }
236
237            OPTION_CLASS_BY_CODE = Collections.unmodifiableMap( classByCode );
238            CODE_BY_CLASS = Collections.unmodifiableMap( codeByClass );
239        }
240        catch ( Exception e )
241        {
242            throw new RuntimeException( I18n.err( I18n.ERR_640 ), e );
243        }
244    }
245
246
247    public static Class<?> getClassByTag( int tag )
248    {
249        return OPTION_CLASS_BY_CODE.get( tag );
250    }
251
252
253    public static int getTagByClass( Class<?> c )
254    {
255        return CODE_BY_CLASS.get( c );
256    }
257
258    /**
259     * The default data array used for simple (unparsed) options.
260     */
261    private byte[] data;
262
263
264    /**
265     * Get the option's code tag.
266     * 
267     * @return byte
268     */
269    public abstract byte getTag();
270
271
272    /**
273     * Set the data (wire format) from a byte array. The default implementation
274     * just records the data as a byte array. Subclasses may parse the data into
275     * something more meaningful.
276     * 
277     * @param data
278     */
279    public void setData( byte[] data )
280    {
281        this.data = data;
282    }
283
284
285    /**
286     * Get the data (wire format) into a byte array. Subclasses must provide an
287     * implementation which serializes the parsed data back into a byte array if
288     * they override {@link #setData(byte[])}.
289     * 
290     * @return byte[]
291     */
292    public byte[] getData()
293    {
294        return data;
295    }
296
297
298    public final void writeTo( ByteBuffer out )
299    {
300        out.put( getTag() );
301
302        // FIXME: handle continuation, i.e. options longer than 128 bytes?
303        byte[] data = getData();
304
305        if ( data.length > 255 )
306        {
307            throw new IllegalArgumentException( I18n.err( I18n.ERR_641 ) );
308        }
309
310        out.put( ( byte ) data.length );
311        out.put( data );
312    }
313}