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.io; 022 023 024 import java.io.UnsupportedEncodingException; 025 import java.net.InetAddress; 026 import java.nio.ByteBuffer; 027 import java.util.Iterator; 028 029 import org.apache.directory.server.dhcp.messages.DhcpMessage; 030 import org.apache.directory.server.dhcp.messages.HardwareAddress; 031 import org.apache.directory.server.dhcp.options.DhcpOption; 032 import org.apache.directory.server.dhcp.options.OptionsField; 033 import org.apache.directory.server.dhcp.options.dhcp.DhcpMessageType; 034 import org.apache.directory.server.i18n.I18n; 035 036 037 /** 038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 039 * @version $Rev: 902331 $, $Date: 2010-01-23 02:41:35 +0100 (Sat, 23 Jan 2010) $ 040 */ 041 public class DhcpMessageEncoder 042 { 043 /** 044 * Converts a DhcpMessage object into a byte buffer. 045 * 046 * @param byteBuffer ByteBuffer to put DhcpMessage into 047 * @param message DhcpMessage to encode into ByteBuffer 048 */ 049 public void encode( ByteBuffer byteBuffer, DhcpMessage message ) 050 { 051 byteBuffer.put( message.getOp() ); 052 053 HardwareAddress hardwareAddress = message.getHardwareAddress(); 054 055 byteBuffer.put( ( byte ) ( null != hardwareAddress ? hardwareAddress.getType() : 0 ) ); 056 byteBuffer.put( ( byte ) ( null != hardwareAddress ? hardwareAddress.getLength() : 0 ) ); 057 byteBuffer.put( ( byte ) message.getHopCount() ); 058 byteBuffer.putInt( message.getTransactionId() ); 059 byteBuffer.putShort( ( short ) message.getSeconds() ); 060 byteBuffer.putShort( message.getFlags() ); 061 062 writeAddress( byteBuffer, message.getCurrentClientAddress() ); 063 writeAddress( byteBuffer, message.getAssignedClientAddress() ); 064 writeAddress( byteBuffer, message.getNextServerAddress() ); 065 writeAddress( byteBuffer, message.getRelayAgentAddress() ); 066 067 writeBytes( byteBuffer, ( null != hardwareAddress ? hardwareAddress.getAddress() : new byte[] 068 {} ), 16 ); 069 070 writeString( byteBuffer, message.getServerHostname(), 64 ); 071 writeString( byteBuffer, message.getBootFileName(), 128 ); 072 073 OptionsField options = message.getOptions(); 074 075 // update message type option (if set) 076 if ( null != message.getMessageType() ) 077 options.add( new DhcpMessageType( message.getMessageType() ) ); 078 079 encodeOptions( options, byteBuffer ); 080 } 081 082 083 /** 084 * Write a zero-terminated string to a field of len bytes. 085 * 086 * @param byteBuffer 087 * @param serverHostname 088 * @param i 089 */ 090 private void writeString( ByteBuffer byteBuffer, String string, int len ) 091 { 092 if ( null == string ) 093 string = ""; 094 095 try 096 { 097 byte sbytes[] = string.getBytes( "ASCII" ); 098 099 // writeBytes will automatically zero-pad and thus terminate the 100 // string. 101 writeBytes( byteBuffer, sbytes, len ); 102 } 103 catch ( UnsupportedEncodingException e ) 104 { 105 // should not happen 106 throw new RuntimeException( I18n.err( I18n.ERR_635 ), e ); 107 } 108 } 109 110 111 /** 112 * Write an InetAddress to the byte buffer. 113 * 114 * @param byteBuffer 115 * @param currentClientAddress 116 */ 117 private void writeAddress( ByteBuffer byteBuffer, InetAddress currentClientAddress ) 118 { 119 if ( null == currentClientAddress ) 120 { 121 byte emptyAddress[] = 122 { 0, 0, 0, 0 }; 123 byteBuffer.put( emptyAddress ); 124 } 125 else 126 { 127 byte[] addressBytes = currentClientAddress.getAddress(); 128 byteBuffer.put( addressBytes ); 129 } 130 } 131 132 133 /** 134 * Write an array of bytes to the buffer. Write exactly len bytes, 135 * truncating if more than len, padding if less than len bytes are 136 * available. 137 * 138 * @param byteBuffer 139 * @param currentClientAddress 140 */ 141 private void writeBytes( ByteBuffer byteBuffer, byte bytes[], int len ) 142 { 143 if ( null == bytes ) 144 bytes = new byte[] 145 {}; 146 147 byteBuffer.put( bytes, 0, Math.min(len, bytes.length) ); 148 149 // pad as necessary 150 int remain = len - bytes.length; 151 while ( remain-- > 0 ) 152 byteBuffer.put( ( byte ) 0 ); 153 } 154 155 private static final byte[] VENDOR_MAGIC_COOKIE = 156 { ( byte ) 99, ( byte ) 130, ( byte ) 83, ( byte ) 99 }; 157 158 159 public void encodeOptions( OptionsField options, ByteBuffer message ) 160 { 161 message.put( VENDOR_MAGIC_COOKIE ); 162 163 for ( Iterator i = options.iterator(); i.hasNext(); ) 164 { 165 DhcpOption option = ( DhcpOption ) i.next(); 166 option.writeTo( message ); 167 } 168 169 // add end option 170 message.put( ( byte ) 0xff ); 171 } 172 }