View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.dhcp.store;
21  
22  
23  import java.net.InetAddress;
24  import java.util.Map;
25  
26  import org.apache.directory.server.dhcp.DhcpException;
27  import org.apache.directory.server.dhcp.messages.HardwareAddress;
28  import org.apache.directory.server.dhcp.options.OptionsField;
29  import org.apache.directory.server.dhcp.options.vendor.HostName;
30  import org.apache.directory.server.dhcp.options.vendor.SubnetMask;
31  import org.apache.directory.server.dhcp.service.Lease;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * Abstract base implementation of a {@link DhcpStore}.
38   * 
39   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
40   * @version $Rev: 545042 $, $Date: 2007-06-06 22:32:01 -0500 (Mi, 06 Jun 2007) $
41   */
42  public abstract class AbstractDhcpStore implements DhcpStore
43  {
44      private static final Logger logger = LoggerFactory.getLogger( AbstractDhcpStore.class );
45  
46  
47      /*
48       * @see org.apache.directory.server.dhcp.service.DhcpStore#getLeaseOffer(org.apache.directory.server.dhcp.messages.HardwareAddress,
49       *      java.net.InetAddress, java.net.InetAddress, long,
50       *      org.apache.directory.server.dhcp.options.OptionsField)
51       */
52      public Lease getLeaseOffer( HardwareAddress hardwareAddress, InetAddress requestedAddress,
53          InetAddress selectionBase, long requestedLeaseTime, OptionsField options ) throws DhcpException
54      {
55          Subnet subnet = findSubnet( selectionBase );
56          if ( null == subnet )
57          {
58              logger.warn( "Don't know anything about the sbnet containing " + selectionBase );
59              return null;
60          }
61  
62          // try to find existing lease
63          Lease lease = null;
64          lease = findExistingLease( hardwareAddress, lease );
65          if ( null != lease )
66              return lease;
67  
68          Host host = null;
69          host = findDesignatedHost( hardwareAddress );
70          if ( null != host )
71          {
72              // make sure that the host is actually within the subnet. Depending
73              // on the way the DhcpStore configuration is implemented, it is not
74              // possible to violate this condition, but we can't be sure.
75              if ( !subnet.contains( host.getAddress() ) )
76              {
77                  logger.warn( "Host " + host + " is not within the subnet for which an address is requested" );
78              }
79              else
80              {
81                  // build properties map
82                  Map properties = getProperties( subnet );
83                  properties.putAll( getProperties( host ) );
84  
85                  // build lease
86                  lease = new Lease();
87                  lease.setAcquired( System.currentTimeMillis() );
88  
89                  long leaseTime = determineLeaseTime( requestedLeaseTime, properties );
90  
91                  lease.setExpires( System.currentTimeMillis() + leaseTime );
92  
93                  lease.setHardwareAddress( hardwareAddress );
94                  lease.setState( Lease.STATE_NEW );
95                  lease.setClientAddress( host.getAddress() );
96  
97                  // set lease options
98                  OptionsField o = lease.getOptions();
99  
100                 // set (client) host name
101                 o.add( new HostName( host.getName() ) );
102 
103                 // add subnet settings
104                 o.add( new SubnetMask( subnet.getNetmask() ) );
105                 o.merge( subnet.getOptions() );
106 
107                 // add the host's options. they override existing
108                 // subnet options as they take the precedence.
109                 o.merge( host.getOptions() );
110             }
111         }
112 
113         if ( null == lease )
114         {
115             // FIXME: use selection base to find a lease in a pool.
116         }
117 
118         // update the lease state
119         if ( null != lease && lease.getState() != Lease.STATE_ACTIVE )
120         {
121             lease.setState( Lease.STATE_OFFERED );
122             updateLease( lease );
123         }
124 
125         return lease;
126     }
127 
128 
129     /*
130      * @see org.apache.directory.server.dhcp.store.DhcpStore#getExistingLease(org.apache.directory.server.dhcp.messages.HardwareAddress,
131      *      java.net.InetAddress, java.net.InetAddress, long,
132      *      org.apache.directory.server.dhcp.options.OptionsField)
133      */
134     public Lease getExistingLease( HardwareAddress hardwareAddress, InetAddress requestedAddress,
135         InetAddress selectionBase, long requestedLeaseTime, OptionsField options ) throws DhcpException
136     {
137         // try to find existing lease. if we don't find a lease based on the
138         // client's
139         // hardware address, we send a NAK.
140         Lease lease = null;
141         lease = findExistingLease( hardwareAddress, lease );
142         if ( null == lease )
143             return null;
144 
145         // check whether the notions of the client address match
146         if ( !lease.getClientAddress().equals( requestedAddress ) )
147         {
148             logger.warn( "Requested address " + requestedAddress + " for " + hardwareAddress
149                 + " doesn't match existing lease " + lease );
150             return null;
151         }
152 
153         // check whether addresses and subnet match
154         Subnet subnet = findSubnet( selectionBase );
155         if ( null == subnet )
156         {
157             logger.warn( "No subnet found for existing lease " + lease );
158             return null;
159         }
160         if ( !subnet.contains( lease.getClientAddress() ) )
161         {
162             logger.warn( "Client with existing lease " + lease + " is on wrong subnet " + subnet );
163             return null;
164         }
165         if ( !subnet.isInRange( lease.getClientAddress() ) )
166         {
167             logger.warn( "Client with existing lease " + lease + " is out of valid range for subnet " + subnet );
168             return null;
169         }
170 
171         // build properties map
172         Map properties = getProperties( subnet );
173 
174         // update lease options
175         OptionsField o = lease.getOptions();
176         o.clear();
177 
178         // add subnet settings
179         o.add( new SubnetMask( subnet.getNetmask() ) );
180         o.merge( subnet.getOptions() );
181 
182         // check whether there is a designated host.
183         Host host = findDesignatedHost( hardwareAddress );
184         if ( null != host )
185         {
186             // check whether the host matches the address (using a fixed
187             // host address is mandatory).
188             if ( host.getAddress() != null && !host.getAddress().equals( lease.getClientAddress() ) )
189             {
190                 logger.warn( "Existing fixed address for " + hardwareAddress + " conflicts with existing lease "
191                     + lease );
192                 return null;
193             }
194 
195             properties.putAll( getProperties( host ) );
196 
197             // set (client) host name
198             o.add( new HostName( host.getName() ) );
199 
200             // add the host's options
201             o.merge( host.getOptions() );
202         }
203 
204         // update other lease fields
205         long leaseTime = determineLeaseTime( requestedLeaseTime, properties );
206         lease.setExpires( System.currentTimeMillis() + leaseTime );
207         lease.setHardwareAddress( hardwareAddress );
208 
209         // update the lease state
210         if ( lease.getState() != Lease.STATE_ACTIVE )
211         {
212             lease.setState( Lease.STATE_ACTIVE );
213             updateLease( lease );
214         }
215 
216         // store information about the lease
217         updateLease( lease );
218 
219         return lease;
220     }
221 
222 
223     /**
224      * Determine the lease time based on the time requested by the client, the
225      * properties and a global default.
226      * 
227      * @param requestedLeaseTime
228      * @param properties
229      * @return long
230      */
231     private long determineLeaseTime( long requestedLeaseTime, Map properties )
232     {
233         // built-in default
234         long leaseTime = 1000L * 3600;
235         Integer propMaxLeaseTime = ( Integer ) properties.get( DhcpConfigElement.PROPERTY_MAX_LEASE_TIME );
236         if ( null != propMaxLeaseTime )
237             if ( requestedLeaseTime > 0 )
238                 leaseTime = Math.min( propMaxLeaseTime.intValue() * 1000L, requestedLeaseTime );
239             else
240                 leaseTime = propMaxLeaseTime.intValue() * 1000L;
241         return leaseTime;
242     }
243 
244 
245     /*
246      * @see org.apache.directory.server.dhcp.store.DhcpStore#releaseLease(org.apache.directory.server.dhcp.service.Lease)
247      */
248     public void releaseLease( Lease lease )
249     {
250         lease.setState( Lease.STATE_RELEASED );
251         updateLease( lease );
252     }
253 
254 
255     /**
256      * Update the (possibly changed) lease in the store.
257      * 
258      * @param lease
259      */
260     protected abstract void updateLease( Lease lease );
261 
262 
263     /**
264      * Return a list of all options applicable to the given config element. List
265      * list must contain the options specified for the element and all parent
266      * elements in an aggregated fashion. For instance, the options for a host
267      * must include the global default options, the options of classes the host
268      * is a member of, the host's group options and the host's options.
269      * 
270      * @param element
271      * @return OptionsField
272      */
273     protected abstract OptionsField getOptions( DhcpConfigElement element );
274 
275 
276     /**
277      * Return a list of all options applicable to the given config element. List
278      * list must contain the options specified for the element and all parent
279      * elements in an aggregated fashion. For instance, the options for a host
280      * must include the global default options, the options of classes the host
281      * is a member of, the host's group options and the host's options.
282      * 
283      * @param element
284      * @return Map
285      */
286     protected abstract Map getProperties( DhcpConfigElement element );
287 
288 
289     /**
290      * Find an existing lease in the store.
291      * 
292      * @param hardwareAddress
293      * @param existingLease
294      * @return Map
295      */
296     protected abstract Lease findExistingLease( HardwareAddress hardwareAddress, Lease existingLease );
297 
298 
299     /**
300      * Find a host to with the explicitely designated hardware address.
301      * 
302      * @param hardwareAddress
303      * @return Host
304      * @throws DhcpException
305      */
306     protected abstract Host findDesignatedHost( HardwareAddress hardwareAddress ) throws DhcpException;
307 
308 
309     /**
310      * Find the subnet definition matching the given address.
311      * 
312      * @param clientAddress
313      * @return Subnet
314      */
315     protected abstract Subnet findSubnet( InetAddress clientAddress );
316 }