/**
 * Copyright (c) 2019, 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;

import android.net.ResolverOptionsParcel;
import android.net.ResolverParamsParcel;
import android.net.metrics.INetdEventListener;
import android.net.resolv.aidl.DnsForwardingParamsParcel;
import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;

/** @hide */
interface IDnsResolver {
    /**
     * Returns true if the service is responding.
     */
    boolean isAlive();

   /**
    * Register event listener
    * DnsResolver supports multiple event listeners, but only one per unique address of the
    * binder interface. A newer listener won't be registered if DnsResolver has an old one on
    * the same address of the binder interface.
    *
    * @param listener event listener to register.
    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
    *         unix errno.
    */
    void registerEventListener(INetdEventListener listener);

    // TODO: Delete these from the public interface
    // Array indices for resolver parameters.
    const int RESOLVER_PARAMS_SAMPLE_VALIDITY = 0;
    const int RESOLVER_PARAMS_SUCCESS_THRESHOLD = 1;
    const int RESOLVER_PARAMS_MIN_SAMPLES = 2;
    const int RESOLVER_PARAMS_MAX_SAMPLES = 3;
    const int RESOLVER_PARAMS_BASE_TIMEOUT_MSEC = 4;
    const int RESOLVER_PARAMS_RETRY_COUNT = 5;
    const int RESOLVER_PARAMS_COUNT = 6;

    /**
     * Sets the name servers, search domains and resolver params for the given network. Flushes the
     * cache as needed (i.e. when the servers or the number of samples to store changes).
     *
     * @param resolverParams the resolver parameters to be wrapped into parcel.
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         unix errno.
     */
    void setResolverConfiguration(in ResolverParamsParcel resolverParams);

    // Array indices for resolver stats.
    const int RESOLVER_STATS_SUCCESSES = 0;
    const int RESOLVER_STATS_ERRORS = 1;
    const int RESOLVER_STATS_TIMEOUTS = 2;
    const int RESOLVER_STATS_INTERNAL_ERRORS = 3;
    const int RESOLVER_STATS_RTT_AVG = 4;
    const int RESOLVER_STATS_LAST_SAMPLE_TIME = 5;
    const int RESOLVER_STATS_USABLE = 6;
    const int RESOLVER_STATS_COUNT = 7;

    /**
     * Retrieves the name servers, search domains and resolver stats associated with the given
     * network ID.
     *
     * @param netId the network ID of the network for which information should be retrieved.
     * @param servers the DNS servers that are currently configured for the network.
     * @param domains the search domains currently configured.
     * @param tlsServers the DNS-over-TLS servers that are currently configured for the network.
     * @param params the resolver parameters configured, i.e. the contents of __res_params in order.
     * @param stats the stats for each server in the order specified by RESOLVER_STATS_XXX
     *         constants, serialized as an int array. The contents of this array are the number of
     *         <ul>
     *           <li> successes,
     *           <li> errors,
     *           <li> timeouts,
     *           <li> internal errors,
     *           <li> the RTT average,
     *           <li> the time of the last recorded sample,
     *           <li> and an integer indicating whether the server is usable (1) or broken (0).
     *         </ul>
     *         in this order. For example, the timeout counter for server N is stored at position
     *         RESOLVER_STATS_COUNT*N + RESOLVER_STATS_TIMEOUTS
     * @param wait_for_pending_req_timeout_count an internal counter used to count the number of
     *        timeouts while resolver is handling concurrent DNS queries on the same hostname.
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         unix errno.
     *
     * TODO: Consider replacing stats and params with parcelables.
     */
    void getResolverInfo(int netId, out @utf8InCpp String[] servers,
            out @utf8InCpp String[] domains, out @utf8InCpp String[] tlsServers, out int[] params,
            out int[] stats, out int[] wait_for_pending_req_timeout_count);

    /**
     * Starts NAT64 prefix discovery on the given network.
     *
     * @param netId the netId to start prefix discovery on.
     */
    void startPrefix64Discovery(int netId);

    /**
     * Stops NAT64 prefix discovery on the given network.
     *
     * @param netId the netId to stop prefix discovery on.
     */
    void stopPrefix64Discovery(int netId);

    /**
     * Get NAT64 prefix in format Pref64::/n which is described in RFC6147 section 2. This
     * interface is used for internal test only. Don't use it for other purposes because doing so
     * would cause race conditions with the NAT64 prefix notifications.
     *
     * @param netId the network ID of the network to get the prefix
     * @return the NAT64 prefix if the query operation was successful
     * @throws ServiceSpecificException in case of failure, with an error code indicating the
     *         cause of the the failure.
     *
     * TODO: Remove this once the tests have been updated to listen for onNat64PrefixEvent.
     */
    @utf8InCpp String getPrefix64(int netId);

    /**
     * Create cache for the given network.
     *
     * @param netId the network ID of the network to create.
     * @throws ServiceSpecificException in case of failure, with an error code indicating the
     *         cause of the failure.
     */
    void createNetworkCache(int netId);

    /**
     * Destroy cache for the given network.
     *
     * @param netId the network ID of the network to destroy.
     */
    void destroyNetworkCache(int netId);

    // Refer to enum LogSeverity from system/libbase/include/android-base/logging.h
    const int DNS_RESOLVER_LOG_VERBOSE = 0;
    const int DNS_RESOLVER_LOG_DEBUG = 1;
    const int DNS_RESOLVER_LOG_INFO = 2;
    const int DNS_RESOLVER_LOG_WARNING = 3;
    const int DNS_RESOLVER_LOG_ERROR = 4;

    /**
     * Set DNS resolver log severity
     *
     * @param logSeverity print log in "VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR".
     *
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         POSIX errno.
     */
    void setLogSeverity(int logSeverity);

    /**
     * Flush cache for the given network.
     *
     * @param netId the network ID of the network to flush.
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         POSIX errno.
     */
    void flushNetworkCache(int netId);

    /**
     * Values for {@code tcMode} of {@code ResolverOptionsParcel}. It controls the way DNS
     * resolver handles truncated DNS response from UDP connection.
     *
     * TC_MODE_DEFAULT: resolver retries on TCP-only on each name server.
     * TC_MODE_UDP_TCP: resolver retries on TCP on the same server, falls back to UDP from next.
     */
    const int TC_MODE_DEFAULT = 0;
    const int TC_MODE_UDP_TCP = 1;

    /**
     * Values for {@code transportTypes} of {@code ResolverParamsParcel}. These values are
     * always the same as the TRANSPORT_* API definations of NetworkCapabilities except for
     * TRANSPORT_UNKNOWN. It controls the transport types for a given network.
     */
    const int TRANSPORT_UNKNOWN = -1;
    const int TRANSPORT_CELLULAR = 0;
    const int TRANSPORT_WIFI = 1;
    const int TRANSPORT_BLUETOOTH = 2;
    const int TRANSPORT_ETHERNET = 3;
    const int TRANSPORT_VPN = 4;
    const int TRANSPORT_WIFI_AWARE = 5;
    const int TRANSPORT_LOWPAN = 6;
    const int TRANSPORT_TEST = 7;
    const int TRANSPORT_USB = 8;
    const int TRANSPORT_THREAD = 9;
    const int TRANSPORT_SATELLITE = 10;

    /**
     * Sets the NAT64 prefix for the given network.
     *
     * Used when the NAT64 prefix has been discovered outside the DNS resolver, e.g., from an RA.
     * This method may only be called if prefix discovery on the given network has been stopped or
     * was never started. Any prefix set by this method will be cleared if startPrefix64Discovery or
     * stopPrefix64Discovery are called.
     *
     * Currently only /96 prefixes are supported. If an invalid, IPv4, or non-/96 prefix is passed
     * in, EINVAL is returned.
     * An empty string will clear the prefix if one was already set by this method.
     *
     * @param netId the netId on which to set the NAT64 prefix.
     * @param prefix the NAT64 prefix to use. Must be a valid IPv6 prefix or an empty string.
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         unix errno.
     */
    void setPrefix64(int netId, @utf8InCpp String prefix);

    /**
    * Register unsolicited event listener
    * DnsResolver supports multiple unsolicited event listeners.
    *
    * This is a non-public interface between DnsResolver and Connectivity/NetworkStack.
    * It is subject to change on Mainline updates without notice. DO NOT DEPEND ON IT.
    *
    * Only system services(Connectivity/NetworkStack) will register the unsolicited listener.
    * Besides, there is no unregister method since the system services will be always there to
    * listen unsolicited events.
    *
    * @param listener unsolicited event listener to register
    * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
    *         unix errno.
    */
    void registerUnsolicitedEventListener(IDnsResolverUnsolicitedEventListener listener);

    /**
     * Sets resolver options for the given network.
     *
     * @param netId the netId on which to set the options.
     * @param optionParams the option parameters to be wrapped into parcel.
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         unix errno.
     */
    void setResolverOptions(int netId, in ResolverOptionsParcel optionParams);

    /**
     * Set whether to allow the UID to explicitly bypass the private DNS rule on a given network.
     *
     * Throws ServiceSpecificException with error code EEXISTS when trying to add a bypass rule
     * that already exists, and ENOENT when trying to remove a bypass rule that does not exist or
     * when there is no known network with this netId.
     *
     * @param netId the netId where the UID is allowed or disallowed to bypass private DNS.
     * @param uid the UID.
     * @param allowed whether to allow or disallow the operation.
     * @throws ServiceSpecificException in case of failure, with an error code indicating the
     *         cause of the failure.
     */
    void setAllowBypassPrivateDnsOnNetwork(int netId, int uid, boolean allowed);

    /**
    *  Sets DNS forwarding from a downstream interface with the specified parameters. Repeated calls
    *  on the same interface will update its upstream configuration with new parameters. When a null
    *  upstream parameter is passed, the forwarding on the downstream interface is stopped.
    *
    *  @param downstreamIfIndex the interface index of the interface of the downstream network.
    *  @param upstreamParams the parameter of the upstream for sending DNS queries.
    *  @throws ServiceSpecificException in case of failure, with an error code corresponding to the
    *          unix errno or a specific value defined for each error variant.
    */
    void setDnsForwarding(
            int downstreamIfIndex, in @nullable DnsForwardingParamsParcel upstreamParams);
}
