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 021 package org.apache.directory.server.dhcp.protocol; 022 023 import java.net.InetAddress; 024 import java.net.InetSocketAddress; 025 026 import org.apache.directory.server.dhcp.messages.DhcpMessage; 027 import org.apache.directory.server.dhcp.messages.MessageType; 028 import org.apache.directory.server.dhcp.service.DhcpService; 029 import org.apache.mina.core.service.IoHandler; 030 import org.apache.mina.core.session.IdleStatus; 031 import org.apache.mina.core.session.IoSession; 032 import org.apache.mina.filter.codec.ProtocolCodecFilter; 033 import org.slf4j.Logger; 034 import org.slf4j.LoggerFactory; 035 036 /** 037 * Implementation of a DHCP protocol handler which delegates the work of 038 * generating replys to a DhcpService implementation. 039 * 040 * @see org.apache.directory.server.dhcp.service.DhcpService 041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 042 * @version $Rev: 725712 $, $Date: 2008-12-11 16:32:04 +0100 (Thu, 11 Dec 2008) $ 043 */ 044 public class DhcpProtocolHandler implements IoHandler { 045 private static final Logger logger = LoggerFactory 046 .getLogger(DhcpProtocolHandler.class); 047 048 /** 049 * Default DHCP client port 050 */ 051 public static final int CLIENT_PORT = 68; 052 053 /** 054 * Default DHCP server port 055 */ 056 public static final int SERVER_PORT = 67; 057 058 /** 059 * The DHCP service implementation. The implementation is supposed to be 060 * thread-safe. 061 */ 062 private final DhcpService dhcpService; 063 064 /** 065 * 066 */ 067 public DhcpProtocolHandler(DhcpService service) { 068 this.dhcpService = service; 069 } 070 071 public void sessionCreated(IoSession session) throws Exception { 072 logger.debug("{} CREATED", session.getLocalAddress()); 073 session.getFilterChain().addFirst("codec", 074 new ProtocolCodecFilter(new DhcpProtocolCodecFactory())); 075 } 076 077 public void sessionOpened(IoSession session) { 078 logger.debug("{} -> {} OPENED", session.getRemoteAddress(), session 079 .getLocalAddress()); 080 } 081 082 public void sessionClosed(IoSession session) { 083 logger.debug("{} -> {} CLOSED", session.getRemoteAddress(), session 084 .getLocalAddress()); 085 } 086 087 public void sessionIdle(IoSession session, IdleStatus status) { 088 // ignore 089 } 090 091 public void exceptionCaught(IoSession session, Throwable cause) { 092 logger.error("EXCEPTION CAUGHT ", cause); 093 cause.printStackTrace(System.out); 094 095 session.close( true ); 096 } 097 098 public void messageReceived(IoSession session, Object message) 099 throws Exception { 100 if (logger.isDebugEnabled()) 101 logger.debug("{} -> {} RCVD: {} " + message, session.getRemoteAddress(), 102 session.getLocalAddress()); 103 104 final DhcpMessage request = (DhcpMessage) message; 105 106 final DhcpMessage reply = dhcpService.getReplyFor( 107 (InetSocketAddress) session.getServiceAddress(), 108 (InetSocketAddress) session.getRemoteAddress(), request); 109 110 if (null != reply) { 111 final InetSocketAddress isa = determineMessageDestination(request, reply); 112 session.write(reply, isa); 113 } 114 } 115 116 /** 117 * Determine where to send the message: <br> 118 * If the 'giaddr' field in a DHCP message from a client is non-zero, the 119 * server sends any return messages to the 'DHCP server' port on the BOOTP 120 * relay agent whose address appears in 'giaddr'. If the 'giaddr' field is 121 * zero and the 'ciaddr' field is nonzero, then the server unicasts DHCPOFFER 122 * and DHCPACK messages to the address in 'ciaddr'. If 'giaddr' is zero and 123 * 'ciaddr' is zero, and the broadcast bit is set, then the server broadcasts 124 * DHCPOFFER and DHCPACK messages to 0xffffffff. If the broadcast bit is not 125 * set and 'giaddr' is zero and 'ciaddr' is zero, then the server unicasts 126 * DHCPOFFER and DHCPACK messages to the client's hardware address and 127 * 'yiaddr' address. In all cases, when 'giaddr' is zero, the server 128 * broadcasts any DHCPNAK messages to 0xffffffff. 129 * 130 * @param request 131 * @param reply 132 * @return 133 */ 134 private InetSocketAddress determineMessageDestination(DhcpMessage request, 135 DhcpMessage reply) { 136 137 final MessageType mt = reply.getMessageType(); 138 if (!isNullAddress(request.getRelayAgentAddress())) 139 // send to agent, if received via agent. 140 return new InetSocketAddress(request.getRelayAgentAddress(), SERVER_PORT); 141 else if (null != mt && mt == MessageType.DHCPNAK) 142 // force broadcast for DHCPNAKs 143 return new InetSocketAddress("255.255.255.255", 68); 144 else // not a NAK... 145 if (!isNullAddress(request.getCurrentClientAddress())) 146 // have a current address? unicast to it. 147 return new InetSocketAddress(request.getCurrentClientAddress(), 148 CLIENT_PORT); 149 else 150 return new InetSocketAddress("255.255.255.255", 68); 151 } 152 153 /** 154 * Determine, whether the given address ist actually the null address 155 * "0.0.0.0". 156 * 157 * @param relayAgentAddress 158 * @return 159 */ 160 private boolean isNullAddress(InetAddress addr) { 161 final byte a[] = addr.getAddress(); 162 for (int i = 0; i < a.length; i++) 163 if (a[i] != 0) 164 return false; 165 return true; 166 } 167 168 public void messageSent(IoSession session, Object message) { 169 if (logger.isDebugEnabled()) 170 logger.debug("{} -> {} SENT: " + message, session.getRemoteAddress(), 171 session.getLocalAddress()); 172 } 173 }