Skip to content

Commit

Permalink
Use KVS stun host in discoverNatBehavior (#1920)
Browse files Browse the repository at this point in the history
* use kvs-specific stun host

* strncmp

* region configurab;e

* clang

* fix windows build

* readme

* log fix

* strnlen

* fix for loop, move the stunhost logic after argv

* stunhostname fix
  • Loading branch information
niyatim23 authored Mar 1, 2024
1 parent dd46d80 commit 391dc0f
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 39 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,19 @@ Similar to the heap profile, you only need to specify the following environment

More information about what environment variables you can configure can be found [here](https://gperftools.github.io/gperftools/cpuprofile.html)

### WebRTC Network Compatibility Checker

This program allows you to understand the network compatibility for WebRTC usage. By providing necessary parameters, it detects NAT behavior and filtering behavior and tells you if you can work with a particular STUN server or not. By default, it uses the STUN server from your environment variable `AWS_DEFAULT_REGION` if present. If not, it uses the STUN server from `us-west-2`.
#### How to Use

1. **Parameters**:
- `-i network-interface-name`: Specify the network interface name.
- `-s stun-hostname`: Specify the STUN server hostname.

2. **Example**:
```bash
./discoverNatBehavior -i eth0 -s stun.example.com

### Filtering network interfaces

This is useful to reduce candidate gathering time when it is known for certain network interfaces to not work well. A sample callback is available in `Common.c`. The `iceSetInterfaceFilterFunc` in `KvsRtcConfiguration` must be set to the required callback. In the sample, it can be done this way in `initializePeerConnection()`:
Expand Down
87 changes: 48 additions & 39 deletions samples/discoverNatBehavior.c
Original file line number Diff line number Diff line change
@@ -1,109 +1,118 @@
#include <com/amazonaws/kinesis/video/webrtcclient/Include.h>

#define NETWORK_INTERFACE_NAME_PARAM "-i"
#define STUN_HOSTNAME_PARAM "-s"
#define DEFAULT_STUN_HOST "stun:stun.sipgate.net:3478"
#define NETWORK_INTERFACE_NAME_PARAM "-i"
#define STUN_HOSTNAME_PARAM "-s"
#define MAX_LEN_NETWORK_INTERFACE_NAME 15

BOOL filterFunc(UINT64 data, PCHAR name)
{
CHAR* desiredInterface = (CHAR*) data;
if (desiredInterface == NULL || STRCMP(name, desiredInterface) == 0) {
if (desiredInterface == NULL || STRNCMP(name, desiredInterface, STRNLEN(name, MAX_LEN_NETWORK_INTERFACE_NAME)) == 0) {
return TRUE;
}
return FALSE;
}

INT32 main(INT32 argc, CHAR** argv)
{
PCHAR interfaceName = NULL, stunHostname = NULL;
printf("Usage: ./discoverNatBehavior -i network-interface-name -s stun-hostname\n");
PCHAR interfaceName = NULL, stunHostname = NULL, pRegion = NULL, pHostnamePostfix = NULL, defaultStunHostName = NULL;
NAT_BEHAVIOR mappingBehavior = NAT_BEHAVIOR_NONE, filteringBehavior = NAT_BEHAVIOR_NONE;
INT32 i;
UINT32 logLevel = LOG_LEVEL_DEBUG;
STATUS status = STATUS_SUCCESS;
CHAR* logLevelStr = NULL;

if ((logLevelStr = GETENV(DEBUG_LOG_LEVEL_ENV_VAR)) != NULL) {
status = STRTOUI32(logLevelStr, NULL, 10, &logLevel);
if (STATUS_FAILED(status)) {
DLOGE("Failed to parse log level with error 0x%08x", status);
exit(1);
}
logLevel = MIN(MAX(logLevel, LOG_LEVEL_VERBOSE), LOG_LEVEL_SILENT);
}
SET_LOGGER_LOG_LEVEL(logLevel);

DLOGI("Usage: ./discoverNatBehavior -i network-interface-name -s stun-hostname");

for (i = 1; i < argc; ++i) {
if (STRCMP(argv[i], NETWORK_INTERFACE_NAME_PARAM) == 0) {
if (STRNCMP(argv[i], NETWORK_INTERFACE_NAME_PARAM, STRNLEN(argv[i], MAX_LEN_NETWORK_INTERFACE_NAME)) == 0) {
interfaceName = argv[++i];
i++;
} else if (STRCMP(argv[i], STUN_HOSTNAME_PARAM) == 0) {
} else if (STRNCMP(argv[i], STUN_HOSTNAME_PARAM, STRNLEN(argv[i], MAX_ICE_CONFIG_URI_LEN + 1)) == 0) {
stunHostname = argv[++i];
i++;
} else {
printf("Unknown param %s", argv[i]);
DLOGW("Unknown param %s", argv[i]);
}
}

if (stunHostname == NULL) {
stunHostname = DEFAULT_STUN_HOST;
if ((pRegion = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) {
pRegion = DEFAULT_AWS_REGION;
}
pHostnamePostfix = KINESIS_VIDEO_STUN_URL_POSTFIX;
// If region is in CN, add CN region uri postfix
if (STRSTR(pRegion, "cn-")) {
pHostnamePostfix = KINESIS_VIDEO_STUN_URL_POSTFIX_CN;
}
defaultStunHostName = (PCHAR) MEMALLOC((MAX_ICE_CONFIG_URI_LEN + 1) * SIZEOF(CHAR));
SNPRINTF(defaultStunHostName, MAX_ICE_CONFIG_URI_LEN + 1, KINESIS_VIDEO_STUN_URL, pRegion, pHostnamePostfix);
stunHostname = defaultStunHostName;
}

printf("Using stun host: %s, local network interface %s.\n", stunHostname, interfaceName);
DLOGI("Using stun host: %s, local network interface %s.", stunHostname, interfaceName);

initKvsWebRtc();
if ((logLevelStr = GETENV(DEBUG_LOG_LEVEL_ENV_VAR)) != NULL) {
status = STRTOUI32(logLevelStr, NULL, 10, &logLevel);
if (STATUS_FAILED(status)) {
fprintf(stderr, "Failed to parse log level with error 0x%08x\n", status);
exit(1);
}
logLevel = MIN(MAX(logLevel, LOG_LEVEL_VERBOSE), LOG_LEVEL_SILENT);
}

SET_LOGGER_LOG_LEVEL(logLevel);

status = discoverNatBehavior(stunHostname, &mappingBehavior, &filteringBehavior, filterFunc, (UINT64) interfaceName);
if (STATUS_FAILED(status)) {
fprintf(stderr, "Failed to detect NAT behavior with error 0x%08x\n", status);
DLOGE("Failed to detect NAT behavior with error 0x%08x", status);
exit(1);
}

printf("Detected NAT mapping behavior %s\n", getNatBehaviorStr(mappingBehavior));
DLOGI("Detected NAT mapping behavior %s", getNatBehaviorStr(mappingBehavior));
switch (mappingBehavior) {
case NAT_BEHAVIOR_NONE:
printf("Failed to detect NAT mapping behavior\n");
DLOGI("Failed to detect NAT mapping behavior");
break;
case NAT_BEHAVIOR_NOT_BEHIND_ANY_NAT:
printf("Host is not behind any NAT. Its IP address is the public IP address. STUN is not needed.\n");
DLOGI("Host is not behind any NAT. Its IP address is the public IP address. STUN is not needed.");
break;
case NAT_BEHAVIOR_NO_UDP_CONNECTIVITY:
printf("Host does not have any UDP connectivity. STUN is not usable. Can only connect using TCP relay\n");
DLOGI("Host does not have any UDP connectivity. STUN is not usable. Can only connect using TCP relay");
break;
case NAT_BEHAVIOR_ENDPOINT_INDEPENDENT:
printf("Host's NAT uses same public IP address regardless of destination address. STUN is usable.\n");
DLOGI("Host's NAT uses same public IP address regardless of destination address. STUN is usable.");
break;
case NAT_BEHAVIOR_ADDRESS_DEPENDENT:
printf("Host's NAT uses different public IP address for different destination address. STUN is not usable.\n");
DLOGI("Host's NAT uses different public IP address for different destination address. STUN is not usable.");
break;
case NAT_BEHAVIOR_PORT_DEPENDENT:
printf("Host's NAT uses different public IP address for different destination address and port. STUN is not usable.\n");
DLOGI("Host's NAT uses different public IP address for different destination address and port. STUN is not usable.");
break;
}

printf("Detected NAT filtering behavior %s\n", getNatBehaviorStr(filteringBehavior));
DLOGI("Detected NAT filtering behavior %s", getNatBehaviorStr(filteringBehavior));
switch (filteringBehavior) {
case NAT_BEHAVIOR_NONE:
printf("Failed to detect NAT filtering behavior\n");
DLOGI("Failed to detect NAT filtering behavior");
break;
case NAT_BEHAVIOR_NOT_BEHIND_ANY_NAT:
printf("Host is not behind any NAT. Its IP address is the public IP address. STUN is not needed.\n");
DLOGI("Host is not behind any NAT. Its IP address is the public IP address. STUN is not needed.");
break;
case NAT_BEHAVIOR_NO_UDP_CONNECTIVITY:
printf("Host does not have any UDP connectivity. STUN is not usable. Can only connect using TCP relay\n");
DLOGI("Host does not have any UDP connectivity. STUN is not usable. Can only connect using TCP relay");
break;
case NAT_BEHAVIOR_ENDPOINT_INDEPENDENT:
printf("Host's NAT allows to receive UDP packet from any external address. STUN is usable.\n");
DLOGI("Host's NAT allows to receive UDP packet from any external address. STUN is usable.");
break;
case NAT_BEHAVIOR_ADDRESS_DEPENDENT:
printf("Host's NAT allows to receive UDP packet from external address that host had previously sent data to. STUN is usable.\n");
DLOGI("Host's NAT allows to receive UDP packet from external address that host had previously sent data to. STUN is usable.");
break;
case NAT_BEHAVIOR_PORT_DEPENDENT:
printf("Host's NAT allows to receive UDP packet from external address and port that host had previously sent data to. STUN is usable.\n");
DLOGI("Host's NAT allows to receive UDP packet from external address and port that host had previously sent data to. STUN is usable.");
break;
}

deinitKvsWebRtc();

SAFE_MEMFREE(defaultStunHostName);
return 0;
}

0 comments on commit 391dc0f

Please sign in to comment.