package org.openautonomousconnection.insserver; import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager; import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer; import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord; import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType; import org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper.TargetName; import java.io.File; import java.io.IOException; import java.security.cert.CertificateException; import java.sql.*; import java.util.*; /** * Database-backed INS server. *
* This implementation resolves records from the SQL schema and performs CNAME recursion (with loop detection + depth limit). * Returned records are deterministically sorted so that callers can safely select index 0 as the "best" record. */ public final class DatabaseINSServer extends ProtocolINSServer { private final String jdbcUrl; private final String jdbcUser; private final String jdbcPassword; private final ConfigurationManager config; /** * Creates a new database-backed INS server. * * @throws IOException If the base server initialization fails. * @throws CertificateException If required certificate files are missing or invalid. */ public DatabaseINSServer() throws Exception { super(new File("config.properties")); config = new ConfigurationManager(new File("config.properties")); config.loadProperties(); if (!config.isSet("db.url")) { config.set( "db.url", "jdbc:mysql://localhost:3306/ins?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" ); config.saveProperties(); } if (!config.isSet("db.user")) { config.set("db.user", "username"); config.saveProperties(); } if (!config.isSet("db.password")) { config.set("db.password", "password"); config.saveProperties(); } if (!config.isSet("port")) { config.set("port", 1023); config.saveProperties(); } jdbcUrl = config.getString("db.url"); jdbcUser = config.getString("db.user"); jdbcPassword = config.getString("db.password"); Main.getSettings().port = config.getInt("port"); } private Connection openConnection() throws SQLException { return DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword); } /** * Resolves a request for an INS record based on TLN, name, subname and record type. *
* The implementation: *
* The value is read from {@code tln.info} and must be of the form {@code "host:port"}.
*
* @param tln The TLN name.
* @return The configured info target ("host:port") or {@code null} if not present.
*/
@Override
public String resolveTLNInfoSite(String tln) {
String sql = "SELECT info FROM tln WHERE name = ?";
try (Connection conn = openConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, tln);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) return rs.getString("info");
}
} catch (SQLException ex) {
getProtocolBridge().getLogger().exception("Failed to resolve TLN info site for tln=" + tln, ex);
}
return null;
}
private String formatName(String tln, String name, String sub) {
if (sub == null || sub.isEmpty()) return name + "." + tln;
return sub + "." + name + "." + tln;
}
/**
* Internal recursive resolver with CNAME handling.
*
* @param depth Current recursion depth.
* @param visited Loop detection set of canonical names (sub.name.tln).
*/
private List Rules:
*
*
*
* @param requestedType The type being requested (kept for future type-specific tuning).
* @return Comparator for {@link INSRecord}.
*/
private Comparator