Commit 42b1b132 authored by jselbie's avatar jselbie Committed by John Selbie

Version 1.2.0 candidate

parent 09e63bc0
...@@ -9,5 +9,4 @@ Version 1.1.2 - Fix compile issues for older linux and macos distributions ...@@ -9,5 +9,4 @@ Version 1.1.2 - Fix compile issues for older linux and macos distributions
Version 1.1.3 - Fix compile issue for clang on MacOSX Version 1.1.3 - Fix compile issue for clang on MacOSX
Version 1.2.0 - Amazon EC2 support added
STUNTMAN - An open source STUN server STUNTMAN - An open source STUN server
Version 1.1.0 Version 1.2.0
February 1, 2012 December 5, 2012
--------------------------------------------------------- ---------------------------------------------------------
...@@ -19,6 +19,10 @@ Features: ...@@ -19,6 +19,10 @@ Features:
address interfaces (if available) and provide NAT behavior and filtering address interfaces (if available) and provide NAT behavior and filtering
detection support for clients. detection support for clients.
Support for running a full mode STUN service on an Amazon EC2 instance. Run
"stunserver --help" for visit www.stunprotocol.org on how to configure this
mode.
Open source Apache license. See LICENSE file fore more details. Open source Apache license. See LICENSE file fore more details.
--------------------------------------------------------- ---------------------------------------------------------
...@@ -58,9 +62,12 @@ Testing: ...@@ -58,9 +62,12 @@ Testing:
Fedora 15 with gcc/g++ 4.6.0 Fedora 15 with gcc/g++ 4.6.0
Ubuntu 11 with gcc/g++ 4.5.2 Ubuntu 11 with gcc/g++ 4.5.2
Ubuntu 12 with gcc/g++ 4.6.3
Ubuntu 12 with clang/clang++ 3.0
Amazon AWS with gcc/g++ 4.4 Amazon AWS with gcc/g++ 4.4
MacOS Snow Leopard (will not compile on earlier versions without updating to MacOS Snow Leopard (will not compile on earlier versions without updating to
a newer version of gcc/g++) a newer version of gcc/g++)
MacOS Lion (with Clang compiler)
FreeBSD 9.0 with gcc/g++ 4.2.1 FreeBSD 9.0 with gcc/g++ 4.2.1
Solaris 11 with gcc/g++ 4.5.2 Solaris 11 with gcc/g++ 4.5.2
...@@ -124,9 +131,6 @@ Firewall ...@@ -124,9 +131,6 @@ Firewall
Feature roadmap (the features I want to implement in a subsequent release) Feature roadmap (the features I want to implement in a subsequent release)
Host a full server across two separate machines (such that two ip addresses
on a single machine will not be required for full mode).
Cleanup Makefile and add "configure" and autotools support Cleanup Makefile and add "configure" and autotools support
Finish Windows port and able to run as a Windows service Finish Windows port and able to run as a Windows service
......
# BOOST_INCLUDE := -I/home/jselbie/boost_1_48_0 # BOOST_INCLUDE := -I/home/jselbie/boost_1_51_0
# OPENSSL_INCLUDE := -I/home/jselbie/lib/openssl # OPENSSL_INCLUDE := -I/home/jselbie/lib/openssl
DEFINES := -DNDEBUG DEFINES := -DNDEBUG
# CLANG compiler works fine
# CXX := /usr/bin/clang++
STANDARD_FLAGS := -Wall -Wuninitialized STANDARD_FLAGS := -Wall -Wuninitialized
RELEASE_FLAGS := -O2 RELEASE_FLAGS := -O2
...@@ -19,6 +22,7 @@ endif ...@@ -19,6 +22,7 @@ endif
.PHONY: all clean debug .PHONY: all clean debug
%.h.gch: %.h %.h.gch: %.h
......
...@@ -61,6 +61,33 @@ Cleanup: ...@@ -61,6 +61,33 @@ Cleanup:
} }
HRESULT NumericIPToAddress(int family, const char* pszIP, CSocketAddress* pAddr)
{
HRESULT hr = S_OK;
ChkIf((family != AF_INET) && (family != AF_INET6), E_INVALIDARG);
if (family == AF_INET)
{
sockaddr_in addr4 = {};
ChkIf(0 == ::inet_pton(family, pszIP, &addr4.sin_addr), E_FAIL);
addr4.sin_family = family;
*pAddr = CSocketAddress(addr4);
}
else
{
sockaddr_in6 addr6 = {};
ChkIf(0 == ::inet_pton(family, pszIP, &addr6.sin6_addr), E_FAIL);
addr6.sin6_family = family;
*pAddr = CSocketAddress(addr6);
}
Cleanup:
return hr;
}
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
*/ */
HRESULT ResolveHostName(const char* pszHostName, int family, bool fNumericOnly, CSocketAddress* pAddr); HRESULT ResolveHostName(const char* pszHostName, int family, bool fNumericOnly, CSocketAddress* pAddr);
HRESULT NumericIPToAddress(int family, const char* pszIP, CSocketAddress* pAddr);
#endif /* RESOLVEHOSTNAME_H */ #endif /* RESOLVEHOSTNAME_H */
......
STUNK - An open source STUN server STUNTMAN - An open source STUN server
Version 1.1.0 Version 1.2.0
February 1, 2012 December 5, 2012
--------------------------------------------------------- ---------------------------------------------------------
...@@ -19,6 +19,10 @@ Features: ...@@ -19,6 +19,10 @@ Features:
address interfaces (if available) and provide NAT behavior and filtering address interfaces (if available) and provide NAT behavior and filtering
detection support for clients. detection support for clients.
Support for running a full mode STUN service on an Amazon EC2 instance. Run
"stunserver --help" for visit www.stunprotocol.org on how to configure this
mode.
Open source Apache license. See LICENSE file fore more details. Open source Apache license. See LICENSE file fore more details.
--------------------------------------------------------- ---------------------------------------------------------
...@@ -58,9 +62,12 @@ Testing: ...@@ -58,9 +62,12 @@ Testing:
Fedora 15 with gcc/g++ 4.6.0 Fedora 15 with gcc/g++ 4.6.0
Ubuntu 11 with gcc/g++ 4.5.2 Ubuntu 11 with gcc/g++ 4.5.2
Ubuntu 12 with gcc/g++ 4.6.3
Ubuntu 12 with clang/clang++ 3.0
Amazon AWS with gcc/g++ 4.4 Amazon AWS with gcc/g++ 4.4
MacOS Snow Leopard (will not compile on earlier versions without updating to MacOS Snow Leopard (will not compile on earlier versions without updating to
a newer version of gcc/g++) a newer version of gcc/g++)
MacOS Lion (with Clang compiler)
FreeBSD 9.0 with gcc/g++ 4.2.1 FreeBSD 9.0 with gcc/g++ 4.2.1
Solaris 11 with gcc/g++ 4.5.2 Solaris 11 with gcc/g++ 4.5.2
...@@ -124,9 +131,6 @@ Firewall ...@@ -124,9 +131,6 @@ Firewall
Feature roadmap (the features I want to implement in a subsequent release) Feature roadmap (the features I want to implement in a subsequent release)
Host a full server across two separate machines (such that two ip addresses
on a single machine will not be required for full mode).
Cleanup Makefile and add "configure" and autotools support Cleanup Makefile and add "configure" and autotools support
Finish Windows port and able to run as a Windows service Finish Windows port and able to run as a Windows service
......
STUNK - An open source STUN server STUNTMAN - An open source STUN server
Version 1.1.0 Version 1.2.0
February 1, 2012 December 5, 2012
--------------------------------------------------------- ---------------------------------------------------------
...@@ -14,6 +14,8 @@ Features: ...@@ -14,6 +14,8 @@ Features:
Stun server can operate in "full" mode as well as "basic" mode. Basic mode configures the server to listen on one port and respond to STUN binding requests. Full mode configures the service to listen on two different IP address interfaces (if available) and provide NAT behavior and filtering detection support for clients. Stun server can operate in "full" mode as well as "basic" mode. Basic mode configures the server to listen on one port and respond to STUN binding requests. Full mode configures the service to listen on two different IP address interfaces (if available) and provide NAT behavior and filtering detection support for clients.
Support for running a full mode STUN service on an Amazon EC2 instance. Run "stunserver --help" for visit www.stunprotocol.org on how to configure this mode.
Open source Apache license. See LICENSE file fore more details. Open source Apache license. See LICENSE file fore more details.
--------------------------------------------------------- ---------------------------------------------------------
...@@ -36,8 +38,11 @@ Testing: ...@@ -36,8 +38,11 @@ Testing:
Fedora 15 with gcc/g++ 4.6.0 Fedora 15 with gcc/g++ 4.6.0
Ubuntu 11 with gcc/g++ 4.5.2 Ubuntu 11 with gcc/g++ 4.5.2
Ubuntu 12 with gcc/g++ 4.6.3
Ubuntu 12 with clang/clang++ 3.0
Amazon AWS with gcc/g++ 4.4 Amazon AWS with gcc/g++ 4.4
MacOS Snow Leopard (will not compile on earlier versions without updating to a newer version of gcc/g++) MacOS Snow Leopard (will not compile on earlier versions without updating to a newer version of gcc/g++)
MacOS Lion (with Clang compiler)
FreeBSD 9.0 with gcc/g++ 4.2.1 FreeBSD 9.0 with gcc/g++ 4.2.1
Solaris 11 with gcc/g++ 4.5.2 Solaris 11 with gcc/g++ 4.5.2
...@@ -79,8 +84,6 @@ Firewall ...@@ -79,8 +84,6 @@ Firewall
Feature roadmap (the features I want to implement in a subsequent release) Feature roadmap (the features I want to implement in a subsequent release)
Host a full server across two separate machines (such that two ip addresses on a single machine will not be required for full mode).
Cleanup Makefile and add "configure" and autotools support Cleanup Makefile and add "configure" and autotools support
Finish Windows port and able to run as a Windows service Finish Windows port and able to run as a Windows service
......
...@@ -7,94 +7,93 @@ stunclient - command line app for the STUN protocol ...@@ -7,94 +7,93 @@ stunclient - command line app for the STUN protocol
\f[B]stunclient\f[] [OPTIONS] server [port] \f[B]stunclient\f[] [OPTIONS] server [port]
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
stunclient attempts to discover the local host's own external IP stunclient attempts to discover the local host\[aq]s own external IP
address, obtain a port mapping, and optionally discover properties address, obtain a port mapping, and optionally discover properties of
of the Network Address Translator (NAT) between the host and the the Network Address Translator (NAT) between the host and the the
the server. server.
.SH OPTIONS .SH OPTIONS
.PP .PP
The following options are supported. The following options are supported.
.PP .IP
\f[CR] .nf
--mode\ MODE \f[C]
--localaddr\ INTERFACE --mode\ MODE
--localport\ PORTNUMBER --localaddr\ INTERFACE
--family\ IPVERSION --localport\ PORTNUMBER
--protocol\ PROTO --family\ IPVERSION
--verbosity\ LOGLEVEL --protocol\ PROTO
--help --verbosity\ LOGLEVEL
--help
\f[] \f[]
.fi
.PP .PP
Details of each option and paramters are as follows. Details of each option and paramters are as follows.
.PP .PP
\f[B]server\f[] \f[B]server\f[]
.PP .PP
The \f[B]server\f[] parameter is the IP address or FQDN of the The \f[B]server\f[] parameter is the IP address or FQDN of the remote
remote server to befrom the binding tests with. server to befrom the binding tests with.
It is the only required parameter. It is the only required parameter.
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]port\f[] \f[B]port\f[]
.PP .PP
The \f[B]port\f[] parameter is an optional parameter that can The \f[B]port\f[] parameter is an optional parameter that can follow the
follow the server parameter. server parameter.
The default is 3478 for UDP and TCP. The default is 3478 for UDP and TCP.
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]mode\f[] MODE \f[B]--mode\f[] MODE
.PP .PP
Where MODE is either \[lq]basic\[rq] or \[lq]full\[rq]. Where MODE is either "basic" or "full".
\[lq]basic\[rq] mode is the default and indicates that the client "basic" mode is the default and indicates that the client should perform
should perform a STUN binding test only. a STUN binding test only.
\[lq]full\[rq] mode indicates that the client should attempt to "full" mode indicates that the client should attempt to diagnose NAT
diagnose NAT behavior and filtering methodologies if the server behavior and filtering methodologies if the server supports this mode.
supports this mode.
The NAT filtering test is only supported for UDP. The NAT filtering test is only supported for UDP.
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]localaddr\f[] INTERFACE or IPADDRESS \f[B]--localaddr\f[] INTERFACE or IPADDRESS
.PP .PP
The value for this option may the name of an interface (such as The value for this option may the name of an interface (such as "eth0"
\[lq]eth0\[rq] or \[lq]lo\[rq]). or "lo").
Or it may be one of the available IP addresses assigned to a Or it may be one of the available IP addresses assigned to a network
network interface present on the host (such as interface present on the host (such as "128.23.45.67").
\[lq]128.23.45.67\[rq]).
The interface chosen will be the preferred address for sending and The interface chosen will be the preferred address for sending and
receiving responses with the remote server. receiving responses with the remote server.
The default is to let the system decide which address to send on The default is to let the system decide which address to send on and to
and to listen for responses on all addresses (INADDR_ANY). listen for responses on all addresses (INADDR_ANY).
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]localport\f[] PORTNUM \f[B]--localport\f[] PORTNUM
.PP .PP
PORTNUM is a value between 1 to 65535. PORTNUM is a value between 1 to 65535.
This is the UDP or TCP port that the primary and alternate This is the UDP or TCP port that the primary and alternate interfaces
interfaces listen on as the primary port for binding requests. listen on as the primary port for binding requests.
If not specified, a randomly available port chosen by the system is If not specified, a randomly available port chosen by the system is
used. used.
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]family\f[] IPVERSION \f[B]--family\f[] IPVERSION
.PP .PP
IPVERSION is either \[lq]4\[rq] or \[lq]6\[rq] to specify the usage IPVERSION is either "4" or "6" to specify the usage of IPV4 or IPV6.
of IPV4 or IPV6. If not specified, the default value is "4".
If not specified, the default value is \[lq]4\[rq].
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]protocol\f[] PROTO \f[B]--protocol\f[] PROTO
.PP .PP
PROTO is either \[lq]udp\[rq] or \[lq]tcp\[rq]. PROTO is either "udp" or "tcp".
\[lq]udp\[rq] is the default if this parameter is not specified "udp" is the default if this parameter is not specified
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]verbosity\f[] LOGLEVEL \f[B]--verbosity\f[] LOGLEVEL
.PP .PP
Sets the verbosity of the logging level. Sets the verbosity of the logging level.
0 is the default (minimal output and logging). 0 is the default (minimal output and logging).
...@@ -103,22 +102,22 @@ Sets the verbosity of the logging level. ...@@ -103,22 +102,22 @@ Sets the verbosity of the logging level.
.PP .PP
* * * * * * * * * *
.PP .PP
\f[B]\[em]help\f[] Prints this help page \f[B]--help\f[] Prints this help page
.SH EXAMPLES .SH EXAMPLES
.TP .TP
.B stunclient stunserver.org 3478 .B stunclient stunserver.org 3478
Performs a simple binding test request with the server listening at Performs a simple binding test request with the server listening at
\[lq]stunserver.org\[rq] "stunserver.org"
.RS .RS
.RE .RE
.TP .TP
.B stunclient \[em]mode full \[em]localport 9999 12.34.56.78 .B stunclient --mode full --localport 9999 12.34.56.78
Performs a full set of UDP NAT behavior tests from local port 9999 Performs a full set of UDP NAT behavior tests from local port 9999 to
to the server listening at IP Address 12.34.56.78 (port 3478) the server listening at IP Address 12.34.56.78 (port 3478)
.RS .RS
.RE .RE
.TP .TP
.B stunclient \[em]protocol tcp stun.selbie.com .B stunclient --protocol tcp stun.selbie.com
Performs a simple binding test using TCP to server listening on the Performs a simple binding test using TCP to server listening on the
default port of 3478 at stun.selbie.com default port of 3478 at stun.selbie.com
.RS .RS
...@@ -126,4 +125,3 @@ default port of 3478 at stun.selbie.com ...@@ -126,4 +125,3 @@ default port of 3478 at stun.selbie.com
.SH AUTHOR .SH AUTHOR
.PP .PP
john selbie (jselbie\@gmail.com) john selbie (jselbie\@gmail.com)
This diff is collapsed.
This diff is collapsed.
...@@ -26,6 +26,8 @@ The following options are supported. ...@@ -26,6 +26,8 @@ The following options are supported.
--protocol PROTO --protocol PROTO
--maxconn MAXCONN --maxconn MAXCONN
--verbosity LOGLEVEL --verbosity LOGLEVEL
--primaryadvertised
--altadvertised
--help --help
Details of each option are as follows. Details of each option are as follows.
...@@ -67,7 +69,7 @@ a configured IP address. ...@@ -67,7 +69,7 @@ a configured IP address.
____ ____
**--altinterface** INTERFACE OR IPADDRESS **--altinterface** INTERFACE
Where INTERFACE specified is either a local IP address (e.g. "192.168.1.3") Where INTERFACE specified is either a local IP address (e.g. "192.168.1.3")
of the host or the name of a network interface (e.g. "eth1"). of the host or the name of a network interface (e.g. "eth1").
...@@ -148,6 +150,31 @@ The default is 0. ...@@ -148,6 +150,31 @@ The default is 0.
____ ____
**--primaryadvertised** PRIMARY-IP
**--altadvertised** ALT-IP
Where PRIMARY-IP and ALT-IP are valid numeric IP address strings (e.g. "101.23.45.67") that
are the public IP addresses of the --primaryinterface and --altinterface addresses discussed
above.
These two parameters are for advanced usage only. It is intended for support of
running a STUN server in full mode on Amazon EC2 or other hosted environment
where the server is running behind a NAT. Do not set this parameter unless you
know specifically the effect it creates.
Normally, without these parameters being set, the ORIGIN attribute, OTHER-ADDRESS attribute, and
CHANGED-ADDRESS attributes are are determined by querying the local adapters or sockets
for the IP address they are listening on. When running the server in a NAT environment,
binding responses will still contain a correct set of mapping address attributes, such that P2P
connectivity may succeed. However, the the ORIGIN, OTHER-ADDRESS,
and CHANGED-ADDRESS attributes sent by the server will be incorrect. The impact of sending an incorrect OTHER-ADDRESS or CHANGED-ADDRESS
will result in a client attempting to do NAT Behavior tests or NAT filtering tests to report an incorrect result.
For more details, visit www.stunprotocol.org for details on how to correctly set these parameters for use within Amazon EC2.
____
**--help** **--help**
Prints this help page Prints this help page
......
This diff is collapsed.
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
// these are auto-generated files made from markdown sources. See ../resources // these are auto-generated files made from markdown sources. See ../resources
#include "stunserver.txtcode" #include "stunserver.txtcode"
#include "stunserver_lite.txtcode" #include "stunserver_lite.txtcode"
#include "resolvehostname.h"
void PrintUsage(bool fSummaryUsage) void PrintUsage(bool fSummaryUsage)
...@@ -104,11 +105,14 @@ struct StartupArgs ...@@ -104,11 +105,14 @@ struct StartupArgs
std::string strAltInterface; std::string strAltInterface;
std::string strPrimaryPort; std::string strPrimaryPort;
std::string strAltPort; std::string strAltPort;
std::string strPrimaryAdvertised;
std::string strAlternateAdvertised;
std::string strFamily; std::string strFamily;
std::string strProtocol; std::string strProtocol;
std::string strHelp; std::string strHelp;
std::string strVerbosity; std::string strVerbosity;
std::string strMaxConnections; std::string strMaxConnections;
}; };
#define PRINTARG(member) Logging::LogMsg(LL_DEBUG, "%s = %s", #member, args.member.length() ? args.member.c_str() : "<empty>"); #define PRINTARG(member) Logging::LogMsg(LL_DEBUG, "%s = %s", #member, args.member.length() ? args.member.c_str() : "<empty>");
...@@ -119,6 +123,8 @@ void DumpStartupArgs(StartupArgs& args) ...@@ -119,6 +123,8 @@ void DumpStartupArgs(StartupArgs& args)
PRINTARG(strMode); PRINTARG(strMode);
PRINTARG(strPrimaryInterface); PRINTARG(strPrimaryInterface);
PRINTARG(strAltInterface); PRINTARG(strAltInterface);
PRINTARG(strPrimaryAdvertised);
PRINTARG(strAlternateAdvertised);
PRINTARG(strPrimaryPort); PRINTARG(strPrimaryPort);
PRINTARG(strAltPort); PRINTARG(strAltPort);
PRINTARG(strFamily); PRINTARG(strFamily);
...@@ -157,6 +163,18 @@ void DumpConfig(CStunServerConfig &config) ...@@ -157,6 +163,18 @@ void DumpConfig(CStunServerConfig &config)
Logging::LogMsg(LL_DEBUG, "AA = %s", strSocket.c_str()); Logging::LogMsg(LL_DEBUG, "AA = %s", strSocket.c_str());
} }
if (config.addrPrimaryAdvertised.IsIPAddressZero() == false)
{
config.addrPrimaryAdvertised.ToString(&strSocket);
Logging::LogMsg(LL_DEBUG, "Primary IP will be advertised as %s", strSocket.c_str());
}
if (config.addrAlternateAdvertised.IsIPAddressZero() == false)
{
config.addrAlternateAdvertised.ToString(&strSocket);
Logging::LogMsg(LL_DEBUG, "Alternate IP will be advertised as %s", strSocket.c_str());
}
Logging::LogMsg(LL_DEBUG, "Protocol = %s", config.fTCP ? "TCP" : "UDP"); Logging::LogMsg(LL_DEBUG, "Protocol = %s", config.fTCP ? "TCP" : "UDP");
if (config.fTCP && (config.nMaxConnections>0)) if (config.fTCP && (config.nMaxConnections>0))
{ {
...@@ -206,6 +224,8 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig* ...@@ -206,6 +224,8 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
bool fHasAtLeastTwoAdapters = false; bool fHasAtLeastTwoAdapters = false;
CStunServerConfig config; CStunServerConfig config;
int nMaxConnections = 0; int nMaxConnections = 0;
const char* pszPrimaryAdvertised = argsIn.strPrimaryAdvertised.c_str();
const char* pszAltAdvertised = argsIn.strAlternateAdvertised.c_str();
enum ServerMode enum ServerMode
{ {
...@@ -221,7 +241,7 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig* ...@@ -221,7 +241,7 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
ChkIfA(pConfigOut == NULL, E_INVALIDARG); ChkIfA(pConfigOut == NULL, E_INVALIDARG);
// normalize the args. The "trim" is not needed for command line args, but will be useful when we have an "init file" for intializing the server // normalize the args. The "trim" is not needed for command line args, but will be useful when we have an "init file" for initializing the server
StringHelper::ToLower(args.strMode); StringHelper::ToLower(args.strMode);
StringHelper::Trim(args.strMode); StringHelper::Trim(args.strMode);
...@@ -237,6 +257,9 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig* ...@@ -237,6 +257,9 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
StringHelper::ToLower(args.strProtocol); StringHelper::ToLower(args.strProtocol);
StringHelper::Trim(args.strProtocol); StringHelper::Trim(args.strProtocol);
StringHelper::Trim(args.strPrimaryAdvertised);
StringHelper::Trim(args.strAlternateAdvertised);
...@@ -338,7 +361,7 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig* ...@@ -338,7 +361,7 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
if (nPrimaryPort == nAltPort) if (nPrimaryPort == nAltPort)
{ {
Logging::LogMsg(LL_ALWAYS, "Primary port and altnernate port must be different values"); Logging::LogMsg(LL_ALWAYS, "Primary port and alternate port must be different values");
Chk(E_INVALIDARG); Chk(E_INVALIDARG);
} }
...@@ -435,6 +458,37 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig* ...@@ -435,6 +458,37 @@ HRESULT BuildServerConfigurationFromArgs(StartupArgs& argsIn, CStunServerConfig*
} }
// ---- Address advertisement --------------------------------------------------------
// handle the advertised address parameters and make sure they are valid IP address strings
if (!StringHelper::IsNullOrEmpty(pszPrimaryAdvertised))
{
hr = ::NumericIPToAddress(family, pszPrimaryAdvertised, &config.addrPrimaryAdvertised);
if (FAILED(hr))
{
Logging::LogMsg(LL_ALWAYS, "Error with --primaryadvertised. %s is not a valid IP address string", pszPrimaryAdvertised);
Chk(hr);
}
}
if (!StringHelper::IsNullOrEmpty(pszAltAdvertised))
{
if (mode != Full)
{
Logging::LogMsg(LL_ALWAYS, "Error. --altadvertised was specified, but --mode param was not set to FULL.");
ChkIf(config.fHasAA, E_INVALIDARG);
}
hr = ::NumericIPToAddress(family, pszAltAdvertised, &config.addrAlternateAdvertised);
if (FAILED(hr))
{
Logging::LogMsg(LL_ALWAYS, "Error with --altadvertised. %s is not a valid IP address string", pszAltAdvertised);
Chk(hr);
}
}
*pConfigOut = config; *pConfigOut = config;
hr = S_OK; hr = S_OK;
...@@ -452,6 +506,8 @@ HRESULT ParseCommandLineArgs(int argc, char** argv, int startindex, StartupArgs* ...@@ -452,6 +506,8 @@ HRESULT ParseCommandLineArgs(int argc, char** argv, int startindex, StartupArgs*
cmdline.AddOption("mode", required_argument, &pStartupArgs->strMode); cmdline.AddOption("mode", required_argument, &pStartupArgs->strMode);
cmdline.AddOption("primaryinterface", required_argument, &pStartupArgs->strPrimaryInterface); cmdline.AddOption("primaryinterface", required_argument, &pStartupArgs->strPrimaryInterface);
cmdline.AddOption("altinterface", required_argument, &pStartupArgs->strAltInterface); cmdline.AddOption("altinterface", required_argument, &pStartupArgs->strAltInterface);
cmdline.AddOption("primaryadvertised", required_argument, &pStartupArgs->strPrimaryAdvertised);
cmdline.AddOption("altadvertised", required_argument, &pStartupArgs->strAlternateAdvertised);
cmdline.AddOption("primaryport", required_argument, &pStartupArgs->strPrimaryPort); cmdline.AddOption("primaryport", required_argument, &pStartupArgs->strPrimaryPort);
cmdline.AddOption("altport", required_argument, &pStartupArgs->strAltPort); cmdline.AddOption("altport", required_argument, &pStartupArgs->strAltPort);
cmdline.AddOption("family", required_argument, &pStartupArgs->strFamily); cmdline.AddOption("family", required_argument, &pStartupArgs->strFamily);
......
...@@ -49,11 +49,54 @@ CStunServer::~CStunServer() ...@@ -49,11 +49,54 @@ CStunServer::~CStunServer()
Shutdown(); Shutdown();
} }
HRESULT CStunServer::AddSocket(TransportAddressSet* pTSA, SocketRole role, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise)
{
HRESULT hr = S_OK;
ASSERT(IsValidSocketRole(role));
Chk(_arrSockets[role].UDPInit(addrListen, role));
ChkA(_arrSockets[role].EnablePktInfoOption(true));
#ifdef DEBUG
{
CSocketAddress addrLocal = _arrSockets[role].GetLocalAddress();
// addrListen is the address we asked the socket to listen on via a call to bind()
// addrLocal is the socket address returned by getsockname after the socket is binded
// I can't think of any case where addrListen != addrLocal
// the ports will be different if addrListen.GetPort() is 0, but that
// should never happen.
// but if the assert below fails, I want to know about it
ASSERT(addrLocal.IsSameIP_and_Port(addrListen));
}
#endif
pTSA->set[role].fValid = true;
if (addrAdvertise.IsIPAddressZero() == false)
{
// set the TSA for this socket to what the configuration wants us to advertise this address for in ORIGIN and OTHER address attributes
pTSA->set[role].addr = addrAdvertise;
pTSA->set[role].addr.SetPort(addrListen.GetPort()); // use the original port
}
else
{
pTSA->set[role].addr = addrListen; // use the socket's IP and port (OK if this is INADDR_ANY)
}
Cleanup:
return hr;
}
HRESULT CStunServer::Initialize(const CStunServerConfig& config) HRESULT CStunServer::Initialize(const CStunServerConfig& config)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
int socketcount = 0; int socketcount = 0;
CRefCountedPtr<IStunAuth> _spAuth; CRefCountedPtr<IStunAuth> _spAuth;
TransportAddressSet tsa = {};
// cleanup any thing that's going on now // cleanup any thing that's going on now
Shutdown(); Shutdown();
...@@ -61,39 +104,34 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config) ...@@ -61,39 +104,34 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config)
// optional code: create an authentication provider and initialize it here (if you want authentication) // optional code: create an authentication provider and initialize it here (if you want authentication)
// set the _spAuth member to reference it // set the _spAuth member to reference it
// Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth)); // Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth));
// Create the sockets // Create the sockets and initialize the TSA thing
if (config.fHasPP) if (config.fHasPP)
{ {
Chk(_arrSockets[RolePP].UDPInit(config.addrPP, RolePP)); Chk(AddSocket(&tsa, RolePP, config.addrPP, config.addrPrimaryAdvertised));
ChkA(_arrSockets[RolePP].EnablePktInfoOption(true));
socketcount++; socketcount++;
} }
if (config.fHasPA) if (config.fHasPA)
{ {
Chk(_arrSockets[RolePA].UDPInit(config.addrPA, RolePA)); Chk(AddSocket(&tsa, RolePA, config.addrPA, config.addrPrimaryAdvertised));
ChkA(_arrSockets[RolePA].EnablePktInfoOption(true));
socketcount++; socketcount++;
} }
if (config.fHasAP) if (config.fHasAP)
{ {
Chk(_arrSockets[RoleAP].UDPInit(config.addrAP, RoleAP)); Chk(AddSocket(&tsa, RoleAP, config.addrAP, config.addrAlternateAdvertised));
ChkA(_arrSockets[RoleAP].EnablePktInfoOption(true));
socketcount++; socketcount++;
} }
if (config.fHasAA) if (config.fHasAA)
{ {
Chk(_arrSockets[RoleAA].UDPInit(config.addrAA, RoleAA)); Chk(AddSocket(&tsa, RoleAA, config.addrAA, config.addrAlternateAdvertised));
ChkA(_arrSockets[RoleAA].EnablePktInfoOption(true));
socketcount++; socketcount++;
} }
ChkIf(socketcount == 0, E_INVALIDARG); ChkIf(socketcount == 0, E_INVALIDARG);
if (config.fMultiThreadedMode == false) if (config.fMultiThreadedMode == false)
{ {
Logging::LogMsg(LL_DEBUG, "Configuring single threaded mode\n"); Logging::LogMsg(LL_DEBUG, "Configuring single threaded mode\n");
...@@ -104,7 +142,7 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config) ...@@ -104,7 +142,7 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config)
_threads.push_back(pThread); _threads.push_back(pThread);
Chk(pThread->Init(_arrSockets, _spAuth, (SocketRole)-1)); Chk(pThread->Init(_arrSockets, &tsa, _spAuth, (SocketRole)-1));
} }
else else
{ {
...@@ -121,7 +159,7 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config) ...@@ -121,7 +159,7 @@ HRESULT CStunServer::Initialize(const CStunServerConfig& config)
pThread = new CStunSocketThread(); pThread = new CStunSocketThread();
ChkIf(pThread==NULL, E_OUTOFMEMORY); ChkIf(pThread==NULL, E_OUTOFMEMORY);
_threads.push_back(pThread); _threads.push_back(pThread);
Chk(pThread->Init(_arrSockets, _spAuth, rolePrimaryRecv)); Chk(pThread->Init(_arrSockets, &tsa, _spAuth, rolePrimaryRecv));
} }
} }
} }
...@@ -161,8 +199,7 @@ HRESULT CStunServer::Shutdown() ...@@ -161,8 +199,7 @@ HRESULT CStunServer::Shutdown()
_threads.clear(); _threads.clear();
_spAuth.ReleaseAndClear(); _spAuth.ReleaseAndClear();
return S_OK; return S_OK;
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "stunsocket.h" #include "stunsocket.h"
#include "stunsocketthread.h" #include "stunsocketthread.h"
#include "stunauth.h" #include "stunauth.h"
#include "messagehandler.h"
...@@ -43,6 +44,9 @@ public: ...@@ -43,6 +44,9 @@ public:
CSocketAddress addrPA; // address for PA CSocketAddress addrPA; // address for PA
CSocketAddress addrAP; // address for AP CSocketAddress addrAP; // address for AP
CSocketAddress addrAA; // address for AA CSocketAddress addrAA; // address for AA
CSocketAddress addrPrimaryAdvertised; // public-IP for PP and PA (port is ignored)
CSocketAddress addrAlternateAdvertised; // public-IP for AP and AA (port is ignored)
CStunServerConfig(); CStunServerConfig();
}; };
...@@ -68,6 +72,8 @@ private: ...@@ -68,6 +72,8 @@ private:
friend class CObjectFactory<CStunServer>; friend class CObjectFactory<CStunServer>;
CRefCountedPtr<IStunAuth> _spAuth; CRefCountedPtr<IStunAuth> _spAuth;
HRESULT AddSocket(TransportAddressSet* pTSA, SocketRole role, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise);
public: public:
......
...@@ -46,7 +46,7 @@ void CStunSocketThread::ClearSocketArray() ...@@ -46,7 +46,7 @@ void CStunSocketThread::ClearSocketArray()
_socks.clear(); _socks.clear();
} }
HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAuth, SocketRole rolePrimaryRecv) HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, TransportAddressSet* pTSA, IStunAuth* pAuth, SocketRole rolePrimaryRecv)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
...@@ -55,6 +55,7 @@ HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAut ...@@ -55,6 +55,7 @@ HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAut
ChkIfA(_fThreadIsValid, E_UNEXPECTED); ChkIfA(_fThreadIsValid, E_UNEXPECTED);
ChkIfA(arrayOfFourSockets == NULL, E_INVALIDARG); ChkIfA(arrayOfFourSockets == NULL, E_INVALIDARG);
ChkIfA(pTSA == NULL, E_INVALIDARG);
// if this thread was configured to listen on a single socket (aka "multi-threaded mode"), then // if this thread was configured to listen on a single socket (aka "multi-threaded mode"), then
// validate that it exists // validate that it exists
...@@ -66,18 +67,7 @@ HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAut ...@@ -66,18 +67,7 @@ HRESULT CStunSocketThread::Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAut
_arrSendSockets = arrayOfFourSockets; _arrSendSockets = arrayOfFourSockets;
// initialize the TSA thing // initialize the TSA thing
memset(&_tsa, '\0', sizeof(_tsa)); _tsa = *pTSA;
for (size_t i = 0; i < 4; i++)
{
if (_arrSendSockets[i].IsValid())
{
SocketRole role = _arrSendSockets[i].GetRole();
ASSERT(role == (SocketRole)i);
_tsa.set[role].fValid = true;
_tsa.set[role].addr = _arrSendSockets[i].GetLocalAddress();
}
}
if (fSingleSocketRecv) if (fSingleSocketRecv)
{ {
...@@ -275,10 +265,12 @@ void CStunSocketThread::Run() ...@@ -275,10 +265,12 @@ void CStunSocketThread::Run()
int ret; int ret;
int sendsocketcount = 0; int sendsocketcount = 0;
sendsocketcount += (int)(_tsa.set[RolePP].fValid); sendsocketcount += (int)(_tsa.set[RolePP].fValid);
sendsocketcount += (int)(_tsa.set[RolePA].fValid); sendsocketcount += (int)(_tsa.set[RolePA].fValid);
sendsocketcount += (int)(_tsa.set[RoleAP].fValid); sendsocketcount += (int)(_tsa.set[RoleAP].fValid);
sendsocketcount += (int)(_tsa.set[RoleAA].fValid); sendsocketcount += (int)(_tsa.set[RoleAA].fValid);
Logging::LogMsg(LL_DEBUG, "Starting listener thread (%d recv sockets, %d send sockets)", _socks.size(), sendsocketcount); Logging::LogMsg(LL_DEBUG, "Starting listener thread (%d recv sockets, %d send sockets)", _socks.size(), sendsocketcount);
while (_fNeedToExit == false) while (_fNeedToExit == false)
......
...@@ -32,7 +32,7 @@ public: ...@@ -32,7 +32,7 @@ public:
CStunSocketThread(); CStunSocketThread();
~CStunSocketThread(); ~CStunSocketThread();
HRESULT Init(CStunSocket* arrayOfFourSockets, IStunAuth* pAuth, SocketRole rolePrimaryRecv); HRESULT Init(CStunSocket* arrayOfFourSockets, TransportAddressSet* pTSA, IStunAuth* pAuth, SocketRole rolePrimaryRecv);
HRESULT Start(); HRESULT Start();
HRESULT SignalForStop(bool fPostMessages); HRESULT SignalForStop(bool fPostMessages);
...@@ -52,20 +52,16 @@ private: ...@@ -52,20 +52,16 @@ private:
CStunSocket* _arrSendSockets; // matches CStunServer::_arrSockets CStunSocket* _arrSendSockets; // matches CStunServer::_arrSockets
std::vector<CStunSocket*> _socks; // sockets for receiving on std::vector<CStunSocket*> _socks; // sockets for receiving on
bool _fNeedToExit; bool _fNeedToExit;
pthread_t _pthread; pthread_t _pthread;
bool _fThreadIsValid; bool _fThreadIsValid;
int _rotation; int _rotation;
TransportAddressSet _tsa; TransportAddressSet _tsa;
CRefCountedPtr<IStunAuth> _spAuth; CRefCountedPtr<IStunAuth> _spAuth;
// pre-allocated objects for the thread // pre-allocated objects for the thread
CStunMessageReader _reader; CStunMessageReader _reader;
CRefCountedBuffer _spBufferReader; // buffer internal to the reader CRefCountedBuffer _spBufferReader; // buffer internal to the reader
......
...@@ -243,7 +243,7 @@ HRESULT CTCPStunThread::Init(const TransportAddressSet& tsaListen, const Transpo ...@@ -243,7 +243,7 @@ HRESULT CTCPStunThread::Init(const TransportAddressSet& tsaListen, const Transpo
// Max sure we didn't accidently pass in anything crazy // Max sure we didn't accidently pass in anything crazy
ChkIfA(_maxConnections >= 100000, E_INVALIDARG); ChkIfA(_maxConnections >= 100000, E_INVALIDARG);
for (size_t i = 0; i <= ARRAYSIZE(_tsa.set); i++) for (size_t i = 0; i < ARRAYSIZE(_tsa.set); i++)
{ {
countListen += tsaListen.set[i].fValid ? 1 : 0; countListen += tsaListen.set[i].fValid ? 1 : 0;
countHandler += tsaHandler.set[i].fValid ? 1 : 0; countHandler += tsaHandler.set[i].fValid ? 1 : 0;
...@@ -825,10 +825,34 @@ CTCPServer::~CTCPServer() ...@@ -825,10 +825,34 @@ CTCPServer::~CTCPServer()
} }
void CTCPServer::InitTSA(TransportAddressSet* pTSA, SocketRole role, bool fValid, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise)
{
if (fValid == false)
{
pTSA->set[role].fValid = false;
pTSA->set[role].addr = CSocketAddress();
}
else
{
pTSA->set[role].fValid = true;
if (addrAdvertise.IsIPAddressZero())
{
pTSA->set[role].addr = addrListen;
}
else
{
pTSA->set[role].addr = addrAdvertise;
pTSA->set[role].addr.SetPort(addrListen.GetPort());
}
}
}
HRESULT CTCPServer::Initialize(const CStunServerConfig& config) HRESULT CTCPServer::Initialize(const CStunServerConfig& config)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
TransportAddressSet tsaListen; TransportAddressSet tsaListenAll;
TransportAddressSet tsaHandler; TransportAddressSet tsaHandler;
ChkIfA(_threads[0] != NULL, E_UNEXPECTED); // we can't already be initialized, right? ChkIfA(_threads[0] != NULL, E_UNEXPECTED); // we can't already be initialized, right?
...@@ -838,39 +862,45 @@ HRESULT CTCPServer::Initialize(const CStunServerConfig& config) ...@@ -838,39 +862,45 @@ HRESULT CTCPServer::Initialize(const CStunServerConfig& config)
// Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth)); // Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth));
// tsaHandler is sort of a hack for TCP. It's really just a glorified indication to the the // tsaHandler is sort of a hack for TCP. It's really just a glorified indication to the the
// CStunRequestHandler code to figure out if can offer a CHANGED-ADDRESS attribute. // CStunRequestHandler code to figure out if it can offer a CHANGED-ADDRESS attribute.
tsaHandler.set[RolePP].fValid = config.fHasPP; InitTSA(&tsaHandler, RolePP, config.fHasPP, config.addrPP, config.addrPrimaryAdvertised);
tsaHandler.set[RolePP].addr = config.addrPP; InitTSA(&tsaHandler, RolePA, config.fHasPA, config.addrPA, config.addrPrimaryAdvertised);
InitTSA(&tsaHandler, RoleAP, config.fHasAP, config.addrAP, config.addrAlternateAdvertised);
tsaHandler.set[RolePA].fValid = config.fHasPA; InitTSA(&tsaHandler, RoleAA, config.fHasAA, config.addrAA, config.addrAlternateAdvertised);
tsaHandler.set[RolePA].addr = config.addrPA;
InitTSA(&tsaListenAll, RolePP, config.fHasPP, config.addrPP, CSocketAddress());
tsaHandler.set[RoleAP].fValid = config.fHasAP; InitTSA(&tsaListenAll, RolePA, config.fHasPA, config.addrPA, CSocketAddress());
tsaHandler.set[RoleAP].addr = config.addrAP; InitTSA(&tsaListenAll, RoleAP, config.fHasAP, config.addrAP, CSocketAddress());
InitTSA(&tsaListenAll, RoleAA, config.fHasAA, config.addrAA, CSocketAddress());
tsaHandler.set[RoleAA].fValid = config.fHasAA;
tsaHandler.set[RoleAA].addr = config.addrAA;
if (config.fMultiThreadedMode == false) if (config.fMultiThreadedMode == false)
{ {
tsaListen = tsaHandler;
_threads[0] = new CTCPStunThread(); _threads[0] = new CTCPStunThread();
ChkA(_threads[0]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections)); ChkA(_threads[0]->Init(tsaListenAll, tsaHandler, _spAuth, config.nMaxConnections));
} }
else else
{ {
for (int threadindex = 0; threadindex < 4; threadindex++) for (int threadindex = 0; threadindex < 4; threadindex++)
{ {
memset(&tsaListen, '\0', sizeof(tsaListen));
if (tsaHandler.set[threadindex].fValid) if (tsaHandler.set[threadindex].fValid)
{ {
tsaListen.set[threadindex] = tsaHandler.set[threadindex]; TransportAddressSet tsaListen = tsaListenAll;
// Since we already initialized tsaListenAll above,
// make a copy and uninit each one that isn't going to be managed
// by the thread we are about to create
for (int temp = 0; temp < 4; temp++)
{
if (temp != threadindex)
{
tsaListen.set[temp].fValid = false;
tsaListen.set[temp].addr = CSocketAddress();
}
}
_threads[threadindex] = new CTCPStunThread(); _threads[threadindex] = new CTCPStunThread();
Chk(_threads[threadindex]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections)); Chk(_threads[threadindex]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections));
} }
......
...@@ -126,7 +126,9 @@ private: ...@@ -126,7 +126,9 @@ private:
CTCPStunThread* _threads[4]; CTCPStunThread* _threads[4];
CRefCountedPtr<IStunAuth> _spAuth; CRefCountedPtr<IStunAuth> _spAuth;
void InitTSA(TransportAddressSet* pTSA, SocketRole role, bool fValid, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise);
public: public:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment