Added TURN media NAT option and possibility to give username/password

for STUN/TURN server.
This commit is contained in:
Juha Heinanen
2020-06-17 18:49:49 +03:00
parent 0ad0e3af8c
commit e7af96f321
7 changed files with 212 additions and 31 deletions

View File

@ -994,6 +994,64 @@ Java_com_tutpro_baresip_AccountKt_account_1set_1stun_1port(JNIEnv *env, jobject
return res;
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_AccountKt_account_1stun_1user(JNIEnv *env, jobject thiz, jstring jAcc)
{
const char *native_acc = (*env)->GetStringUTFChars(env, jAcc, 0);
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
(*env)->ReleaseStringUTFChars(env, jAcc, native_acc);
if (acc) {
const char *stun_user = account_stun_user(acc);
if (stun_user) return (*env)->NewStringUTF(env, stun_user);
}
return (*env)->NewStringUTF(env, "");
}
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_AccountKt_account_1set_1stun_1user(JNIEnv *env, jobject thiz,
jstring jAcc, jstring jUser) {
const char *native_acc = (*env)->GetStringUTFChars(env, jAcc, 0);
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
(*env)->ReleaseStringUTFChars(env, jAcc, native_acc);
const char *user = (*env)->GetStringUTFChars(env, jUser, 0);
int res;
if (strlen(user) > 0)
res = account_set_stun_user(acc, user);
else
res = account_set_stun_user(acc, NULL);
(*env)->ReleaseStringUTFChars(env, jUser, user);
return res;
}
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_AccountKt_account_1stun_1pass(JNIEnv *env, jobject thiz, jstring jAcc)
{
const char *native_acc = (*env)->GetStringUTFChars(env, jAcc, 0);
struct account *acc = (struct account *) strtoul(native_acc, NULL, 10);
(*env)->ReleaseStringUTFChars(env, jAcc, native_acc);
if (acc) {
const char *stun_pass = account_stun_pass(acc);
if (stun_pass) return (*env)->NewStringUTF(env, stun_pass);
}
return (*env)->NewStringUTF(env, "");
}
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_AccountKt_account_1set_1stun_1pass(JNIEnv *env, jobject thiz,
jstring jAcc, jstring jPass) {
const char *native_acc = (*env)->GetStringUTFChars(env, jAcc, 0);
struct account *acc = (struct account *)strtoul(native_acc, NULL, 10);
(*env)->ReleaseStringUTFChars(env, jAcc, native_acc);
const char *pass = (*env)->GetStringUTFChars(env, jPass, 0);
int res;
if (strlen(pass) > 0)
res = account_set_stun_pass(acc, pass);
else
res = account_set_stun_pass(acc, NULL);
(*env)->ReleaseStringUTFChars(env, jPass, pass);
return res;
}
JNIEXPORT jint JNICALL
Java_com_tutpro_baresip_AccountKt_account_1set_1mwi(JNIEnv *env, jobject thiz,
jstring javaAcc, jstring javaValue) {

View File

@ -14,6 +14,8 @@ class Account(val accp: String) {
var outbound = ArrayList<String>()
var mediaNat = account_medianat(accp)
var stunServer = ""
var stunUser = account_stun_user(accp)
var stunPass = account_stun_pass(accp)
var audioCodec = ArrayList<String>()
var videoCodec = ArrayList<String>()
var regint = account_regint(accp)
@ -92,7 +94,11 @@ class Account(val accp: String) {
if (mediaNat != "") res = res + ";medianat=${mediaNat}"
if (stunServer != "") res = res + ";stunserver=\"stun:${stunServer}\""
if (stunServer != "") res = res + ";stunserver=\"${stunServer}\""
if (stunUser != "") res = res + ";stunuser=\"${stunUser}\""
if (stunPass != "") res = res + ";stunpass=\"${stunPass}\""
if (audioCodec.size > 0) {
var first = true
@ -243,6 +249,10 @@ external fun account_stun_host(acc: String): String
external fun account_stun_port(acc: String): Int
external fun account_set_stun_host(acc: String, host: String): Int
external fun account_set_stun_port(acc: String, port: Int): Int
external fun account_stun_user(acc: String): String
external fun account_set_stun_user(acc: String, user: String): Int
external fun account_stun_pass(acc: String): String
external fun account_set_stun_pass(acc: String, pass: String): Int
external fun account_mediaenc(acc: String): String
external fun account_set_mediaenc(acc: String, mediaenc: String): Int
external fun account_medianat(acc: String): String

View File

@ -24,6 +24,8 @@ class AccountActivity : AppCompatActivity() {
internal lateinit var outbound2: EditText
internal lateinit var mediaNat: String
internal lateinit var stunServer: EditText
internal lateinit var stunUser: EditText
internal lateinit var stunPass: EditText
internal lateinit var regCheck: CheckBox
internal lateinit var mediaEnc: String
internal lateinit var ipV6MediaCheck: CheckBox
@ -78,8 +80,8 @@ class AccountActivity : AppCompatActivity() {
mediaNat = acc.mediaNat
val mediaNatSpinner = findViewById(R.id.mediaNatSpinner) as Spinner
val mediaNatKeys = arrayListOf("stun", "ice", "")
val mediaNatVals = arrayListOf("STUN", "ICE", "-")
val mediaNatKeys = arrayListOf("stun", "turn", "ice", "")
val mediaNatVals = arrayListOf("STUN", "TURN", "ICE", "-")
var keyIx = mediaNatKeys.indexOf(acc.mediaNat)
var keyVal = mediaNatVals.elementAt(keyIx)
mediaNatKeys.removeAt(keyIx)
@ -94,6 +96,8 @@ class AccountActivity : AppCompatActivity() {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
mediaNat = mediaNatKeys[mediaNatVals.indexOf(parent.selectedItem.toString())]
stunServer.isEnabled = mediaNat != ""
stunUser.isEnabled = mediaNat != ""
stunPass.isEnabled = mediaNat != ""
}
override fun onNothingSelected(parent: AdapterView<*>) {
}
@ -103,6 +107,14 @@ class AccountActivity : AppCompatActivity() {
stunServer.setText(acc.stunServer)
stunServer.isEnabled = mediaNat != ""
stunUser = findViewById(R.id.StunUser) as EditText
stunUser.setText(acc.stunUser)
stunUser.isEnabled = mediaNat != ""
stunPass = findViewById(R.id.StunPass) as EditText
stunPass.setText(acc.stunPass)
stunPass.isEnabled = mediaNat != ""
mediaEnc = acc.mediaEnc
val mediaEncSpinner = findViewById(R.id.mediaEncSpinner) as Spinner
val mediaEncKeys = arrayListOf("zrtp", "dtls_srtp", "srtp-mandf", "srtp-mand", "srtp", "")
@ -312,31 +324,64 @@ class AccountActivity : AppCompatActivity() {
}
if (mediaNat != "") {
val newStunServer = stunServer.text.toString().trim()
var newStunServer = stunServer.text.toString().trim()
if (newStunServer == "")
newStunServer = resources.getString(R.string.stun_server_default)
if (acc.stunServer != newStunServer) {
if (!Utils.checkHostPort(newStunServer)) {
if (!Utils.checkStunUri(newStunServer)) {
Utils.alertView(this, getString(R.string.notice),
String.format(getString(R.string.invalid_stun_server), newStunServer))
return false
}
val p = newStunServer.split(":")
var host = ""
var port = 0
if (newStunServer != "") {
val hostPort = newStunServer.split(":")
host = hostPort[0]
if (hostPort.size == 2) port = hostPort[1].toInt()
val port: Int
if (p.size == 2) {
host = newStunServer
port = 0
} else {
host = newStunServer.substringBeforeLast(":")
port = newStunServer.substringAfterLast(":").toInt()
}
if ((account_set_stun_host(acc.accp, host) == 0) &&
(account_set_stun_port(acc.accp, port) == 0)) {
acc.stunServer = account_stun_host(acc.accp)
if (port != 0)
acc.stunServer += ":" + account_stun_port(acc.accp).toString()
Log.d("Baresip", "New StunServer is '${acc.stunServer}'")
Log.d("Baresip", "New STUN/TURN server URI is '${acc.stunServer}'")
save = true
} else {
Log.e("Baresip", "Setting of StunServer failed")
Log.e("Baresip", "Setting of STUN/TURN URI server failed")
}
}
val su = stunUser.text.toString().trim()
if (Account.checkAuthUser(su)) {
if (account_set_stun_user(acc.accp, su) == 0) {
acc.stunUser = account_stun_user(acc.accp);
Log.d("Baresip", "New STUN/TURN user is ${acc.stunUser}")
save = true
} else {
Log.e("Baresip", "Setting of STUN/TURN user failed")
}
} else {
Utils.alertView(this, getString(R.string.notice),
String.format(getString(R.string.invalid_stun_username), su))
return false
}
val sp = stunPass.text.toString().trim()
if (sp.isEmpty() || Account.checkAuthPass(sp)) {
if (account_set_stun_pass(acc.accp, sp) == 0) {
acc.stunPass = account_stun_pass(acc.accp);
Log.d("Baresip", "New stun pass is ${acc.stunPass}")
save = true
} else {
Log.e("Baresip", "Setting of stun pass failed")
}
} else {
Utils.alertView(this, getString(R.string.notice),
String.format(getString(R.string.invalid_stun_password), sp))
return false
}
}
if (mediaEnc != acc.mediaEnc) {
@ -469,6 +514,14 @@ class AccountActivity : AppCompatActivity() {
Utils.alertView(this, getString(R.string.stun_server),
getString(R.string.stun_server_help))
}
findViewById(R.id.StunUserTitle) as TextView -> {
Utils.alertView(this, getString(R.string.stun_username),
getString(R.string.stun_username_help))
}
findViewById(R.id.StunPassTitle) as TextView -> {
Utils.alertView(this, getString(R.string.stun_password),
getString(R.string.stun_password_help))
}
findViewById(R.id.MediaEncTitle) as TextView -> {
Utils.alertView(this, getString(R.string.media_encryption),
getString(R.string.media_encryption_help))

View File

@ -125,6 +125,13 @@ object Utils {
return checkUriUser(aorUser(aor)) && checkDomain(aorDomain(aor))
}
fun checkStunUri(uri: String): Boolean {
if (!uri.startsWith("stun:") && !uri.startsWith("stuns:") &&
!uri.startsWith("turn:") && !uri.startsWith("turns:"))
return false
return checkHostPort(uri.substringAfter(":"))
}
private fun checkPortTransport(portTransport: String): Boolean {
val pt = portTransport.split(";transport=")
if (pt.count() == 1)

View File

@ -154,6 +154,24 @@
android:text="@string/audio_codecs" >
</TextView>
<TextView
android:id="@+id/MediaEncTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:textSize="18sp"
android:textColor="@android:color/black"
android:onClick="onClick"
android:text="@string/media_encryption" >
</TextView>
<Spinner
android:id="@+id/mediaEncSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp" >
</Spinner>
<TextView
android:id="@+id/MediaNatTitle"
android:layout_width="wrap_content"
@ -198,22 +216,46 @@
</EditText>
<TextView
android:id="@+id/MediaEncTitle"
android:id="@+id/StunUserTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:textSize="18sp"
android:textColor="@android:color/black"
android:onClick="onClick"
android:text="@string/media_encryption" >
android:text="@string/stun_username" >
</TextView>
<Spinner
android:id="@+id/mediaEncSpinner"
android:layout_width="match_parent"
<EditText
android:id="@+id/StunUser"
android:layout_height="wrap_content"
android:paddingTop="8dp" >
</Spinner>
android:layout_width="fill_parent"
android:hint="@string/user_id"
android:textSize="18sp"
android:inputType="textEmailAddress"
android:autofillHints="username" >
</EditText>
<TextView
android:id="@+id/StunPassTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:textSize="18sp"
android:textColor="@android:color/black"
android:onClick="onClick"
android:text="@string/stun_password" >
</TextView>
<EditText
android:id="@+id/StunPass"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:textSize="18sp"
android:inputType="textPassword"
android:importantForAutofill="no" >
</EditText>
<RelativeLayout
android:layout_width="wrap_content"

View File

@ -84,13 +84,18 @@
(vapaaehtoinen). Vaihtoehtoja ovat STUN (Session Traversal Utilities
for NAT, RFC 5389) ja ICE (Interactive Connectivity Establishment, RFC 5245).
</string>
<string name="stun_server">STUN-palvelin</string>
<string name="stun_server_help">STUN-palvelimen muotoa palvelin[:portti]
oleva osoite. Oletusarvo on \'stun.l.google.com:19302\', joka
osoittaa Google:n julkiseen STUN-palvelimeen. Käyttäjätunnusta ja
salasanaa ei voi tällä hetkellä antaa.
<string name="stun_server">STUN/TURN-palvelin</string>
<string name="stun_server_help">STUN/TURN-palvelimen muotoa \'kaava:palvelin[:portti]\'
oleva osoite, missä kaava on \'stun\', \'stuns\', \'turn\' tai \'turns\'. Oletusarvo on
\'stun:stun.l.google.com:19302\', joka osoittaa Google:n julkiseen STUN-palvelimeen.
</string>
<string name="invalid_stun_server">Virheellinen STUN-palvelin \'%1$s\'</string>
<string name="invalid_stun_server">Virheellinen STUN/TURN-palvelimen URI \'%1$s\'</string>
<string name="stun_username">STUN/TURN-käyttäjätunnus</string>
<string name="stun_username_help">Käyttäjätunnus jos STUN/TURN-palvelin vaatii sellaisen</string>
<string name="invalid_stun_username">Virheellinen käyttäjätunnus \'%1$s\'</string>
<string name="stun_password">STUN/TURN-salasana</string>
<string name="stun_password_help">Salasana jos STUN/TURN-palvelin vaatii sellaisen</string>
<string name="invalid_stun_password">Virheellinen salasana \'%1$s\'</string>
<string name="media_encryption">Median salaus</string>
<string name="media_encryption_help">Valitsee median salausprotokollan (vapaaehtoinen).
\n • ZRTP (suositeltu) tarkoittaa, että ZRTP-salausta yritetään neuvotella sen jälkeen, kun puhelu on alkanut.

View File

@ -78,13 +78,19 @@
(Session Traversal Utilities for NAT, RFC 5389) and ICE (Interactive Connectivity
Establishment, RFC 5245).
</string>
<string name="stun_server">STUN Server</string>
<string name="stun_server_help">A STUN Server of form host[:port].
Factory default value is \'stun.l.google.com:19302\', pointing to public Google STUN server.
Username and password are currently not supported.
<string name="stun_server">STUN/TURN Server</string>
<string name="stun_server_help">A STUN/TURN Server URI of form scheme:host[:port], where scheme
is \'stun\', \'stuns\', \'turn\', or \'turns\'. Factory default value is
\'stun:stun.l.google.com:19302\', pointing to public Google STUN server.
</string>
<string name="invalid_stun_server">Invalid STUN Server \'%1$s\'</string>
<string name="stun_server_default" translatable="false">stun.l.google.com:19302</string>
<string name="invalid_stun_server">Invalid STUN/TURN Server URI \'%1$s\'</string>
<string name="stun_server_default" translatable="false">stun:stun.l.google.com:19302</string>
<string name="stun_username">STUN/TURN Username</string>
<string name="stun_username_help">Username if required by STUN/TURN server</string>
<string name="invalid_stun_username">Invalid Username \'%1$s\'</string>
<string name="stun_password">STUN/TURN Password</string>
<string name="stun_password_help">Password if required by STUN/TURN server</string>
<string name="invalid_stun_password">Invalid Password \'%1$s\'</string>
<string name="media_encryption">Media Encryption</string>
<string name="media_encryption_help">Selects media transport encryption protocol (if any).
\n • ZRTP (recommended) means that ZRTP end-to-end media encryption negotiation is tried after