From d419304845031c7598cfe6271d90e25d527938c8 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sat, 25 May 2019 16:45:32 +0300 Subject: [PATCH] - By default, obtain DNS server addresses dynamically from the system. --- app/src/main/assets/config | 3 +- app/src/main/cpp/baresip.c | 86 +++++++++++++++---- app/src/main/kotlin/com/tutpro/baresip/Api.kt | 2 + .../com/tutpro/baresip/BaresipService.kt | 45 +++++++++- .../main/kotlin/com/tutpro/baresip/Config.kt | 43 ++++++++-- .../com/tutpro/baresip/ConfigActivity.kt | 59 +++++++++++-- .../main/kotlin/com/tutpro/baresip/Utils.kt | 15 +++- app/src/main/res/layout/activity_config.xml | 1 - app/src/main/res/values-fi/strings.xml | 12 +-- app/src/main/res/values/strings.xml | 10 ++- 10 files changed, 223 insertions(+), 53 deletions(-) diff --git a/app/src/main/assets/config b/app/src/main/assets/config index 372ab0ec..998fde33 100644 --- a/app/src/main/assets/config +++ b/app/src/main/assets/config @@ -18,8 +18,7 @@ rtp_tos 184 rtcp_mux no jitter_buffer_delay 5-10 rtp_stats no -dns_server 8.8.8.8:53 -dns_server [2001:4860:4860::8888]:53 +dyn_dns yes prefer_ipv6 no module opus.so module g711.so diff --git a/app/src/main/cpp/baresip.c b/app/src/main/cpp/baresip.c index 4da751c8..93d162f4 100644 --- a/app/src/main/cpp/baresip.c +++ b/app/src/main/cpp/baresip.c @@ -19,7 +19,6 @@ if (log_level_get() <= LEVEL_ERROR) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__)) - typedef struct baresip_context { JavaVM *javaVM; jclass jniHelperClz; @@ -40,6 +39,26 @@ static int vprintf_null(const char *p, size_t size, void *arg) return 0; } +static net_debug_log() { + char debug_buf[2048]; + int l; + l = re_snprintf(&(debug_buf[0]), 2047, "%H", net_debug, baresip_network()); + if (l != -1) { + debug_buf[l] = '\0'; + LOGD("%s\n", debug_buf); + } +} + +static ua_print_sip_status_log() { + char debug_buf[2048]; + int l; + l = re_snprintf(&(debug_buf[0]), 2047, "%H", ua_print_sip_status); + if (l != -1) { + debug_buf[l] = '\0'; + LOGD("%s\n", debug_buf); + } +} + static struct re_printf pf_null = {vprintf_null, 0}; static void signal_handler(int sig) @@ -379,7 +398,7 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc conf_path_set(path); - // log_enable_debug(true); + log_enable_debug(true); err = conf_configure(); if (err) { @@ -450,18 +469,8 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc goto out; } - /* char debug_buf[2048]; - int l; - l = re_snprintf(&(debug_buf[0]), 2047, "%H", net_debug, baresip_network()); - if (l != -1) { - debug_buf[l] = '\0'; - LOGD("%s\n", debug_buf); - } - l = re_snprintf(&(debug_buf[0]), 2047, "%H", ua_print_sip_status); - if (l != -1) { - debug_buf[l] = '\0'; - LOGD("%s\n", debug_buf); - } */ + net_debug_log(); + ua_print_sip_status_log(); LOGI("running main loop ...\n"); err = re_main(signal_handler); @@ -1053,7 +1062,6 @@ Java_com_tutpro_baresip_Api_ua_1hangup(JNIEnv *env, jobject thiz, (*env)->ReleaseStringUTFChars(env, javaUA, native_ua); (*env)->ReleaseStringUTFChars(env, javaCall, native_call); (*env)->ReleaseStringUTFChars(env, reason, native_reason); - return; } JNIEXPORT jstring JNICALL @@ -1121,7 +1129,6 @@ Java_com_tutpro_baresip_Api_ua_1answer(JNIEnv *env, jobject thiz, jstring javaUA re_thread_leave(); (*env)->ReleaseStringUTFChars(env, javaUA, native_ua); (*env)->ReleaseStringUTFChars(env, javaCall, native_call); - return; } JNIEXPORT jint JNICALL @@ -1155,7 +1162,6 @@ Java_com_tutpro_baresip_Api_call_1notify_1sipfrag(JNIEnv *env, jobject thiz, jst re_thread_leave(); (*env)->ReleaseStringUTFChars(env, javaCall, native_call); (*env)->ReleaseStringUTFChars(env, reason, native_reason); - return; } JNIEXPORT void JNICALL @@ -1168,7 +1174,6 @@ Java_com_tutpro_baresip_Api_call_1start_1audio(JNIEnv *env, jobject thiz, jstrin if (!audio_started(a)) audio_start(a); re_thread_leave(); (*env)->ReleaseStringUTFChars(env, javaCall, native_call); - return; } JNIEXPORT void JNICALL @@ -1181,7 +1186,6 @@ Java_com_tutpro_baresip_Api_call_1stop_1audio(JNIEnv *env, jobject thiz, jstring if (audio_started(a)) audio_stop(a); re_thread_leave(); (*env)->ReleaseStringUTFChars(env, javaCall, native_call); - return; } JNIEXPORT jint JNICALL @@ -1334,6 +1338,7 @@ Java_com_tutpro_baresip_Api_contact_1add(JNIEnv *env, jobject thiz, jstring java } else { LOGD("added contact %s\n", native_contact); } + (*env)->ReleaseStringUTFChars(env, javaContact, native_contact); } JNIEXPORT void JNICALL @@ -1353,3 +1358,46 @@ Java_com_tutpro_baresip_Api_log_1level_1set(JNIEnv *env, jobject thiz, jint leve log_level_set(native_level); } +JNIEXPORT jint JNICALL +Java_com_tutpro_baresip_Api_dnsc_1srv_1set(JNIEnv *env, jobject thiz, jstring javaServers) { + const char *native_servers = (*env)->GetStringUTFChars(env, javaServers, 0); + char servers[256]; + char *server; + struct sa nsv[NET_MAX_NS]; + uint32_t count = 0; + char *comma; + int err; + LOGD("setting dns servers '%s'\n", native_servers); + if (str_len(native_servers) > 255) { + LOGW("dnsc_srv_set: too long servers list (%s)\n", native_servers); + return 1; + } + str_ncpy(servers, native_servers, 256); + (*env)->ReleaseStringUTFChars(env, javaServers, native_servers); + server = &(servers[0]); + while((count < NET_MAX_NS) && ((comma = strchr(server, ',')) != NULL)) { + *comma = '\0'; + err = sa_decode(&(nsv[count]), server, str_len(server)); + if (err) { + LOGW("dnsc_srv_set: could not decode '%s' (%u)\n", server, err); + return err; + } + server = ++comma; + count++; + } + if ((count < NET_MAX_NS) && (str_len(server) > 0)) { + err = sa_decode(&(nsv[count]), server, str_len(server)); + if (err) { + LOGW("dnsc_srv_set: could not decode `%s' (%u)\n", server, err); + return err; + } + count++; + } + (void)dnsc_srv_set(net_dnsc(baresip_network()), nsv, count); + return 0; +} + +JNIEXPORT void JNICALL +Java_com_tutpro_baresip_Api_net_1debug(JNIEnv *env, jobject thiz) { + net_debug_log(); +} diff --git a/app/src/main/kotlin/com/tutpro/baresip/Api.kt b/app/src/main/kotlin/com/tutpro/baresip/Api.kt index 540b5df2..c5351c6c 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Api.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Api.kt @@ -31,5 +31,7 @@ object Api { external fun contact_add(contact: String) external fun contacts_remove() external fun log_level_set(level: Int) + external fun dnsc_srv_set(servers: String): Int + external fun net_debug() } diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index a8dd8834..0fac813f 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -6,6 +6,7 @@ import android.app.Notification.VISIBILITY_PUBLIC import android.content.* import android.media.* import android.net.ConnectivityManager +import android.net.LinkProperties import android.net.wifi.WifiManager import android.os.IBinder import android.os.PowerManager @@ -22,6 +23,7 @@ import android.net.NetworkRequest import android.provider.Settings import java.io.File +import java.net.InetAddress import java.nio.charset.StandardCharsets import java.util.* import kotlin.math.roundToInt @@ -35,6 +37,7 @@ class BaresipService: Service() { internal lateinit var rt: Ringtone internal lateinit var nm: NotificationManager internal lateinit var snb: NotificationCompat.Builder + internal lateinit var cm: ConnectivityManager internal lateinit var wakeLock: PowerManager.WakeLock internal lateinit var fl: WifiManager.WifiLock @@ -61,9 +64,9 @@ class BaresipService: Service() { createNotificationChannels() snb = NotificationCompat.Builder(this, DEFAULT_CHANNEL_ID) - val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val builder = NetworkRequest.Builder() - connectivityManager.registerNetworkCallback( + cm.registerNetworkCallback( builder.build(), object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { @@ -73,12 +76,26 @@ class BaresipService: Service() { UserAgent.register() disconnected = false } + if (dynDns) { + val dnsServers = cm.getLinkProperties(network).getDnsServers() + if (Config.updateDnsServers(dnsServers) != 0) + Log.w(LOG_TAG, "Failed to update DNS servers '$dnsServers") + } } override fun onLost(network: Network) { super.onLost(network) Log.d(LOG_TAG, "Network $network is lost") disconnected = true } + override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) { + super.onLinkPropertiesChanged(network, linkProperties) + Log.d(LOG_TAG, "Network $network link properties changed") + if (dynDns) { + val dnsServers = linkProperties.getDnsServers() + if (Config.updateDnsServers(dnsServers) != 0) + Log.w(LOG_TAG, "Failed to update DNS servers '$dnsServers") + } + } } ) @@ -128,13 +145,31 @@ class BaresipService: Service() { Utils.copyAssetToFile(applicationContext, a, "$filesPath/$a") } else { Log.d(LOG_TAG, "Asset $a already copied") - if (a == "config") Config.initialize() + if (a == "config") { + var dnsServers = listOf() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val activeNetwork = cm.activeNetwork + if (activeNetwork != null) { + dnsServers = cm.getLinkProperties(activeNetwork).dnsServers + Log.d(LOG_TAG, "DNS Servers = $dnsServers") + } else { + Log.d(LOG_TAG, "No active network!") + } + } + Config.initialize(dnsServers) + } } } + ContactsActivity.restoreContacts(applicationContext.filesDir) + Thread(Runnable { baresipStart(filesPath) }).start() isServiceRunning = true showStatusNotification() + + if (Config.variable("dyn_dns")[0] == "yes") + Config.remove("dns_server") + } "Call Show", "Call Answer" -> { @@ -397,8 +432,9 @@ class BaresipService: Service() { am.setStreamVolume(am.mode, (callVolume * 0.1 * am.getStreamMaxVolume(am.mode)).roundToInt(), 0) + Log.d(LOG_TAG, "Original/new call volume of stream ${am.mode} is " + + "$origCallVolume/${am.getStreamVolume(am.mode)}") } - Log.d(LOG_TAG, "Call volume of stream ${am.mode} is ${am.getStreamVolume(am.mode)}") } "call verified", "call secure" -> { val call = Call.find(callp) @@ -765,6 +801,7 @@ class BaresipService: Service() { var isServiceClean = false var speakerPhone = false var callVolume = 0 + var dynDns = false var filesPath = "" var uas = ArrayList() diff --git a/app/src/main/kotlin/com/tutpro/baresip/Config.kt b/app/src/main/kotlin/com/tutpro/baresip/Config.kt index 858c009b..fe88f1e0 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Config.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Config.kt @@ -2,6 +2,7 @@ package com.tutpro.baresip import android.content.Context import java.io.File +import java.net.InetAddress object Config { @@ -9,7 +10,7 @@ object Config { private val file = File(path) private var config = Utils.getFileContents(file) - fun initialize() { + fun initialize(dnsServers: List) { var write = false if (!config.contains("zrtp_hash")) { config = "${config}zrtp_hash yes\n" @@ -52,6 +53,17 @@ object Config { } else { BaresipService.callVolume = variable("call_volume")[0].toInt() } + if (!config.contains("dyn_dns")) { + config = "${config}dyn_dns no\n" + write = true + } else { + if (config.contains(Regex("dyn_dns[ ]+yes"))) { + for (dnsServer in dnsServers) + config = "${config}dns_server ${dnsServer.hostAddress}:53\n" + BaresipService.dynDns = true + write = true + } + } if (write) { Log.e("Baresip", "Writing '$config'") Utils.putFileContents(file, config) @@ -59,8 +71,8 @@ object Config { } fun variable(name: String): ArrayList { - val lines = config.split("\n") val result = ArrayList() + val lines = config.split("\n") for (line in lines) { if (line.startsWith(name)) result.add((line.substring(name.length).trim()).split("# \t")[0]) @@ -69,7 +81,7 @@ object Config { } fun add(variable: String, value: String) { - config += "\n$variable $value\n" + config += "$variable $value\n" } fun remove(variable: String) { @@ -87,8 +99,29 @@ object Config { } fun save() { + var result = "" + for (line in config.split("\n")) + if (line.length > 0) + result = result + line + '\n' + config = result Utils.putFileContents(file, config) - Log.d("Baresip", "New config '$config'") + Log.d("Baresip", "New config '$result'") // Api.reload_config() } -} \ No newline at end of file + + fun updateDnsServers(dnsServers: List): Int { + var servers = "" + for (dnsServer in dnsServers) { + var address = dnsServer.hostAddress + if (Utils.checkIpV4(address)) + address = "${address}:53" + else + address = "[${address}]:53" + if (servers == "") + servers = address + else + servers = "${servers},${address}" + } + return Api.dnsc_srv_set(servers) + } +} diff --git a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt index 980950da..8ef22636 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt @@ -1,7 +1,10 @@ package com.tutpro.baresip import android.app.Activity +import android.content.Context import android.content.Intent +import android.net.ConnectivityManager +import android.os.Build import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.Menu @@ -52,10 +55,15 @@ class ConfigActivity : AppCompatActivity() { preferIPv6.isChecked = oldPreferIPv6 == "yes" dnsServers = findViewById(R.id.DnsServers) as EditText - val dsCv = Config.variable("dns_server") - var dsTv = "" - for (ds in dsCv) dsTv += ", $ds" - oldDnsServers = dsTv.trimStart(',').trimStart(' ') + val ddCv = Config.variable("dyn_dns") + if (ddCv[0] == "yes") { + oldDnsServers = "" + } else { + val dsCv = Config.variable("dns_server") + var dsTv = "" + for (ds in dsCv) dsTv += ", $ds" + oldDnsServers = dsTv.trimStart(',').trimStart(' ') + } dnsServers.setText(oldDnsServers) opusBitRate = findViewById(R.id.OpusBitRate) as EditText @@ -144,17 +152,35 @@ class ConfigActivity : AppCompatActivity() { restart = true } - val dnsServers = dnsServers.text.toString().trim().toLowerCase() + val dnsServers = addMissingPorts(dnsServers.text.toString().trim().toLowerCase()) if (dnsServers != oldDnsServers) { if (!checkDnsServers(dnsServers)) { - Utils.alertView(this, "Notice", "Invalid DNS Servers: $dnsServers") + Utils.alertView(this, "Notice", + "Invalid DNS Servers: $dnsServers") return false } + Config.remove("dyn_dns") Config.remove("dns_server") - for (server in dnsServers.split(",")) - Config.add("dns_server", server) + if (dnsServers.isNotEmpty()) { + for (server in dnsServers.split(",")) + Config.add("dns_server", server) + Config.add("dyn_dns", "no") + if (Api.dnsc_srv_set(dnsServers) != 0) { + Utils.alertView(this, "Notice", + "Failed to set DNS servers '$dnsServers'") + return false + } + } else { + Config.add("dyn_dns", "yes") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + Config.updateDnsServers(cm.getLinkProperties(cm.activeNetwork).getDnsServers()) + } else { + restart = true + } + } + Api.net_debug() save = true - restart = true } val opusBitRate = opusBitRate.text.toString().trim() @@ -267,5 +293,20 @@ class ConfigActivity : AppCompatActivity() { return (number >=6000) && (number <= 510000) } + private fun addMissingPorts(addressList: String): String { + if (addressList == "") return "" + var result = "" + for (addr in addressList.split(",")) + if (Utils.checkIpPort(addr)) { + result = "$result,$addr" + } else { + if (Utils.checkIpV4(addr)) + result = "$result,$addr:53" + else + result = "$result,[$addr]:53" + } + return result.substring(1) + } + } diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index 8a775f66..78a8e18b 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -87,7 +87,7 @@ object Utils { fun removeLinesStartingWithName(string: String, name: String): String { var result = "" for (line in string.split("\n")) - if (!line.startsWith(name)) result += line + "\n" + if (!line.startsWith(name) && (line.length > 0)) result += line + "\n" return result } @@ -171,6 +171,11 @@ object Utils { return Regex("^(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})$").matches(ip) } + fun checkIpv6InBrackets(bracketedIp: String): Boolean { + return bracketedIp.startsWith("[") && bracketedIp.endsWith("]") && + checkIpV6(bracketedIp.substring(1, bracketedIp.length - 2)) + } + fun checkIp(ip: String): Boolean { return checkIpV4(ip) || checkIpV6(ip) } @@ -214,8 +219,12 @@ object Utils { } fun checkIpPort(ipPort: String): Boolean { - return checkIp(ipPort.substringBeforeLast(":")) && - checkPort(ipPort.substringAfterLast(":")) + if (ipPort.startsWith("[")) + return checkIpv6InBrackets(ipPort.substringBeforeLast(":")) && + checkPort(ipPort.substringAfterLast(":")) + else + return checkIpV4(ipPort.substringBeforeLast(":")) && + checkPort(ipPort.substringAfterLast(":")) } fun checkParams(params: String): Boolean { diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml index 0ea59c2c..3145899d 100644 --- a/app/src/main/res/layout/activity_config.xml +++ b/app/src/main/res/layout/activity_config.xml @@ -109,7 +109,6 @@ android:layout_marginBottom="12dp" android:textSize="18sp" android:inputType="textUri" - android:hint="@string/_8_8_8_8_53" android:importantForAutofill="no" > diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 22c8f57d..00af9e98 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -186,12 +186,12 @@ Jos merkitty, baresip suosii IPv6-protokollaa, mikäli sekä IPv4 että IPv6 ovat käytettävissä. DNS-palvelimet - Pilkulla toisistaan erotettu - luettelo DNS-palvelijoita. Kukin DNS-palvelija on muotoa - \'palvelin:portti\'. Jos palvelin on IPv6-osoite, osoite pitää - kirjoittaa sulkujen [] sisään. Oletusarvo on - \'8.8.8.8:53,[2001:4860:4860::8888]:53\', mikä osoittaa Googlen - julkisiin DNS-palvelijoihin. + Pilkulla toisistaan erotettu luettelo DNS-palvelijoiden + osoitteita. Jos jätetään antamatta (oletus), osoitteet hankitaan dynaamisesti järjestelmästä. + Kukin osoite on muotoa \'ip:portti\' tai \'ip\', missä ip on IPv4 tai IPv6 osoite. Jos ip + on IPv6-osoite ja myös portti annetaan, pitää osoite kirjoittaa sulkujen [] sisään. + Esimerkiksi luettelo \'8.8.8.8:53,[2001:4860:4860::8888]:53\' osoittaa Googlen julkisiin + DNS-palvelijoihin. Opus-koodekin bittinopeus Opus-koodekin käyttämä keskimääräinen enimmäisnopeus. Mahdollisia arvoja ovat diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f74e5a98..e4d22728 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -151,10 +151,12 @@ Prefer IPv6 Prefer IPv6 if both IPv4 and IPv6 are available. DNS Servers - Comma separated list of DNS servers. Each DNS server is of form - \'server:port\'. If server is an IPv6 address, the address must be written inside brackets []. - Factory default value is \'8.8.8.8:53,[2001:4860:4860::8888]:53\' pointing to public Google - DNS servers. + Comma separated list of addresses of DNS servers. If not given, + DNS server addresses are obtained dynamically from the system. Each DNS address is of form + \'ip:port\' or \'ip\'. If port is omitted, it defaults to 53. If ip is an IPv6 address and + also port is given, ip must + be written inside brackets []. As an example, list \'8.8.8.8:53,[2001:4860:4860::8888]:53\' + points to IPv4 and IPv6 addresses of public Google DNS servers. 8.8.8.8:53 Opus Bit Rate Average maximum bit rate used by Opus audio stream.