Use all available network addresses and name servers

This commit is contained in:
Juha Heinanen
2021-09-19 16:30:18 +03:00
parent 72ccb8a3b1
commit 9990ddca06
5 changed files with 183 additions and 159 deletions
+70 -8
View File
@@ -437,21 +437,22 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1set_1address(JNIEnv *env, jobject thiz, jstring javaIp); Java_com_tutpro_baresip_Api_net_1add_1address(JNIEnv *env, jobject thiz, jstring javaIp);
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1use_1nameserver(JNIEnv *env, jobject thiz, jstring javaServers); Java_com_tutpro_baresip_Api_net_1use_1nameserver(JNIEnv *env, jobject thiz, jstring javaServers);
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instance, Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instance,
jstring jPath, jstring jIpV4Addr, jstring jIpV6Addr, jstring jNetInterface, jstring jPath, jstring jIpAddrs, jstring jNetInterface, jint jNetAf, jint jLogLevel) {
jstring jDnsServers, jint jNetAf, jint javaLogLevel) {
LOGD("starting baresip\n"); LOGI("starting baresip\n");
const char *net_interface = (*env)->GetStringUTFChars(env, jNetInterface, 0); const char *net_interface = (*env)->GetStringUTFChars(env, jNetInterface, 0);
const int net_af = jNetAf; const int net_af = jNetAf;
const char *ip_addrs = (*env)->GetStringUTFChars(env, jIpAddrs, 0);
char start_error[64] = ""; char start_error[64] = "";
JavaVM *javaVM = g_ctx.javaVM; JavaVM *javaVM = g_ctx.javaVM;
@@ -477,7 +478,7 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
conf_path_set(path); conf_path_set(path);
log_level_set((enum log_level)javaLogLevel); log_level_set((enum log_level)jLogLevel);
err = conf_configure(); err = conf_configure();
if (err) { if (err) {
@@ -502,9 +503,26 @@ Java_com_tutpro_baresip_BaresipService_baresipStart(JNIEnv *env, jobject instanc
goto out; goto out;
} }
Java_com_tutpro_baresip_Api_net_1set_1address(env, instance, jIpV4Addr); if (strlen(ip_addrs) > 0) {
Java_com_tutpro_baresip_Api_net_1set_1address(env, instance, jIpV6Addr); char* addr_list = (char*)malloc(strlen(ip_addrs));
Java_com_tutpro_baresip_Api_net_1use_1nameserver(env, instance, jDnsServers); struct sa temp_sa;
char buf[256];
net_flush_addresses(baresip_network());
strcpy(addr_list, ip_addrs);
char *ptr = strtok(addr_list, ";");
while (ptr != NULL) {
LOGI("adding address '%s'", ptr);
if (0 == sa_set_str(&temp_sa, ptr, 0)) {
sa_ntop(&temp_sa, buf, 256);
net_add_address(baresip_network(), &temp_sa);
} else {
LOGE("invalid ip address %s\n", ptr);
res = EAFNOSUPPORT;
}
ptr = strtok(NULL, ";");
}
free(addr_list);
}
net_debug_log(); net_debug_log();
@@ -1677,6 +1695,50 @@ Java_com_tutpro_baresip_Api_net_1set_1address(JNIEnv *env, jobject thiz, jstring
return res; return res;
} }
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1add_1address(JNIEnv *env, jobject thiz, jstring javaIp) {
const char *native_ip = (*env)->GetStringUTFChars(env, javaIp, 0);
int res = 0;
struct sa temp_sa;
char buf[256];
LOGI("adding address '%s'\n", native_ip);
if (str_len(native_ip) == 0) {
(*env)->ReleaseStringUTFChars(env, javaIp, native_ip);
return 0;
}
if (0 == sa_set_str(&temp_sa, native_ip, 0)) {
sa_ntop(&temp_sa, buf, 256);
net_add_address(baresip_network(), &temp_sa);
} else {
LOGE("invalid ip address %s\n", native_ip);
res = EAFNOSUPPORT;
}
(*env)->ReleaseStringUTFChars(env, javaIp, native_ip);
return res;
}
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_Api_net_1rm_1address(JNIEnv *env, jobject thiz, jstring jIp) {
const char *native_ip = (*env)->GetStringUTFChars(env, jIp, 0);
int res = 0;
struct sa temp_sa;
char buf[256];
LOGD("removing address '%s'\n", native_ip);
if (str_len(native_ip) == 0) {
(*env)->ReleaseStringUTFChars(env, jIp, native_ip);
return 0;
}
if (0 == sa_set_str(&temp_sa, native_ip, 0)) {
sa_ntop(&temp_sa, buf, 256);
net_rm_address(baresip_network(), &temp_sa);
} else {
LOGE("invalid ip address %s\n", native_ip);
res = EAFNOSUPPORT;
}
(*env)->ReleaseStringUTFChars(env, jIp, native_ip);
return res;
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_tutpro_baresip_Api_net_1unset_1address(JNIEnv *env, jobject thiz, jint javaAf) { Java_com_tutpro_baresip_Api_net_1unset_1address(JNIEnv *env, jobject thiz, jint javaAf) {
struct sa temp_sa; struct sa temp_sa;
@@ -3,7 +3,7 @@ package com.tutpro.baresip
object Api { object Api {
const val AF_UNSPEC = 0 const val AF_UNSPEC = 0
const val AF_INET = 2 // const val AF_INET = 2
const val AF_INET6 = 10 const val AF_INET6 = 10
const val VIDMODE_OFF = 0 const val VIDMODE_OFF = 0
// const val VIDMODE_ON = 1 // const val VIDMODE_ON = 1
@@ -76,6 +76,8 @@ object Api {
external fun net_use_nameserver(servers: String): Int external fun net_use_nameserver(servers: String): Int
external fun net_set_address(ip_addr: String): Int external fun net_set_address(ip_addr: String): Int
external fun net_add_address(ip_addr: String): Int
external fun net_rm_address(ip_addr: String): Int
external fun net_unset_address(af: Int) external fun net_unset_address(af: Int)
external fun net_debug() external fun net_debug()
external fun net_dns_debug() external fun net_dns_debug()
@@ -29,6 +29,7 @@ import java.io.File
import java.net.InetAddress import java.net.InetAddress
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
import kotlin.math.roundToInt import kotlin.math.roundToInt
@@ -55,7 +56,7 @@ class BaresipService: Service() {
private var origVolume = -1 private var origVolume = -1
private val btAdapter = BluetoothAdapter.getDefaultAdapter() private val btAdapter = BluetoothAdapter.getDefaultAdapter()
private var activeNetwork: Network? = null private var activeNetwork: Network? = null
private var linkAddresses = listOf<LinkAddress>() private var linkAddresses = mutableListOf<LinkAddress>()
@SuppressLint("WakelockTimeout") @SuppressLint("WakelockTimeout")
override fun onCreate() { override fun onCreate() {
@@ -119,15 +120,9 @@ class BaresipService: Service() {
updateNetwork() updateNetwork()
} }
override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) {
super.onCapabilitiesChanged(network, caps)
Log.i(TAG, "Network $network capabilities changed: $caps")
}
} }
) )
wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
@@ -234,6 +229,25 @@ class BaresipService: Service() {
when (action) { when (action) {
"Start" -> { "Start" -> {
var ipAddrs = ""
for (n in cm.allNetworks) {
val props = cm.getLinkProperties(n)
if (props != null) {
for (a in props.linkAddresses)
linkAddresses.add(a)
val addrs = Utils.hostAddresses(props.linkAddresses)
if (addrs != "") {
if (ipAddrs == "")
ipAddrs = addrs
else
ipAddrs += ";$addrs"
}
}
}
updateDnsServers()
val assets = arrayOf("accounts", "config", "contacts", "busy.wav", "callwaiting.wav", val assets = arrayOf("accounts", "config", "contacts", "busy.wav", "callwaiting.wav",
"error.wav", "ringback.wav") "error.wav", "ringback.wav")
var file = File(filesPath) var file = File(filesPath)
@@ -264,15 +278,12 @@ class BaresipService: Service() {
CallHistory.restore() CallHistory.restore()
Message.restore() Message.restore()
val ipV4Addr = Utils.findIpV4Address(linkAddresses) if (ipAddrs == "")
val ipV6Addr = Utils.findIpV6Address(linkAddresses)
val dnsServers = Utils.findDnsServers(BaresipService.dnsServers)
if ((ipV4Addr == "") && (ipV6Addr == ""))
Log.w(TAG, "Starting baresip without IP addresses") Log.w(TAG, "Starting baresip without IP addresses")
Thread { Thread {
baresipStart( baresipStart(
filesPath, ipV4Addr, ipV6Addr, "", dnsServers, Api.AF_UNSPEC, logLevel filesPath, ipAddrs, "", Api.AF_UNSPEC, logLevel
) )
}.start() }.start()
@@ -425,35 +436,11 @@ class BaresipService: Service() {
"registering failed" -> { "registering failed" -> {
status[account_index] = R.drawable.dot_red status[account_index] = R.drawable.dot_red
updateStatusNotification() updateStatusNotification()
if ((ev.size > 1) && (ev[1] == "Invalid argument")) { if (ev.size > 1 && ev[1] == "Invalid argument")
// Most likely this error is due to DNS lookup failure // Likely due to DNS lookup failure
newEvent = "registering failed,DNS lookup failed" newEvent = "registering failed,DNS lookup failed"
Api.net_dns_debug()
if (dynDns)
if (VERSION.SDK_INT >= 23) {
val activeNetwork = cm.activeNetwork
if (activeNetwork != null) {
val props = cm.getLinkProperties(activeNetwork)
if (props != null) {
val dnsServers = props.dnsServers
Log.d(TAG, "Updating DNS Servers = $dnsServers")
if (Config.updateDnsServers(dnsServers) != 0) {
Log.w(TAG, "Failed to update DNS servers '$dnsServers'")
} else {
Api.net_dns_debug()
if (!ua.registrationFailed) { if (!ua.registrationFailed) {
ua.registrationFailed = true ua.registrationFailed = true
Api.ua_register(uap)
}
}
}
} else {
Log.d(TAG, "No active network!")
}
}
}
if ((ev.size > 1) && (ev[1] == "Software caused connection abort")) {
// Perhaps due to VPN connect/disconnect
updateNetwork() updateNetwork()
} }
if (!Utils.isVisible()) if (!Utils.isVisible())
@@ -1102,94 +1089,92 @@ class BaresipService: Service() {
} }
private fun updateNetwork() { private fun updateNetwork() {
/* for (n in cm.allNetworks)
var selectedNetwork: Network? = null Log.i(TAG, "NETWORK $n with caps ${cm.getNetworkCapabilities(n)} and props " +
var caps: NetworkCapabilities? = null "${cm.getLinkProperties(n)} is active ${isNetworkActive(n)}") */
var props: LinkProperties? = null activeNetwork = activeNetwork()
if (activeNetwork != null) {
// Use VPN network if available val linkCaps = cm.getNetworkCapabilities(activeNetwork)
val linkProps = cm.getLinkProperties(activeNetwork)
Log.d(TAG, "Using active network $activeNetwork with caps: $linkCaps, props: $linkProps")
val lnAddrs = mutableListOf<LinkAddress>()
for (n in cm.allNetworks) { for (n in cm.allNetworks) {
caps = cm.getNetworkCapabilities(n) ?: continue val props = cm.getLinkProperties(n)
if (isNetworkActive(n) && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { if (props != null)
props = cm.getLinkProperties(n) ?: continue for (a in props.linkAddresses)
Log.i(TAG, "Active VPN network $n is available with caps: $caps, props: $props") lnAddrs.add(a)
selectedNetwork = n
break
} }
var addrUpdate = false
for (a in lnAddrs)
if (!linkAddresses.contains(a)) {
Api.net_add_address(a.address.hostAddress)
addrUpdate = true
} }
for (a in linkAddresses)
// Otherwise, use currently active default data network if (!lnAddrs.contains(a)) {
for (n in cm.allNetworks) { Api.net_rm_address(a.address.hostAddress)
if (isNetworkActive(n)) { addrUpdate = true
caps = cm.getNetworkCapabilities(n) ?: continue
props = cm.getLinkProperties(n) ?: continue
Log.i(TAG, "Active network $n is available with caps: $caps, props: $props")
selectedNetwork = n
break
} }
} val dnsUpdate = updateDnsServers()
if (addrUpdate) {
if (selectedNetwork != null) { linkAddresses = lnAddrs
activeNetwork = selectedNetwork Api.uag_reset_transp(register = true, reinvite = true)
if (isServiceRunning) {
updateLinkProperties(props!!)
} else { } else {
dnsServers = props!!.dnsServers if (dnsUpdate)
linkAddresses = props.linkAddresses UserAgent.register()
} }
if (caps!!.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { if (linkCaps != null && linkCaps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "Acquiring WiFi Lock") Log.d(TAG, "Acquiring WiFi Lock")
wifiLock.acquire() wifiLock.acquire()
} else { } else {
Log.d(TAG, "Releasing WiFi Lock") Log.d(TAG, "Releasing WiFi Lock")
wifiLock.release() wifiLock.release()
} }
} } else
Log.w(TAG, "No active network")
} }
private fun updateLinkProperties(props: LinkProperties) { private fun updateDnsServers(): Boolean {
if (dynDns && (dnsServers != props.dnsServers)) { if (isServiceRunning && !dynDns)
if (isServiceRunning) return false
if (Config.updateDnsServers(props.dnsServers) != 0) val servers = mutableListOf<InetAddress>()
Log.w(TAG, "Failed to update DNS servers '${props.dnsServers}'") // Use DNS servers first from active network (if given)
else for (n in cm.allNetworks)
dnsServers = props.dnsServers if (isNetworkActive(n)) {
else val linkProps = cm.getLinkProperties(n)
dnsServers = props.dnsServers if (linkProps != null) {
servers.addAll(linkProps.dnsServers)
break
} }
updateLinkAddresses(props.linkAddresses) }
// Then add DNS servers from the other networks
for (n in cm.allNetworks) {
if (isNetworkActive(n)) continue
val linkProps = cm.getLinkProperties(n)
if (linkProps != null)
for (server in linkProps.dnsServers)
if (!servers.contains(server)) servers.add(server)
}
// Update if change
if (servers != dnsServers) {
if (isServiceRunning && Config.updateDnsServers(servers) != 0) {
Log.w(TAG, "Failed to update DNS servers '${servers}'")
} else {
// Log.d(TAG, "Updated DNS servers: '${servers}'")
dnsServers = servers
return true
}
}
return false
} }
private fun updateLinkAddresses(linkAddrs: List<LinkAddress>) { private fun activeNetwork(): Network? {
var updated = false return if (VERSION.SDK_INT >= 23)
val ipV6Addr = Utils.findIpV6Address(linkAddrs) cm.activeNetwork
if (ipV6Addr != Utils.findIpV6Address(linkAddresses)) { else {
Log.d(TAG, "Updating IPv6 address to '$ipV6Addr'") for (n in cm.allNetworks)
if (ipV6Addr != "") { if (isNetworkActive(n)) return n
if (Api.net_set_address(ipV6Addr) != 0) return null
Log.w(TAG, "Failed to update net address '$ipV6Addr")
} else {
Api.net_unset_address(Api.AF_INET6)
}
updated = true
}
val ipV4Addr = Utils.findIpV4Address(linkAddrs)
if (ipV4Addr != Utils.findIpV4Address(linkAddresses)) {
Log.d(TAG, "Updating IPv4 address to '$ipV4Addr'")
if (ipV4Addr != "") {
if (Api.net_set_address(ipV4Addr) != 0)
Log.w(TAG, "Failed to update net address '$ipV4Addr'")
} else {
Api.net_unset_address(Api.AF_INET)
}
updated = true
}
if (updated) {
linkAddresses = linkAddrs
Api.uag_reset_transp(register = true, reinvite = true)
Api.net_debug()
} else {
UserAgent.register()
} }
} }
@@ -1220,9 +1205,8 @@ class BaresipService: Service() {
isServiceClean = true isServiceClean = true
} }
private external fun baresipStart(path: String, ipV4Addr: String, ipV6Addr: String, private external fun baresipStart(path: String, ipAddrs: String, netInterface: String,
netInterface: String, dnsServers: String, netAf: Int, netAf: Int, logLevel: Int)
logLevel: Int)
private external fun baresipStop(force: Boolean) private external fun baresipStop(force: Boolean)
companion object { companion object {
@@ -147,7 +147,6 @@ object Config {
} }
fun updateDnsServers(dnsServers: List<InetAddress>): Int { fun updateDnsServers(dnsServers: List<InetAddress>): Int {
Log.i(TAG, "Updating dnsServers with $dnsServers")
var servers = "" var servers = ""
for (dnsServer in dnsServers) { for (dnsServer in dnsServers) {
var address = dnsServer.hostAddress.removePrefix("/") var address = dnsServer.hostAddress.removePrefix("/")
@@ -9,8 +9,7 @@ import android.content.res.Configuration
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Bitmap.createScaledBitmap import android.graphics.Bitmap.createScaledBitmap
import android.graphics.Color import android.graphics.Color
import android.net.LinkAddress import android.net.*
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.DocumentsContract import android.provider.DocumentsContract
@@ -27,7 +26,6 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import java.io.* import java.io.*
import java.net.InetAddress
import java.security.SecureRandom import java.security.SecureRandom
import java.util.* import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
@@ -279,36 +277,15 @@ object Utils {
return true return true
} }
fun findIpV6Address(list: List<LinkAddress>): String { fun hostAddresses(list: List<LinkAddress>?): String {
for (la in list) var result = ""
if (list != null) for (la in list)
if (la.scope == android.system.OsConstants.RT_SCOPE_UNIVERSE) if (la.scope == android.system.OsConstants.RT_SCOPE_UNIVERSE)
if (checkIpV6(la.address.hostAddress)) if (result == "")
return la.address.hostAddress result = la.address.hostAddress
return ""
}
fun findIpV4Address(list: List<LinkAddress>): String {
for (la in list)
if (la.scope == android.system.OsConstants.RT_SCOPE_UNIVERSE)
if (checkIpV4(la.address.hostAddress))
return la.address.hostAddress
return ""
}
fun findDnsServers(list: List<InetAddress>): String {
var servers = ""
for (dnsServer in list) {
var address = dnsServer.hostAddress.removePrefix("/")
address = if (checkIpV4(address))
"${address}:53"
else else
"[${address}]:53" result += ";" + la.address.hostAddress
servers = if (servers == "") return result
address
else
"${servers},${address}"
}
return servers
} }
fun implode(list: List<String>, sep: String): String { fun implode(list: List<String>, sep: String): String {