• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.util.ArraySet;
26 
27 import com.android.net.module.util.FdEventsReader;
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 = new ArraySet<>();
43 
44     interface PacketHandler {
handlePacket(byte[] recvbuf, int length, InetSocketAddress src)45         void handlePacket(byte[] recvbuf, int length, InetSocketAddress src);
46     }
47 
48     public static final class RecvBuffer {
49         final byte[] data;
50         final InetSocketAddress src;
51 
RecvBuffer(byte[] data, InetSocketAddress src)52         private RecvBuffer(byte[] data, InetSocketAddress src) {
53             this.data = data;
54             this.src = src;
55         }
56     }
57 
58     /**
59      * Create a new {@link MulticastPacketReader}.
60      * @param socket Socket to read from. This will *not* be closed when the reader terminates.
61      * @param buffer Buffer to read packets into. Will only be used from the handler thread.
62      * @param port the port number for the socket
63      */
MulticastPacketReader(@onNull String interfaceTag, @NonNull ParcelFileDescriptor socket, @NonNull Handler handler, @NonNull byte[] buffer)64     protected MulticastPacketReader(@NonNull String interfaceTag,
65             @NonNull ParcelFileDescriptor socket, @NonNull Handler handler,
66             @NonNull byte[] buffer) {
67         // Set the port to zero as placeholder as the recvfrom() call will fill the actual port
68         // value later.
69         super(handler, new RecvBuffer(buffer, new InetSocketAddress(0 /* port */)));
70         mLogTag = MulticastPacketReader.class.getSimpleName() + "/" + interfaceTag;
71         mSocket = socket;
72         mHandler = handler;
73     }
74 
75     @Override
recvBufSize(@onNull RecvBuffer buffer)76     protected int recvBufSize(@NonNull RecvBuffer buffer) {
77         return buffer.data.length;
78     }
79 
80     @Override
createFd()81     protected FileDescriptor createFd() {
82         // Keep a reference to the PFD as it would close the fd in its finalizer otherwise
83         return mSocket.getFileDescriptor();
84     }
85 
86     @Override
onStop()87     protected void onStop() {
88         // Do nothing (do not close the FD)
89     }
90 
91     @Override
readPacket(@onNull FileDescriptor fd, @NonNull RecvBuffer buffer)92     protected int readPacket(@NonNull FileDescriptor fd, @NonNull RecvBuffer buffer)
93             throws Exception {
94         return Os.recvfrom(
95                 fd, buffer.data, 0, buffer.data.length, 0 /* flags */, buffer.src);
96     }
97 
98     @Override
handlePacket(@onNull RecvBuffer recvbuf, int length)99     protected void handlePacket(@NonNull RecvBuffer recvbuf, int length) {
100         for (PacketHandler handler : mPacketHandlers) {
101             handler.handlePacket(recvbuf.data, length, recvbuf.src);
102         }
103     }
104 
105     /**
106      * Add a packet handler to deal with received packets. If the handler is already set,
107      * this is a no-op.
108      */
addPacketHandler(@onNull PacketHandler handler)109     public void addPacketHandler(@NonNull PacketHandler handler) {
110         ensureRunningOnHandlerThread(mHandler);
111         mPacketHandlers.add(handler);
112     }
113 
114     /**
115      * Remove a packet handler added via {@link #addPacketHandler}. If the handler was not set,
116      * this is a no-op.
117      */
removePacketHandler(@onNull PacketHandler handler)118     public void removePacketHandler(@NonNull PacketHandler handler) {
119         ensureRunningOnHandlerThread(mHandler);
120         mPacketHandlers.remove(handler);
121     }
122 }
123 
124