blob: 17632a4638564e43654df5ba9b48c9ab0d534f74 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed 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 android.net.dhcp;
import android.os.Handler;
import android.system.Os;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.net.module.util.FdEventsReader;
import java.io.FileDescriptor;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
/**
* A {@link FdEventsReader} to receive and parse {@link DhcpPacket}.
* @hide
*/
abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
static final class Payload {
protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH];
protected Inet4Address mSrcAddr;
protected int mSrcPort;
}
DhcpPacketListener(@NonNull Handler handler) {
super(handler, new Payload());
}
@Override
protected int recvBufSize(@NonNull Payload buffer) {
return buffer.mBytes.length;
}
@Override
protected final void handlePacket(@NonNull Payload recvbuf, int length) {
if (recvbuf.mSrcAddr == null) {
return;
}
try {
final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length,
DhcpPacket.ENCAP_BOOTP);
onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort);
} catch (DhcpPacket.ParseException e) {
logParseError(recvbuf.mBytes, length, e);
} catch (Throwable e) {
Log.wtf(DhcpPacketListener.class.getSimpleName(), "Error handling DHCP packet", e);
}
}
@Override
protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer)
throws Exception {
final InetSocketAddress addr = new InetSocketAddress(0);
final int read = Os.recvfrom(
fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr);
// Buffers with null srcAddr will be dropped in handlePacket()
packetBuffer.mSrcAddr = inet4AddrOrNull(addr);
packetBuffer.mSrcPort = addr.getPort();
return read;
}
@Nullable
private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) {
return addr.getAddress() instanceof Inet4Address
? (Inet4Address) addr.getAddress()
: null;
}
protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
int srcPort);
protected abstract void logParseError(@NonNull byte[] packet, int length,
@NonNull DhcpPacket.ParseException e);
}