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 03:41:35 +0200 (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 }