001/*
002 * Copyright 2015-2020 the original author or authors
003 *
004 * This software is licensed under the Apache License, Version 2.0,
005 * the GNU Lesser General Public License version 2 or later ("LGPL")
006 * and the WTFPL.
007 * You may choose either license to govern your use of this software only
008 * upon the condition that you accept all of the terms of either
009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL.
010 */
011package org.minidns.record;
012
013import java.io.DataInputStream;
014import java.io.DataOutputStream;
015import java.io.IOException;
016
017import org.minidns.dnsname.DnsName;
018import org.minidns.record.Record.TYPE;
019
020/**
021 * SRV record payload (service pointer).
022 */
023public class SRV extends Data implements Comparable<SRV> {
024
025    /**
026     * The priority of this service. Lower values mean higher priority.
027     */
028    public final int priority;
029
030    /**
031     * The weight of this service. Services with the same priority should be
032     * balanced based on weight.
033     */
034    public final int weight;
035
036    /**
037     * The target port.
038     */
039    public final int port;
040
041    /**
042     * The target server.
043     */
044    public final DnsName target;
045
046    /**
047     * The target server.
048     *
049     * @deprecated use {@link #target} instead.
050     */
051    @Deprecated
052    public final DnsName name;
053
054    public static SRV parse(DataInputStream dis, byte[] data)
055        throws IOException {
056        int priority = dis.readUnsignedShort();
057        int weight = dis.readUnsignedShort();
058        int port = dis.readUnsignedShort();
059        DnsName name = DnsName.parse(dis, data);
060        return new SRV(priority, weight, port, name);
061    }
062
063    public SRV(int priority, int weight, int port, String name) {
064        this(priority, weight, port, DnsName.from(name));
065    }
066
067    public SRV(int priority, int weight, int port, DnsName name) {
068        this.priority = priority;
069        this.weight = weight;
070        this.port = port;
071        this.target = name;
072        this.name = target;
073    }
074
075    /**
076     * Check if the service is available at this domain. This checks f the target points to the root label. As per RFC
077     * 2782 the service is decidedly not available if there is only a single SRV answer pointing to the root label. From
078     * RFC 2782:
079     *
080     * <blockquote>A Target of "." means that the service is decidedly not available at this domain.</blockquote>
081     *
082     * @return true if the service is available at this domain.
083     */
084    public boolean isServiceAvailable() {
085        return !target.isRootLabel();
086    }
087
088    @Override
089    public void serialize(DataOutputStream dos) throws IOException {
090        dos.writeShort(priority);
091        dos.writeShort(weight);
092        dos.writeShort(port);
093        target.writeToStream(dos);
094    }
095
096    @Override
097    public String toString() {
098        return priority + " " + weight + " " + port + " " + target + ".";
099    }
100
101    @Override
102    public TYPE getType() {
103        return TYPE.SRV;
104    }
105
106    @Override
107    public int compareTo(SRV other) {
108        int res = other.priority - this.priority;
109        if (res == 0) {
110            res = this.weight - other.weight;
111        }
112        return res;
113    }
114}