1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.connectivity.mdns; 18 19 import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread; 20 21 import android.annotation.NonNull; 22 import android.os.Handler; 23 import android.os.ParcelFileDescriptor; 24 import android.system.Os; 25 26 import com.android.net.module.util.FdEventsReader; 27 import com.android.server.connectivity.mdns.util.MdnsUtils; 28 29 import java.io.FileDescriptor; 30 import java.net.InetSocketAddress; 31 import java.util.Set; 32 33 /** Simple reader for mDNS packets. */ 34 public class MulticastPacketReader extends FdEventsReader<MulticastPacketReader.RecvBuffer> { 35 @NonNull 36 private final String mLogTag; 37 @NonNull 38 private final ParcelFileDescriptor mSocket; 39 @NonNull 40 private final Handler mHandler; 41 @NonNull 42 private final Set<PacketHandler> mPacketHandlers = MdnsUtils.newSet(); 43 44 interface PacketHandler { 45 /** 46 * Handle an incoming packet. 47 * 48 * The recvbuf and src <b>will be reused and modified</b> after this method returns, so 49 * implementers must ensure that they are not accessed after handlePacket returns. 50 */ handlePacket(byte[] recvbuf, int length, InetSocketAddress src)51 void handlePacket(byte[] recvbuf, int length, InetSocketAddress src); 52 } 53 54 public static final class RecvBuffer { 55 final byte[] data; 56 final InetSocketAddress src; 57 RecvBuffer(byte[] data, InetSocketAddress src)58 private RecvBuffer(byte[] data, InetSocketAddress src) { 59 this.data = data; 60 this.src = src; 61 } 62 } 63 64 /** 65 * Create a new {@link MulticastPacketReader}. 66 * @param socket Socket to read from. This will *not* be closed when the reader terminates. 67 * @param buffer Buffer to read packets into. Will only be used from the handler thread. 68 * @param port the port number for the socket 69 */ MulticastPacketReader(@onNull String interfaceTag, @NonNull ParcelFileDescriptor socket, @NonNull Handler handler, @NonNull byte[] buffer)70 protected MulticastPacketReader(@NonNull String interfaceTag, 71 @NonNull ParcelFileDescriptor socket, @NonNull Handler handler, 72 @NonNull byte[] buffer) { 73 // Set the port to zero as placeholder as the recvfrom() call will fill the actual port 74 // value later. 75 super(handler, new RecvBuffer(buffer, new InetSocketAddress(0 /* port */))); 76 mLogTag = MulticastPacketReader.class.getSimpleName() + "/" + interfaceTag; 77 mSocket = socket; 78 mHandler = handler; 79 } 80 81 @Override recvBufSize(@onNull RecvBuffer buffer)82 protected int recvBufSize(@NonNull RecvBuffer buffer) { 83 return buffer.data.length; 84 } 85 86 @Override createFd()87 protected FileDescriptor createFd() { 88 // Keep a reference to the PFD as it would close the fd in its finalizer otherwise 89 return mSocket.getFileDescriptor(); 90 } 91 92 @Override onStop()93 protected void onStop() { 94 // Do nothing (do not close the FD) 95 } 96 97 @Override readPacket(@onNull FileDescriptor fd, @NonNull RecvBuffer buffer)98 protected int readPacket(@NonNull FileDescriptor fd, @NonNull RecvBuffer buffer) 99 throws Exception { 100 return Os.recvfrom( 101 fd, buffer.data, 0, buffer.data.length, 0 /* flags */, buffer.src); 102 } 103 104 @Override handlePacket(@onNull RecvBuffer recvbuf, int length)105 protected void handlePacket(@NonNull RecvBuffer recvbuf, int length) { 106 for (PacketHandler handler : mPacketHandlers) { 107 handler.handlePacket(recvbuf.data, length, recvbuf.src); 108 } 109 } 110 111 /** 112 * Add a packet handler to deal with received packets. If the handler is already set, 113 * this is a no-op. 114 */ addPacketHandler(@onNull PacketHandler handler)115 public void addPacketHandler(@NonNull PacketHandler handler) { 116 ensureRunningOnHandlerThread(mHandler); 117 mPacketHandlers.add(handler); 118 } 119 120 /** 121 * Remove a packet handler added via {@link #addPacketHandler}. If the handler was not set, 122 * this is a no-op. 123 */ removePacketHandler(@onNull PacketHandler handler)124 public void removePacketHandler(@NonNull PacketHandler handler) { 125 ensureRunningOnHandlerThread(mHandler); 126 mPacketHandlers.remove(handler); 127 } 128 } 129 130