| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| package org.apache.directory.server.dhcp.protocol; |
| |
| |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| |
| import org.apache.directory.server.dhcp.messages.DhcpMessage; |
| import org.apache.directory.server.dhcp.messages.MessageType; |
| import org.apache.directory.server.dhcp.service.DhcpService; |
| import org.apache.mina.core.service.IoHandler; |
| import org.apache.mina.core.session.IdleStatus; |
| import org.apache.mina.core.session.IoSession; |
| import org.apache.mina.filter.codec.ProtocolCodecFilter; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * Implementation of a DHCP protocol handler which delegates the work of |
| * generating replys to a DhcpService implementation. |
| * |
| * @see org.apache.directory.server.dhcp.service.DhcpService |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class DhcpProtocolHandler implements IoHandler |
| { |
| private static final Logger logger = LoggerFactory |
| .getLogger( DhcpProtocolHandler.class ); |
| |
| /** |
| * Default DHCP client port |
| */ |
| public static final int CLIENT_PORT = 68; |
| |
| /** |
| * Default DHCP server port |
| */ |
| public static final int SERVER_PORT = 67; |
| |
| /** |
| * The DHCP service implementation. The implementation is supposed to be |
| * thread-safe. |
| */ |
| private final DhcpService dhcpService; |
| |
| |
| /** |
| * |
| */ |
| public DhcpProtocolHandler( DhcpService service ) |
| { |
| this.dhcpService = service; |
| } |
| |
| |
| public void sessionCreated( IoSession session ) throws Exception |
| { |
| logger.debug( "{} CREATED", session.getLocalAddress() ); |
| session.getFilterChain().addFirst( "codec", |
| new ProtocolCodecFilter( new DhcpProtocolCodecFactory() ) ); |
| } |
| |
| |
| public void sessionOpened( IoSession session ) |
| { |
| logger.debug( "{} -> {} OPENED", session.getRemoteAddress(), session |
| .getLocalAddress() ); |
| } |
| |
| |
| public void sessionClosed( IoSession session ) |
| { |
| logger.debug( "{} -> {} CLOSED", session.getRemoteAddress(), session |
| .getLocalAddress() ); |
| } |
| |
| |
| public void sessionIdle( IoSession session, IdleStatus status ) |
| { |
| // ignore |
| } |
| |
| |
| public void exceptionCaught( IoSession session, Throwable cause ) |
| { |
| logger.error( "EXCEPTION CAUGHT ", cause ); |
| cause.printStackTrace( System.out ); |
| |
| session.close( true ); |
| } |
| |
| |
| public void messageReceived( IoSession session, Object message ) |
| throws Exception |
| { |
| if ( logger.isDebugEnabled() ) |
| { |
| logger.debug( "{} -> {} RCVD: {} " + message, session.getRemoteAddress(), |
| session.getLocalAddress() ); |
| } |
| |
| final DhcpMessage request = ( DhcpMessage ) message; |
| |
| final DhcpMessage reply = dhcpService.getReplyFor( |
| ( InetSocketAddress ) session.getServiceAddress(), |
| ( InetSocketAddress ) session.getRemoteAddress(), request ); |
| |
| if ( null != reply ) |
| { |
| final InetSocketAddress isa = determineMessageDestination( request, reply ); |
| session.write( reply, isa ); |
| } |
| } |
| |
| |
| /** |
| * Determine where to send the message: <br> |
| * If the 'giaddr' field in a DHCP message from a client is non-zero, the |
| * server sends any return messages to the 'DHCP server' port on the BOOTP |
| * relay agent whose address appears in 'giaddr'. If the 'giaddr' field is |
| * zero and the 'ciaddr' field is nonzero, then the server unicasts DHCPOFFER |
| * and DHCPACK messages to the address in 'ciaddr'. If 'giaddr' is zero and |
| * 'ciaddr' is zero, and the broadcast bit is set, then the server broadcasts |
| * DHCPOFFER and DHCPACK messages to 0xffffffff. If the broadcast bit is not |
| * set and 'giaddr' is zero and 'ciaddr' is zero, then the server unicasts |
| * DHCPOFFER and DHCPACK messages to the client's hardware address and |
| * 'yiaddr' address. In all cases, when 'giaddr' is zero, the server |
| * broadcasts any DHCPNAK messages to 0xffffffff. |
| * |
| * @param request |
| * @param reply |
| * @return |
| */ |
| //This will suppress PMD.AvoidUsingHardCodedIP warnings in this class |
| @SuppressWarnings("PMD.AvoidUsingHardCodedIP") |
| private InetSocketAddress determineMessageDestination( DhcpMessage request, |
| DhcpMessage reply ) |
| { |
| |
| final MessageType mt = reply.getMessageType(); |
| |
| if ( !isNullAddress( request.getRelayAgentAddress() ) ) |
| { |
| // send to agent, if received via agent. |
| return new InetSocketAddress( request.getRelayAgentAddress(), SERVER_PORT ); |
| } |
| else if ( null != mt && mt == MessageType.DHCPNAK ) |
| { |
| // force broadcast for DHCPNAKs |
| return new InetSocketAddress( "255.255.255.255", 68 ); |
| } |
| else |
| { |
| // not a NAK... |
| if ( !isNullAddress( request.getCurrentClientAddress() ) ) |
| { |
| // have a current address? unicast to it. |
| return new InetSocketAddress( request.getCurrentClientAddress(), |
| CLIENT_PORT ); |
| } |
| else |
| { |
| return new InetSocketAddress( "255.255.255.255", 68 ); |
| } |
| } |
| } |
| |
| |
| /** |
| * Determine, whether the given address ist actually the null address |
| * "0.0.0.0". |
| * |
| * @param relayAgentAddress |
| * @return |
| */ |
| private boolean isNullAddress( InetAddress addr ) |
| { |
| final byte a[] = addr.getAddress(); |
| |
| for ( int i = 0; i < a.length; i++ ) |
| { |
| if ( a[i] != 0 ) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| public void messageSent( IoSession session, Object message ) |
| { |
| if ( logger.isDebugEnabled() ) |
| { |
| logger.debug( "{} -> {} SENT: " + message, session.getRemoteAddress(), |
| session.getLocalAddress() ); |
| } |
| } |
| |
| public void inputClosed( IoSession session ) |
| { |
| } |
| } |