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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresApi; 22 import android.os.Build; 23 import android.os.Looper; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.net.module.util.SharedLog; 27 28 import java.util.Collections; 29 import java.util.List; 30 31 /** 32 * Sends mDns announcements when a service registration changes and at regular intervals. 33 * 34 * This allows maintaining other hosts' caches up-to-date. See RFC6762 8.3. 35 */ 36 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 37 public class MdnsAnnouncer extends MdnsPacketRepeater<MdnsAnnouncer.BaseAnnouncementInfo> { 38 private static final long ANNOUNCEMENT_INITIAL_DELAY_MS = 1000L; 39 @VisibleForTesting 40 static final int ANNOUNCEMENT_COUNT = 8; 41 42 // Matches delay and GoodbyeCount used by the legacy implementation 43 private static final long EXIT_DELAY_MS = 2000L; 44 private static final int EXIT_COUNT = 3; 45 46 /** Base class for announcement requests to send with {@link MdnsAnnouncer}. */ 47 public abstract static class BaseAnnouncementInfo implements MdnsPacketRepeater.Request { 48 private final int mServiceId; 49 @NonNull 50 private final MdnsPacket mPacket; 51 BaseAnnouncementInfo(int serviceId, @NonNull List<MdnsRecord> announcedRecords, @NonNull List<MdnsRecord> additionalRecords)52 protected BaseAnnouncementInfo(int serviceId, @NonNull List<MdnsRecord> announcedRecords, 53 @NonNull List<MdnsRecord> additionalRecords) { 54 mServiceId = serviceId; 55 final int flags = 0x8400; // Response, authoritative (rfc6762 18.4) 56 mPacket = new MdnsPacket(flags, 57 Collections.emptyList() /* questions */, 58 announcedRecords, 59 Collections.emptyList() /* authorityRecords */, 60 additionalRecords); 61 } 62 getServiceId()63 public int getServiceId() { 64 return mServiceId; 65 } 66 67 @Override getPacket(int index)68 public MdnsPacket getPacket(int index) { 69 return mPacket; 70 } 71 } 72 73 /** Announcement request to send with {@link MdnsAnnouncer}. */ 74 public static class AnnouncementInfo extends BaseAnnouncementInfo { AnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords, List<MdnsRecord> additionalRecords)75 AnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords, 76 List<MdnsRecord> additionalRecords) { 77 super(serviceId, announcedRecords, additionalRecords); 78 } 79 80 @Override getDelayMs(int nextIndex)81 public long getDelayMs(int nextIndex) { 82 // Delay is doubled for each announcement 83 return ANNOUNCEMENT_INITIAL_DELAY_MS << (nextIndex - 1); 84 } 85 86 @Override getNumSends()87 public int getNumSends() { 88 return ANNOUNCEMENT_COUNT; 89 } 90 } 91 92 /** Service exit announcement request to send with {@link MdnsAnnouncer}. */ 93 public static class ExitAnnouncementInfo extends BaseAnnouncementInfo { ExitAnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords)94 ExitAnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords) { 95 super(serviceId, announcedRecords, Collections.emptyList() /* additionalRecords */); 96 } 97 98 @Override getDelayMs(int nextIndex)99 public long getDelayMs(int nextIndex) { 100 return EXIT_DELAY_MS; 101 } 102 103 @Override getNumSends()104 public int getNumSends() { 105 return EXIT_COUNT; 106 } 107 } 108 MdnsAnnouncer(@onNull Looper looper, @NonNull MdnsReplySender replySender, @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb, @NonNull SharedLog sharedLog)109 public MdnsAnnouncer(@NonNull Looper looper, 110 @NonNull MdnsReplySender replySender, 111 @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb, 112 @NonNull SharedLog sharedLog) { 113 super(looper, replySender, cb, sharedLog, MdnsAdvertiser.DBG); 114 } 115 116 // TODO: Notify MdnsRecordRepository that the records were announced for that service ID, 117 // so it can update the last advertised timestamp of the associated records. 118 } 119